You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by rh...@apache.org on 2014/11/28 14:49:39 UTC

[01/51] [abbrv] qpid-proton git commit: The commit breaks the back of the native JavaScript bindings and can serialise and deserialise arrays and maps etc. There's still some work to do with trackers because they are 64 bit integers and this causes some

Repository: qpid-proton
Updated Branches:
  refs/heads/master db437cf4a -> e8029597b


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/data-test.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-test.js b/proton-c/bindings/javascript/data-test.js
new file mode 100644
index 0000000..6904bc9
--- /dev/null
+++ b/proton-c/bindings/javascript/data-test.js
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * Unit tests for the Data Class.
+ * TODO this is just some random stuff at the moment - need to port the python codec test.
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("../../../bld/proton-c/bindings/javascript/proton.js");
+}
+
+
+try {
+
+    var messenger = new proton.Messenger();
+
+    console.log("name = " + messenger.getName());
+
+    console.log("timeout = " + messenger.getTimeout());
+
+    console.log("isBlocking = " + messenger.isBlocking());
+
+    messenger.setIncomingWindow(1234);
+    console.log("incoming window = " + messenger.getIncomingWindow());
+
+    messenger.setOutgoingWindow(5678);
+    console.log("outgoing window = " + messenger.getOutgoingWindow());
+
+
+    messenger.start();
+    console.log("isStopped = " + messenger.isStopped());
+
+
+    //messenger.subscribe("amqp://narnia");
+    var subscription = messenger.subscribe("amqp://~0.0.0.0");
+    console.log("subscription address = " + subscription.getAddress());
+
+
+    var message = new proton.Message();
+    message.setAddress("amqp://localhost:5672");
+    console.log("message address = " + message.getAddress());
+
+    message.setSubject("UK.WEATHER");
+    console.log("message subject = " + message.getSubject());
+
+
+    messenger.stop();
+    console.log("isStopped = " + messenger.isStopped());
+
+
+
+    message.free();
+
+    messenger.free();
+
+} catch(e) {
+    console.log("Caught Exception " + e);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/drain.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/drain.js b/proton-c/bindings/javascript/drain.js
new file mode 100644
index 0000000..e93ba2e
--- /dev/null
+++ b/proton-c/bindings/javascript/drain.js
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("../../../bld/proton-c/bindings/javascript/proton.js");
+}
+
+try {
+    var address = "amqp://~0.0.0.0";
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    function _process() {
+//        console.log("                          *** process ***");
+
+        // Process incoming messages
+
+        while (messenger.incoming()) {
+console.log("in while loop\n");
+
+            var tracker = messenger.get(message);
+console.log("tracker = " + tracker);
+
+            console.log("Address: " + message.getAddress());
+            console.log("Subject: " + message.getSubject());
+            console.log("Content: " + message.body);
+
+            messenger.accept(tracker);
+        }
+    };
+
+    //messenger.setIncomingWindow(1024);
+
+    messenger.setNetworkCallback(_process);
+    messenger.start();
+
+    messenger.subscribe(address);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+} catch(e) {
+    console.log("Caught Exception " + e);
+}
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/main.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/main.js b/proton-c/bindings/javascript/main.js
deleted file mode 100644
index b66da17..0000000
--- a/proton-c/bindings/javascript/main.js
+++ /dev/null
@@ -1,48 +0,0 @@
-
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    Proton = require("../../../bld/proton-c/bindings/javascript/messenger.js");
-}
-
-
-try {
-
-    var messenger = Proton.Messenger();
-
-    console.log("name = " + messenger.getName());
-
-    console.log("timeout = " + messenger.getTimeout());
-
-    console.log("isBlocking = " + messenger.isBlocking());
-
-    messenger.setIncomingWindow(1234);
-    console.log("incoming window = " + messenger.getIncomingWindow());
-
-    messenger.setOutgoingWindow(5678);
-    console.log("outgoing window = " + messenger.getOutgoingWindow());
-
-
-    messenger.start();
-    console.log("isStopped = " + messenger.isStopped());
-
-
-    //messenger.subscribe("amqp://narnia");
-    var subscription = messenger.subscribe("amqp://~0.0.0.0");
-    console.log("subscription address = " + subscription.getAddress());
-
-
-    var message = Proton.Message();
-
-
-    messenger.stop();
-    console.log("isStopped = " + messenger.isStopped());
-
-
-
-    message.free();
-
-    messenger.free();
-
-} catch(e) {
-    console.log("Caught Exception " + e);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/messenger.c
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/messenger.c b/proton-c/bindings/javascript/messenger.c
deleted file mode 100644
index bae4f81..0000000
--- a/proton-c/bindings/javascript/messenger.c
+++ /dev/null
@@ -1,54 +0,0 @@
-
-#include <stdio.h>
-#include <stdlib.h>
-
-
-
-void test(const char *name) {
-    if (name == NULL) {
-        printf("name is NULL\n");
-    } else {
-        printf("name = %s\n", name);
-    }
-}
-
-
-
-/*
-z_streamp inflateInitialise() {
-    z_streamp stream = malloc(sizeof(z_stream));
-    stream->zalloc = Z_NULL;
-    stream->zfree = Z_NULL;
-    int ret = inflateInit(stream);
-    if (ret != Z_OK) {
-        return Z_NULL;
-    } else {
-        return stream;
-    }
-}
-
-void inflateDestroy(z_streamp stream) {
-    inflateEnd(stream);
-    free(stream);
-}
-
-int zinflate(z_streamp stream,
-             unsigned char* dest, unsigned long* destLen,
-             unsigned char* source, unsigned long sourceLen) {
-    int err;
-    int total = stream->total_out;
-    stream->avail_in = sourceLen;
-    stream->next_in = source;
-
-    stream->avail_out = *destLen;
-    stream->next_out = dest;
-
-    err = inflate(stream, Z_SYNC_FLUSH);
-    *destLen = stream->total_out - total;
-
-    if (err != Z_OK) {
-        inflateEnd(stream);
-    }
-    return err;
-}
-*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/my-library.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/my-library.js b/proton-c/bindings/javascript/my-library.js
index cf1da62..b35ccd1 100644
--- a/proton-c/bindings/javascript/my-library.js
+++ b/proton-c/bindings/javascript/my-library.js
@@ -276,16 +276,7 @@ console.log('e: ' + e);
           if (Module['networkCallback']) {
 console.log("handleOpen triggering networkCallback");
 
-            try {
-              Runtime.dynCall('v', Module['networkCallback']);
-            } catch (e) {
-              if (e instanceof ExitStatus) {
-                return;
-              } else {
-                if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
-                throw e;
-              }
-            }
+            Module['networkCallback']();
           }
 
 
@@ -318,21 +309,12 @@ console.log("handleOpen triggering networkCallback");
 
           sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
 
-// TODO trigger new emscripten_set_network_callback here.
+
 
           if (Module['networkCallback']) {
 console.log("handleMessage triggering networkCallback");
 
-            try {
-              Runtime.dynCall('v', Module['networkCallback']);
-            } catch (e) {
-              if (e instanceof ExitStatus) {
-                return;
-              } else {
-                if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
-                throw e;
-              }
-            }
+            Module['networkCallback']();
           }
 
 
@@ -525,21 +507,12 @@ console.log('close');
 
 
 
-// TODO trigger new emscripten_set_network_callback here.
+
 
           if (Module['networkCallback']) {
 console.log("On connection triggering networkCallback");
 
-            try {
-              Runtime.dynCall('v', Module['networkCallback']);
-            } catch (e) {
-              if (e instanceof ExitStatus) {
-                return;
-              } else {
-                if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
-                throw e;
-              }
-            }
+            Module['networkCallback']();
           }
 
 
@@ -711,8 +684,22 @@ console.log('getname');
   },
 
   emscripten_set_network_callback: function(func) {
+
+    function _func() {
+      try {
+        Runtime.dynCall('v', func);
+      } catch (e) {
+        if (e instanceof ExitStatus) {
+          return;
+        } else {
+          if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+          throw e;
+        }
+      }
+    };
+
     Module['noExitRuntime'] = true;
-    Module['networkCallback'] = func;
+    Module['networkCallback'] = _func;
   }
 
 });

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/post-wrap.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/post-wrap.js b/proton-c/bindings/javascript/post-wrap.js
deleted file mode 100644
index 9faf241..0000000
--- a/proton-c/bindings/javascript/post-wrap.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-})(); // End of self calling lambda used to wrap library.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/pre-wrap.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/pre-wrap.js b/proton-c/bindings/javascript/pre-wrap.js
deleted file mode 100644
index 38a4eff..0000000
--- a/proton-c/bindings/javascript/pre-wrap.js
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/**
- * This file provides a JavaScript wrapper around Proton Messenger.
- * It will be used to wrap the emscripten compiled proton-c code and minified by
- * the Closure compiler, so all comments will be stripped from the actual library.
- *
- * This JavaScript wrapper provides a slightly more object oriented interface which
- * abstracts some of the  emscripten based implementation details from client code
- * via the use of a higher level Buffer class.
- */
-(function() { // Start of self-calling lambda used to wrap library and avoid polluting global namespace.
-
-var Module = {
-    // Prevents the runtime exiting as otherwise things like printf won't work from methods called by JavaScript.
-    "noExitRuntime" : true
-};
-
-/**
- * This class is a buffer for use with the emscripten based port of zlib. It allows creation management of a 
- * buffer in the virtual heap space of the zlib library hiding the implementation detail from client code.
- */
-/*
-var Buffer = function(size) {
-    var _public = {};
-    var asize = 0; // The allocated size of the input buffer.
-    var ptr   = 0; // Handle to the input buffer.
-
-    // Private methods.
-    function freeBuffer() {
-        if (ptr !== 0) {
-            _free(ptr);
-        }
-    };
-
-    // Public methods
-    _public.destroy = function() {
-        freeBuffer();
-    };
-
-    _public.setSize = function(size) {
-        if (size > asize) {
-            freeBuffer();
-            ptr = _malloc(size); // Get output buffer from emscripten.
-            asize = size;
-        }
-        _public.size = size;
-    };
-
-    _public.getRaw = function() {
-        return ptr;
-    };
-
-    _public.getBuffer = function() {
-        // Get a Uint8Array view on the input buffer.
-        return new Uint8Array(HEAPU8.buffer, ptr, _public.size);
-    };
-
-    if (size) {
-        _public.setSize(size);
-    }
-
-    return _public;
-};
-*/
-
-
-// N.B. Using associative array form for declaring exported properties to prevent Closure compiler minifying them.
-
-/**
- * This class is a wrapper for Messenger's subscriptions.
- */
-var Subscription = function(subscription) {
-    var _public = {};
-    var _subscription = subscription;
-
-    // **************************************** Public methods ******************************************
-    /**
-     * TODO Not sure exactly what this does.
-     * @return the Subscription's Context.
-     */
-    _public["getContext"] = function() {
-        return _pn_subscription_get_context(_subscription);
-    };
-
-    /**
-     * TODO Not sure exactly what this does.
-     * @param context the Subscription's new Context.
-     */
-    _public["setContext"] = function(context) {
-        _pn_subscription_set_context(_subscription, context);
-    };
-
-    /**
-     * @return the Subscription's Address.
-     */
-    _public["getAddress"] = function() {
-        return Pointer_stringify(_pn_subscription_address(_subscription));
-    };
-
-    return _public;
-};
-
-Module["Messenger"] = function(name) {
-    var _public = {};
-
-    var PN_EOS = -1;
-    var PN_ERR = -2;
-    var PN_OVERFLOW = -3;
-    var PN_UNDERFLOW = -4;
-    var PN_STATE_ERR = -5;
-    var PN_ARG_ERR = -6;
-    var PN_TIMEOUT = -7;
-    var PN_INTR = -8;
-    var PN_INPROGRESS = -9;
-
-    var PN_CUMULATIVE = 0x1;
-
-    // ALLOC_STACK will increase the stack and place the item there. When the stack is next restored (like when
-    // the current function call exits), that memory will be automatically freed. The _pn_messenger constructor
-    // copies the char* passed to it so there are no worries with it being freed when this constructor returns.
-    var _messenger = _pn_messenger(name ? allocate(intArrayFromString(name), 'i8', ALLOC_STACK) : 0);
-
-    // Initiate Messenger non-blocking mode. For JavaScript we make this the default behaviour and don't export
-    // this method because JavaScript is fundamentally an asynchronous non-blocking execution environment.
-    _pn_messenger_set_blocking(_messenger, false);
-
-/* TODO just test crap - delete me!!
-    _test(0);
-    _test(allocate(intArrayFromString("Monkey"), 'i8', ALLOC_STACK));
-*/
-
-
-    // *************************************** Private methods ******************************************
-
-    /**
-     * This helper method checks the supplied error code, converts it into an
-     * exception and throws the exception. This method will try to use the message
-     * populated in pn_messenger_error(), if present, but if not it will fall
-     * back to using the basic error code rendering from pn_code().
-     * @param code the error code to check.
-     */
-    function _check(code) {
-        if (code < 0) {
-            if (code === PN_INPROGRESS) {
-                return code;
-            }
-
-            var errno = _public.getErrno();
-            var message = errno ? _public.getError() : Pointer_stringify(_pn_code(code));
-
-            throw { // TODO Improve name and level.
-                name:     "System Error", 
-                level:    "Show Stopper", 
-                message:  message, 
-                toString: function() {return this.name + ": " + this.message} 
-            }
-        } else {
-            return code;
-        }
-    };
-
-    // **************************************** Public methods ******************************************
-
-    /**
-     * N.B. The following methods are not exported by the JavaScript Messenger binding for reasons described below.
-     *
-     * For these methods it is expected that security would be implemented via a secure WebSocket.
-     * TODO what happens if we decide to implement TCP sockets via Node.js net library.
-     * If we do that we may want to compile OpenSSL using emscripten and include these methods.
-     * pn_messenger_set_certificate()
-     * pn_messenger_get_certificate()
-     * pn_messenger_set_private_key()
-     * pn_messenger_get_private_key()
-     * pn_messenger_set_password()
-     * pn_messenger_get_password()
-     * pn_messenger_set_trusted_certificates()
-     * pn_messenger_get_trusted_certificates()
-     *
-     * For these methods the implementation is fairly meaningless because JavaScript
-     * is a fundamentally asynchronous non-blocking environment.
-     * pn_messenger_set_timeout()
-     * pn_messenger_set_blocking()
-     * pn_messenger_interrupt()
-     * pn_messenger_send() // Not sure if this is useful in JavaScript.
-     */
-
-    /**
-     * Retrieves the name of a Messenger.
-     * @return the name of the messenger.
-     */
-    _public["getName"] = function() {
-        return Pointer_stringify(_pn_messenger_name(_messenger));
-    };
-
-    /**
-     * Retrieves the timeout for a Messenger.
-     * @return zero because JavaScript is fundamentally non-blocking.
-     */
-    _public["getTimeout"] = function() {
-        return 0;
-    };
-
-    /**
-     * Accessor for messenger blocking mode.
-     * @return false because JavaScript is fundamentally non-blocking.
-     */
-    _public["isBlocking"] = function() {
-        return true;
-    };
-
-    /**
-     * Free the Messenger. This will close all connections that are managed
-     * by the Messenger. Call the stop method before destroying the Messenger.
-     * N.B. This method has to be called explicitly in JavaScript as we can't
-     * intercept finalisers so we need to remember to free before removing refs.
-     */
-    _public["free"] = function() {
-        _pn_messenger_free(_messenger);
-    };
-
-    /**
-     * @return the most recent error message code.
-     */
-    _public["getErrno"] = function() {
-        return _pn_messenger_errno(_messenger);
-    };
-
-    /**
-     * @return the most recent error message as a String.
-     */
-    _public["getError"] = function() {
-        return Pointer_stringify(_pn_error_text(_pn_messenger_error(_messenger)));
-    };
-
-    /**
-     * Returns the size of the outgoing window that was set with
-     * pn_messenger_set_outgoing_window. The default is 0.
-     * @return the outgoing window.
-     */
-    _public["getOutgoingWindow"] = function() {
-        return _pn_messenger_get_outgoing_window(_messenger);
-    };
-
-    /**
-     * Sets the outgoing tracking window for the Messenger. The Messenger will
-     * track the remote status of this many outgoing deliveries after calling
-     * send. Defaults to zero.
-     *
-     * A Message enters this window when you call the put() method with the Message.
-     * If your outgoing window size is n, and you call put n+1 times, status
-     * information will no longer be available for the first Message.
-     * @param window the size of the tracking window in messages.
-     */
-    _public["setOutgoingWindow"] = function(window) {
-        _check(_pn_messenger_set_outgoing_window(_messenger, window));
-    };
-
-    /**
-     * Returns the size of the incoming window that was set with
-     * pn_messenger_set_incoming_window. The default is 0.
-     * @return the incoming window.
-     */
-    _public["getIncomingWindow"] = function() {
-        return _pn_messenger_get_incoming_window(_messenger);
-    };
-
-    /**
-     * Sets the incoming tracking window for the Messenger. The Messenger will
-     * track the remote status of this many incoming deliveries after calling
-     * send. Defaults to zero.
-     *
-     * Messages enter this window only when you take them into your application
-     * using get. If your incoming window size is n, and you get n+1 messages
-     * without explicitly accepting or rejecting the oldest message, then the
-     * Message that passes beyond the edge of the incoming window will be assigned
-     * the default disposition of its link.
-     * @param window the size of the tracking window in messages.
-     */
-    _public["setIncomingWindow"] = function(window) {
-        _check(_pn_messenger_set_incoming_window(_messenger, window));
-    };
-
-    /**
-     * Currently a no-op placeholder. For future compatibility, do not send or
-     * recv messages before starting the Messenger.
-     */
-    _public["start"] = function() {
-        _check(_pn_messenger_start(_messenger));
-    };
-
-    /**
-     * Transitions the Messenger to an inactive state. An inactive Messenger
-     * will not send or receive messages from its internal queues. A Messenger
-     * should be stopped before being discarded to ensure a clean shutdown
-     * handshake occurs on any internally managed connections.
-     *
-     * The Messenger may require some time to stop if it is busy, and in that
-     * case will return PN_INPROGRESS. In that case, call isStopped to see if
-     * it has fully stopped.
-     */
-    _public["stop"] = function() {
-        return _check(_pn_messenger_stop(_messenger));
-    };
-
-    /**
-     * @return Returns true iff a Messenger is in the stopped state.
-     */
-    _public["isStopped"] = function() {
-        return (_pn_messenger_stopped(_messenger) > 0);
-    };
-
-    /**
-     * Subscribes the Messenger to messages originating from the
-     * specified source. The source is an address as specified in the
-     * Messenger introduction with the following addition. If the
-     * domain portion of the address begins with the '~' character, the
-     * Messenger will interpret the domain as host/port, bind to it,
-     * and listen for incoming messages. For example "~0.0.0.0",
-     * "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
-     * local interface and listen for incoming messages with the last
-     * variant only permitting incoming SSL connections.
-     * @param source the source address we're subscribing to.
-     * @return a subscription.
-     */
-    _public["subscribe"] = function(source) {
-console.log("subscribe: haven't yet proved this works yet");
-        if (!source) {
-            _check(-6); // PN_ARG_ERR
-        }
-        var subscription = _pn_messenger_subscribe(_messenger,
-                                                   allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
-        if (!subscription) {
-            _check(-2); // PN_ERR
-        }
-        return Subscription(subscription);
-    };
-
-    /**
-     * Places the content contained in the message onto the outgoing queue
-     * of the Messenger. This method will never block, however it will send any
-     * unblocked Messages in the outgoing queue immediately and leave any blocked
-     * Messages remaining in the outgoing queue. The send call may be used to
-     * block until the outgoing queue is empty. The outgoing property may be
-     * used to check the depth of the outgoing queue.
-     *
-     * When the content in a given Message object is copied to the outgoing
-     * message queue, you may then modify or discard the Message object
-     * without having any impact on the content in the outgoing queue.
-     *
-     * This method returns an outgoing tracker for the Message.  The tracker
-     * can be used to determine the delivery status of the Message.
-     * @param message a Message to send.
-     * @return a tracker.
-     */
-    _public["put"] = function(message) {
-console.log("put: not fully implemented yet");
-        // TODO message._pre_encode()
-        _check(_pn_messenger_put(_messenger, message));
-        return _pn_messenger_outgoing_tracker(_messenger);
-    };
-
-    /**
-     * Gets the last known remote state of the delivery associated with the given tracker.
-     * @param tracker the tracker whose status is to be retrieved.
-     * @return one of None, PENDING, REJECTED, or ACCEPTED.
-     */
-    _public["status"] = function(tracker) {
-console.log("status: not fully implemented yet");
-        var disp = _pn_messenger_status(_messenger, tracker);
-        return disp; // TODO return a more friendly status.
-    };
-
-    /**
-     * Checks if the delivery associated with the given tracker is still waiting to be sent.
-     * @param tracker the tracker identifying the delivery.
-     * @return true if delivery is still buffered.
-     */
-    _public["isBuffered"] = function(tracker) {
-        return (_pn_messenger_buffered(_messenger, tracker) > 0);
-    };
-
-    /**
-     * Frees a Messenger from tracking the status associated with a given tracker.
-     * If you don't supply a tracker, all outgoing messages up to the most recent
-     * will be settled.
-     * @param tracker the tracker identifying the delivery.
-     */
-    _public["settle"] = function(tracker) {
-console.log("settle: not fully tested yet");
-        var flags = 0;
-        if (!tracker) {
-            tracker = _pn_messenger_outgoing_tracker(_messenger);
-            flags = PN_CUMULATIVE;
-        }
-
-        _check(_pn_messenger_settle(_messenger, tracker, flags));
-    };
-
-    /**
-     * Sends or receives any outstanding messages queued for a Messenger.
-     * For JavaScript the only timeout that makes sense is 0 == do not block.
-     * This method may also do I/O work other than sending and receiving messages.
-     * For example, closing connections after messenger.stop() has been called.
-     * @return 0 if no work to do, < 0 if error, or 1 if work was done.
-     */
-    _public["work"] = function() {
-        //return _pn_messenger_work(_messenger, timeout);
-        return _pn_messenger_work(_messenger, 0);
-    };
-
-    /**
-     * Receives up to limit messages into the incoming queue.  If no value for limit
-     * is supplied, this call will receive as many messages as it can buffer internally.
-     * @param limit the maximum number of messages to receive or -1 to to receive
-     *        as many messages as it can buffer internally.
-     */
-    _public["recv"] = function(limit) {
-        _check(_pn_messenger_recv(_messenger, (limit ? limit : -1)));
-    };
-
-    /**
-     * Returns the capacity of the incoming message queue of messenger. Note this
-     * count does not include those messages already available on the incoming queue.
-     * @return the message queue capacity.
-     */
-    _public["receiving"] = function() {
-        return _pn_messenger_receiving(_messenger);
-    };
-
-    /**
-     * Moves the message from the head of the incoming message queue into the
-     * supplied message object. Any content in the message will be overwritten.
-     *
-     * A tracker for the incoming Message is returned. The tracker can later be
-     * used to communicate your acceptance or rejection of the Message.
-     *
-     * @param message the destination message object. If no Message object is
-     *        passed, the Message popped from the head of the queue is discarded.
-     * @return a tracker for the incoming Message.
-     */
-    _public["get"] = function(message) {
-console.log("get: not fully implemented yet");
-/*
-    if message is None:
-      impl = None
-    else:
-      impl = message._msg
-*/
-
-        _check(_pn_messenger_get(_messenger, message));
-/*
-    if message is not None:
-      message._post_decode()
-*/
-        // TODO message._post_decode()
-
-        return _pn_messenger_incoming_tracker(_messenger);
-    };
-
-    /**
-     * Returns the Subscription of the Message returned by the most recent call
-     * to get, or null if pn_messenger_get has not yet been called.
-     * @return a Subscription or null if get has never been called for this Messenger.
-     */
-    _public["incomingSubscription"] = function() {
-console.log("incomingSubscription: haven't yet proved this works yet");
-
-        var subscription = _pn_messenger_incoming_subscription(_messenger);
-        if (subscription) {
-            return Subscription(subscription);
-        } else {
-            return null;
-        }
-    };
-
-    /**
-     * Signal the sender that you have acted on the Message pointed to by the tracker.
-     * If no tracker is supplied, then all messages that have been returned by the
-     * get method are accepted, except those that have already been auto-settled
-     * by passing beyond your incoming window size.
-     * @param tracker the tracker identifying the delivery.
-     */
-    _public["accept"] = function(tracker) {
-console.log("accept: not fully tested yet");
-        var flags = 0;
-        if (!tracker) {
-            tracker = _pn_messenger_incoming_tracker(_messenger);
-            flags = PN_CUMULATIVE;
-        }
-
-        _check(_pn_messenger_accept(_messenger, tracker, flags));
-    };
-
-    /**
-     * Rejects the Message indicated by the tracker.  If no tracker is supplied,
-     * all messages that have been returned by the get method are rejected, except
-     * those already auto-settled by passing beyond your outgoing window size.
-     * @param tracker the tracker identifying the delivery.
-     */
-    _public["reject"] = function(tracker) {
-console.log("reject: not fully tested yet");
-        var flags = 0;
-        if (!tracker) {
-            tracker = _pn_messenger_incoming_tracker(_messenger);
-            flags = PN_CUMULATIVE;
-        }
-
-        _check(_pn_messenger_reject(_messenger, tracker, flags));
-    };
-
-    /**
-     * Returns the number of messages in the outgoing message queue of a messenger.
-     * @return the outgoing queue depth.
-     */
-    _public["outgoing"] = function() {
-        return _pn_messenger_outgoing(_messenger);
-    };
-
-    /**
-     * Returns the number of messages in the incoming message queue of a messenger.
-     * @return the incoming queue depth.
-     */
-    _public["incoming"] = function() {
-        return _pn_messenger_incoming(_messenger);
-    };
-
-
-
-
-
-
-    /**
-     * 
-     * @param pattern a glob pattern to select messages.
-     * @param address an address indicating outgoing address rewrite.
-     */
-    _public["route"] = function(pattern, address) {
-console.log("route: not fully tested yet");
-
-        _check(_pn_messenger_route(_messenger,
-                                   allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
-                                   allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
-    };
-
-    /**
-     * Similar to route(), except that the destination of the Message is determined
-     * before the message address is rewritten.
-     *
-     * The outgoing address is only rewritten after routing has been finalized. If
-     * a message has an outgoing address of "amqp://0.0.0.0:5678", and a rewriting
-     * rule that changes its outgoing address to "foo", it will still arrive at the
-     * peer that is listening on "amqp://0.0.0.0:5678", but when it arrives there,
-     * the receiver will see its outgoing address as "foo".
-     *
-     * The default rewrite rule removes username and password from addresses
-     * before they are transmitted.
-     * @param pattern a glob pattern to select messages.
-     * @param address an address indicating outgoing address rewrite.
-     */
-    _public["rewrite"] = function(pattern, address) {
-console.log("rewrite: not fully tested yet");
-
-        _check(_pn_messenger_rewrite(_messenger,
-                                     allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
-                                     allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
-    };
-
-
-
-    return _public;
-};
-
-
-
-
-Module["Message"] = function(name) {
-    var _public = {};
-
-    var _message = _pn_message();
-
-
-    // *************************************** Private methods ******************************************
-
-    /**
-     * 
-     */
-/*
-    function _check(code) {
-
-    };*/
-
-    // **************************************** Public methods ******************************************
-
-    /**
-     * Export the underlying message implementation reference, which is needed
-     * by Messenger.put() and Messenger.get(). We use the dot notation rather
-     * than associative array form so it is visible to Messenger, but the Closure
-     * compiler will minify it effectively making it a "protected" property.
-     */
-    _public.impl = _message;
-
-    /**
-     * Retrieves the name of a Messenger.
-     * @return the name of the messenger.
-     */
-    /*_public["getName"] = function() {
-        //return Pointer_stringify(_pn_messenger_name(_messenger));
-    };*/
-
-
-
-    /**
-     * Free the Message.
-     * N.B. This method has to be called explicitly in JavaScript as we can't
-     * intercept finalisers so we need to remember to free before removing refs.
-     */
-    _public["free"] = function() {
-        _pn_message_free(_message);
-    };
-
-
-    return _public;
-};
-
-
-
-
-
-
-/*
-Module["Inflate"] = function(size) {
-    var _public = {};
-    var stream = _inflateInitialise();
-    var inputBuffer  = Buffer(size);
-    var outputBuffer = Buffer(size);
-
-    // Public methods
-    _public["destroy"] = function() {
-        _inflateDestroy(stream);
-        inputBuffer.destroy();
-        outputBuffer.destroy();
-    };
-
-    _public["reset"] = function() {
-        _inflateReset(stream);
-    };
-
-    _public["inflate"] = function(ptr) {
-        ptr = ptr ? ptr : outputBuffer.getRaw();
-        var inflatedSize; // Pass by reference variable - need to use Module.setValue to initialise it.
-        setValue(inflatedSize, outputBuffer.size, "i32");
-        var err = _zinflate(stream, ptr, inflatedSize, inputBuffer.getRaw(), inputBuffer.size);
-        inflatedSize = getValue(inflatedSize, "i32"); // Dereference the real inflatedSize value;
-        outputBuffer.setSize(inflatedSize);
-        return ((err < 0) ? err : inflatedSize); // Return the inflated size, or error code if inflation fails.
-    };
-
-    // Export methods from the input and output buffers for use by client code.
-    _public["setInputBufferSize"] = inputBuffer.setSize;
-    _public["getRawInputBuffer"] = inputBuffer.getRaw;
-    _public["getInputBuffer"] = inputBuffer.getBuffer;
-
-    _public["setOutputBufferSize"] = outputBuffer.setSize;
-    _public["getRawOutBuffer"] = outputBuffer.getRaw;
-    _public["getOutputBuffer"] = outputBuffer.getBuffer;
-
-    return _public;
-};
-*/
-
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/spout.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/spout.js b/proton-c/bindings/javascript/spout.js
new file mode 100644
index 0000000..8bb8542
--- /dev/null
+++ b/proton-c/bindings/javascript/spout.js
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("../../../bld/proton-c/bindings/javascript/proton.js");
+}
+
+try {
+    var address = "amqp://0.0.0.0";
+    var subject = "UK.WEATHER";
+    var msgtext = "Hello World!";
+    var tracker = null;
+    var running = true;
+
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    function _process() {
+//        console.log("                          *** process ***");
+
+        // Process outgoing messages
+        var status = messenger.status(tracker);
+        if (status != proton.Status.PENDING) {
+console.log("status = " + status);
+
+            //messenger.settle(tracker);
+            //tracked--;
+
+            if (running) {
+console.log("stopping");
+                messenger.stop();
+                running = false;
+            } 
+        }
+
+        if (messenger.isStopped()) {
+console.log("exiting");
+            message.free();
+            messenger.free();
+            //exit(0);
+        }
+    };
+
+
+    messenger.setOutgoingWindow(1024);
+
+    messenger.setNetworkCallback(_process);
+    messenger.start();
+
+    message.setAddress(address);
+    message.setSubject(subject);
+    //message.body = msgtext;
+    //message.body = new proton.Data.UUID();
+    //message.body = new proton.Data.Symbol("My Symbol");
+    //message.body = true;
+    //message.body = "   \"127.0\"  ";
+
+    //message.body = 2147483647; // int
+    //message.body = -2147483649; // long
+    //message.body = 12147483649; // long
+
+    //message.body = 2147483647.000001; // double
+
+    //message.body = ['Rod', 'Jane', 'Freddy'];
+    message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
+
+
+    tracker = messenger.put(message);
+
+} catch(e) {
+    console.log("Caught Exception " + e);
+}


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


[02/51] [abbrv] qpid-proton git commit: The commit breaks the back of the native JavaScript bindings and can serialise and deserialise arrays and maps etc. There's still some work to do with trackers because they are 64 bit integers and this causes some

Posted by rh...@apache.org.
The commit breaks the back of the native JavaScript bindings and can serialise and deserialise arrays and maps etc. There's still some work to do with trackers because they are 64 bit integers and this causes some issues interacting with native JavaScript and the Binary type is still TBD

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1583388 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/162d5b20
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/162d5b20
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/162d5b20

Branch: refs/heads/master
Commit: 162d5b208c21889d5edadf93c13903ed841b669c
Parents: d55e2e5
Author: fadams <fa...@unknown>
Authored: Mon Mar 31 18:15:26 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Mon Mar 31 18:15:26 2014 +0000

----------------------------------------------------------------------
 examples/messenger/c/recv-async.c             |    4 +-
 proton-c/bindings/javascript/CMakeLists.txt   |   45 +-
 proton-c/bindings/javascript/binding-close.js |   21 +
 proton-c/bindings/javascript/binding.c        |   80 +
 proton-c/bindings/javascript/binding.js       | 2154 ++++++++++++++++++++
 proton-c/bindings/javascript/data-test.js     |   77 +
 proton-c/bindings/javascript/drain.js         |   61 +
 proton-c/bindings/javascript/main.js          |   48 -
 proton-c/bindings/javascript/messenger.c      |   54 -
 proton-c/bindings/javascript/my-library.js    |   53 +-
 proton-c/bindings/javascript/post-wrap.js     |   21 -
 proton-c/bindings/javascript/pre-wrap.js      |  690 -------
 proton-c/bindings/javascript/spout.js         |   90 +
 13 files changed, 2522 insertions(+), 876 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/examples/messenger/c/recv-async.c
----------------------------------------------------------------------
diff --git a/examples/messenger/c/recv-async.c b/examples/messenger/c/recv-async.c
index c83375e..cb50635 100644
--- a/examples/messenger/c/recv-async.c
+++ b/examples/messenger/c/recv-async.c
@@ -71,7 +71,7 @@ printf("in while loop\n");
       pn_messenger_get(messenger, message);
       check(messenger);
       pn_tracker_t tracker = pn_messenger_incoming_tracker(messenger);
-
+printf("tracker = %ld:%ld\n", (long)(tracker >> 32), (long)tracker);
 
       char buffer[1024];
       size_t buffsize = sizeof(buffer);
@@ -86,7 +86,7 @@ printf("in while loop\n");
 
 
       int err = pn_messenger_accept(messenger, tracker, 0);
-printf("err = %d\n", err);
+printf("err = %d\n\n", err);
     }
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index 2179e7b..bfda16f 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -32,27 +32,15 @@ set(CMAKE_CROSSCOMPILING TRUE)
 # Specify the compiler to use for cross-compilation.
 set(CMAKE_C_COMPILER "${EMCC}")
 
-# Specify the archiver to use for cross-compilation.
-#find_program(EMAR emar)
-#set(CMAKE_AR "${EMAR}")
-
-# Specify the ranlib to use for cross-compilation.
-#find_program(EMRANLIB emranlib)
-#set(CMAKE_RANLIB "${EMRANLIB}")
-
 # Don't do compiler autodetection, since we are cross-compiling.
 include(CMakeForceCompiler)
 CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang)
 
-# Specify the program to use when building static libraries. Force Emscripten-related command line options to clang.
-#set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_AR} rc <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}")
 
 # From this point we should be using emscripten compilation tools rather than default ones
 message(STATUS "emscripten compilation environment:")
 message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
-#message(STATUS "CMAKE_AR: ${CMAKE_AR}")
-#message(STATUS "CMAKE_RANLIB: ${CMAKE_RANLIB}")
-#message(STATUS "CMAKE_C_ARCHIVE_CREATE: ${CMAKE_C_ARCHIVE_CREATE}")
+
 
 # Set this to the proton-c directory, we're cross-compiling code from there.
 set(PN_PATH ${CMAKE_SOURCE_DIR}/proton-c)
@@ -74,7 +62,7 @@ set(pn_driver_impl ${PN_PATH}/src/posix/driver.c)
 
 # Generate encodings.h and protocol.h
 # It may be possible to use the ones generated for the main proton-c build but qpid-proton-core has
-# a dependency on the generated files so I'm not sure if it'll work without a command that can
+# a dependency on the generated files, so I'm not sure if it'll work without a command that can
 # be run as a dependency. Probably best do it this way when cross-compiling - though more copy'n'paste
 add_custom_command(
   OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
@@ -163,15 +151,17 @@ set_source_files_properties(
   COMPILE_DEFINITIONS "${PLATFORM_DEFINITIONS}"
   )
 
+# Compile Proton into LLVM bitcode which will be used later in the linking stage
+# of add_executable for compilation into Javascript.
 add_library(
-  qpid-proton-js SHARED
+  qpid-proton-bitcode SHARED
 
   ${qpid-proton-core}
   ${qpid-proton-platform}
   )
 
 set_target_properties(
-  qpid-proton-js
+  qpid-proton-bitcode
   PROPERTIES
   VERSION   "${PN_LIB_SOMAJOR}.${PN_LIB_SOMINOR}"
   SOVERSION "${PN_LIB_SOMAJOR}"
@@ -181,19 +171,17 @@ set_target_properties(
 
 
 add_executable(send-async.js ${PN_PATH}/../examples/messenger/c/send-async.c)
-target_link_libraries(send-async.js qpid-proton-js)
+target_link_libraries(send-async.js qpid-proton-bitcode)
 
 #add_executable(send-async.html ${PN_PATH}/../examples/messenger/c/send-async.c)
-#target_link_libraries(send-async.html qpid-proton-js)
+#target_link_libraries(send-async.html qpid-proton-bitcode)
 
 add_executable(recv-async.js ${PN_PATH}/../examples/messenger/c/recv-async.c)
-target_link_libraries(recv-async.js qpid-proton-js)
+target_link_libraries(recv-async.js qpid-proton-bitcode)
 
 
 
 # TODO get the patches in my-library.js pushed properly into emscripten ASAP
-# Note there is currently an issue with varargs that makes it necessary
-# to compile with 'EMCC_LLVM_TARGET=i386-pc-linux-gnu make'
 #
 set_target_properties(
   #send-async.js recv-async.js send-async.html
@@ -216,19 +204,20 @@ set_target_properties(
 
 
 
-# Compile with 'EMCC_LLVM_TARGET=i386-pc-linux-gnu make'
-add_executable(messenger.js messenger.c)
-target_link_libraries(messenger.js qpid-proton-js)
+# Build the main JavaScript library called proton.js
+add_executable(proton.js binding.c)
+target_link_libraries(proton.js qpid-proton-bitcode)
 
 set_target_properties(
-  messenger.js
+  proton.js
   PROPERTIES
   COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
 
-  # This build is optimised but not minified
-  LINK_FLAGS "-s \"EXPORT_NAME='Proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/pre-wrap.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/post-wrap.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_error_text', '_pn_code', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '
 _pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming', '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_message', '_pn_message_free']\""
-  )
+  # This build is optimised and minified
+  #LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --pre-js
 
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messen
 ger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bo
 ol', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol
 ', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  )
 
 
 # Some hacks so check what's getting built TODO to get rid of eventually 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/binding-close.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding-close.js b/proton-c/bindings/javascript/binding-close.js
new file mode 100644
index 0000000..9faf241
--- /dev/null
+++ b/proton-c/bindings/javascript/binding-close.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+})(); // End of self calling lambda used to wrap library.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/binding.c
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.c b/proton-c/bindings/javascript/binding.c
new file mode 100644
index 0000000..e91c3c8
--- /dev/null
+++ b/proton-c/bindings/javascript/binding.c
@@ -0,0 +1,80 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+#include "proton/message.h"
+
+typedef struct {
+  size_t next;
+  size_t prev;
+  size_t down;
+  size_t parent;
+  size_t children;
+  pn_atom_t atom;
+  // for arrays
+  bool described;
+  pn_type_t type;
+  bool data;
+  size_t data_offset;
+  size_t data_size;
+  char *start;
+  bool small;
+} pni_node_t;
+
+pni_node_t* pn_data_add(pn_data_t *data);
+
+int test(pn_data_t *data, int64_t l)
+{
+printf("hello\n");
+
+  pni_node_t *node = pn_data_add(data);
+  node->atom.type = PN_LONG;
+  node->atom.u.as_long = l;
+
+  return 0;
+}
+*/
+
+
+
+
+
+/*
+z_streamp inflateInitialise() {
+    z_streamp stream = malloc(sizeof(z_stream));
+    stream->zalloc = Z_NULL;
+    stream->zfree = Z_NULL;
+    int ret = inflateInit(stream);
+    if (ret != Z_OK) {
+        return Z_NULL;
+    } else {
+        return stream;
+    }
+}
+
+void inflateDestroy(z_streamp stream) {
+    inflateEnd(stream);
+    free(stream);
+}
+
+int zinflate(z_streamp stream,
+             unsigned char* dest, unsigned long* destLen,
+             unsigned char* source, unsigned long sourceLen) {
+    int err;
+    int total = stream->total_out;
+    stream->avail_in = sourceLen;
+    stream->next_in = source;
+
+    stream->avail_out = *destLen;
+    stream->next_out = dest;
+
+    err = inflate(stream, Z_SYNC_FLUSH);
+    *destLen = stream->total_out - total;
+
+    if (err != Z_OK) {
+        inflateEnd(stream);
+    }
+    return err;
+}
+*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/162d5b20/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
new file mode 100644
index 0000000..ad6340f
--- /dev/null
+++ b/proton-c/bindings/javascript/binding.js
@@ -0,0 +1,2154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * This file provides a JavaScript wrapper around the Proton Messenger API.
+ * It will be used to wrap the emscripten compiled proton-c code and minified by
+ * the Closure compiler, so all comments will be stripped from the actual library.
+ *
+ * This JavaScript wrapper provides a slightly more object oriented interface which
+ * abstracts the low-level emscripten based implementation details from client code.
+ */
+(function() { // Start of self-calling lambda used to avoid polluting global namespace.
+
+/**
+ * The Module Object is exported by emscripten for all execution platforms, we
+ * use it as a namespace to allow us to selectively export only what we wish to
+ * be publicly visible from this package/module. We will use the associative
+ * array form for declaring exported properties to prevent the Closure compiler
+ * from minifying e.g. Module['Messenger'] = ... to export the Messenger Object.
+ * Exported Objects can be used in client code using the appropriate namespace:
+ * proton = require("proton.js");
+ * var messenger = new proton.Messenger();
+ * var message = new proton.Message();
+ */
+var Module = {
+    // Prevent emscripten runtime exiting, we will be enabling network callbacks.
+    'noExitRuntime' : true
+};
+
+
+
+/**
+ * This class is a buffer for use with the emscripten based port of zlib. It allows creation management of a 
+ * buffer in the virtual heap space of the zlib library hiding the implementation detail from client code.
+ */
+/*
+var Buffer = function(size) {
+    var _public = {};
+    var asize = 0; // The allocated size of the input buffer.
+    var ptr   = 0; // Handle to the input buffer.
+
+    // Private methods.
+    function freeBuffer() {
+        if (ptr !== 0) {
+            _free(ptr);
+        }
+    };
+
+    // Public methods
+    _public.destroy = function() {
+        freeBuffer();
+    };
+
+    _public.setSize = function(size) {
+        if (size > asize) {
+            freeBuffer();
+            ptr = _malloc(size); // Get output buffer from emscripten.
+            asize = size;
+        }
+        _public.size = size;
+    };
+
+    _public.getRaw = function() {
+        return ptr;
+    };
+
+    _public.getBuffer = function() {
+        // Get a Uint8Array view on the input buffer.
+        return new Uint8Array(HEAPU8.buffer, ptr, _public.size);
+    };
+
+    if (size) {
+        _public.setSize(size);
+    }
+
+    return _public;
+};
+*/
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                   Status                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+// Export Status Enum, avoiding minification.
+Module['Status'] = {
+    'UNKNOWN':  0, // PN_STATUS_UNKNOWN  The tracker is unknown.
+    'PENDING':  1, // PN_STATUS_PENDING  The message is in flight.
+                   //                    For outgoing messages, use messenger.isBuffered()
+                   //                    to see if it has been sent or not.
+    'ACCEPTED': 2, // PN_STATUS_ACCEPTED The message was accepted.
+    'REJECTED': 3, // PN_STATUS_REJECTED The message was rejected.
+    'RELEASED': 4, // PN_STATUS_RELEASED The message was released.
+    'MODIFIED': 5, // PN_STATUS_MODIFIED The message was modified.
+    'ABORTED':  6, // PN_STATUS_ABORTED  The message was aborted.
+    'SETTLED':  7  // PN_STATUS_SETTLED  The remote party has settled the message.
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                   Error                                   */
+/*                                                                           */
+/*****************************************************************************/
+
+// Export Error Enum, avoiding minification.
+Module['Error'] = {
+    'EOS':        -1, // PN_EOS
+    'ERR':        -2, // PN_ERR
+    'OVERFLOW':   -3, // PN_OVERFLOW
+    'UNDERFLOW':  -4, // PN_UNDERFLOW
+    'STATE_ERR':  -5, // PN_STATE_ERR
+    'ARG_ERR':    -6, // PN_ARG_ERR
+    'TIMEOUT':    -7, // PN_TIMEOUT
+    'INTR':       -8, // PN_INTR
+    'INPROGRESS': -9  // PN_INPROGRESS
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                 Messenger                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+Module['Messenger'] = function(name) { // Messenger Constructor.
+    /**
+     * The emscripten idiom below is used in a number of places in the JavaScript
+     * bindings to map JavaScript Strings to C style strings. ALLOC_STACK will
+     * increase the stack and place the item there. When the stack is next restored
+     * (by calling Runtime.stackRestore()), that memory will be automatically
+     * freed. In C code compiled by emscripten saving and restoring of the stack
+     * is automatic, but if we want to us ALLOC_STACK from native JavaScript we
+     * need to explicitly save and restore the stack using Runtime.stackSave()
+     * and Runtime.stackRestore() or we will leak memory.
+     * See https://github.com/kripken/emscripten/wiki/Interacting-with-code
+     * The _pn_messenger constructor copies the char* passed to it.
+     */
+    var sp = Runtime.stackSave();
+    this._messenger = _pn_messenger(name ? allocate(intArrayFromString(name), 'i8', ALLOC_STACK) : 0);
+    Runtime.stackRestore(sp);
+
+    /**
+     * Initiate Messenger non-blocking mode. For JavaScript we make this the
+     * default behaviour and don't export this method because JavaScript is
+     * fundamentally an asynchronous non-blocking execution environment.
+     */
+    _pn_messenger_set_blocking(this._messenger, false);
+};
+
+Module['Messenger'].PN_CUMULATIVE = 0x1; // Protected Class attribute.
+
+ // Expose prototype as a variable to make method declarations less verbose.
+var _Messenger_ = Module['Messenger'].prototype;
+
+// ************************* Protected methods ********************************
+
+// We use the dot notation rather than associative array form for protected
+// methods so they are visible to this "package", but the Closure compiler will
+// minify and obfuscate names, effectively making a defacto "protected" method.
+
+/**
+ * This helper method checks the supplied error code, converts it into an
+ * exception and throws the exception. This method will try to use the message
+ * populated in pn_messenger_error(), if present, but if not it will fall
+ * back to using the basic error code rendering from pn_code().
+ * @param code the error code to check.
+ */
+_Messenger_._check = function(code) {
+    if (code < 0) {
+        if (code === Module['Error']['INPROGRESS']) {
+            return code;
+        }
+
+        var errno = this['getErrno']();
+        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
+
+        throw { // TODO Improve name and level.
+            name:     'Messenger Error', 
+            level:    'Show Stopper', 
+            message:  message, 
+            toString: function() {return this.name + ': ' + this.message}
+        };
+    } else {
+        return code;
+    }
+};
+
+// *************************** Public methods *****************************
+
+/**
+ * N.B. The following methods are not exported by the JavaScript Messenger
+ * binding for reasons described below.
+ *
+ * For these methods it is expected that security would be implemented via
+ * a secure WebSocket. TODO what happens if we decide to implement TCP sockets
+ * via Node.js net library. If we do that we may want to compile OpenSSL
+ * using emscripten and include these methods.
+ * pn_messenger_set_certificate()
+ * pn_messenger_get_certificate()
+ * pn_messenger_set_private_key()
+ * pn_messenger_get_private_key()
+ * pn_messenger_set_password()
+ * pn_messenger_get_password()
+ * pn_messenger_set_trusted_certificates()
+ * pn_messenger_get_trusted_certificates()
+ *
+ * For these methods the implementation is fairly meaningless because JavaScript
+ * is a fundamentally asynchronous non-blocking environment.
+ * pn_messenger_set_timeout()
+ * pn_messenger_set_blocking()
+ * pn_messenger_interrupt()
+ * pn_messenger_send() // Not sure if this is useful in JavaScript.
+ */
+
+/**
+ * Retrieves the name of a Messenger.
+ * @return the name of the messenger.
+ */
+_Messenger_['getName'] = function() {
+    return Pointer_stringify(_pn_messenger_name(this._messenger));
+};
+
+/**
+ * Retrieves the timeout for a Messenger.
+ * @return zero because JavaScript is fundamentally non-blocking.
+ */
+_Messenger_['getTimeout'] = function() {
+    return 0;
+};
+
+/**
+ * Accessor for messenger blocking mode.
+ * @return false because JavaScript is fundamentally non-blocking.
+ */
+_Messenger_['isBlocking'] = function() {
+    return true;
+};
+
+/**
+ * Free the Messenger. This will close all connections that are managed
+ * by the Messenger. Call the stop method before destroying the Messenger.
+ * N.B. This method has to be called explicitly in JavaScript as we can't
+ * intercept finalisers, so we need to remember to free before removing refs.
+ */
+_Messenger_['free'] = function() {
+    _pn_messenger_free(this._messenger);
+};
+
+/**
+ * @return the most recent error message code.
+ */
+_Messenger_['getErrno'] = function() {
+    return _pn_messenger_errno(this._messenger);
+};
+
+/**
+ * @return the most recent error message as a String.
+ */
+_Messenger_['getError'] = function() {
+    return Pointer_stringify(_pn_error_text(_pn_messenger_error(this._messenger)));
+};
+
+/**
+ * Returns the size of the outgoing window that was set with
+ * pn_messenger_set_outgoing_window. The default is 0.
+ * @return the outgoing window.
+ */
+_Messenger_['getOutgoingWindow'] = function() {
+    return _pn_messenger_get_outgoing_window(this._messenger);
+};
+
+/**
+ * Sets the outgoing tracking window for the Messenger. The Messenger will
+ * track the remote status of this many outgoing deliveries after calling
+ * send. Defaults to zero.
+ *
+ * A Message enters this window when you call put() with the Message.
+ * If your outgoing window size is n, and you call put() n+1 times, status
+ * information will no longer be available for the first Message.
+ * @param window the size of the tracking window in messages.
+ */
+_Messenger_['setOutgoingWindow'] = function(window) {
+    this._check(_pn_messenger_set_outgoing_window(this._messenger, window));
+};
+
+/**
+ * Returns the size of the incoming window that was set with
+ * pn_messenger_set_incoming_window. The default is 0.
+ * @return the incoming window.
+ */
+_Messenger_['getIncomingWindow'] = function() {
+    return _pn_messenger_get_incoming_window(this._messenger);
+};
+
+/**
+ * Sets the incoming tracking window for the Messenger. The Messenger will
+ * track the remote status of this many incoming deliveries after calling
+ * send. Defaults to zero.
+ *
+ * Messages enter this window only when you take them into your application
+ * using get(). If your incoming window size is n, and you get() n+1 messages
+ * without explicitly accepting or rejecting the oldest message, then the
+ * Message that passes beyond the edge of the incoming window will be assigned
+ * the default disposition of its link.
+ * @param window the size of the tracking window in messages.
+ */
+_Messenger_['setIncomingWindow'] = function(window) {
+    this._check(_pn_messenger_set_incoming_window(this._messenger, window));
+};
+
+/**
+ * Currently a no-op placeholder. For future compatibility, do not send or
+ * recv messages before starting the Messenger.
+ */
+_Messenger_['start'] = function() {
+    this._check(_pn_messenger_start(this._messenger));
+};
+
+/**
+ * Transitions the Messenger to an inactive state. An inactive Messenger
+ * will not send or receive messages from its internal queues. A Messenger
+ * should be stopped before being discarded to ensure a clean shutdown
+ * handshake occurs on any internally managed connections.
+ *
+ * The Messenger may require some time to stop if it is busy, and in that
+ * case will return PN_INPROGRESS. In that case, call isStopped to see if
+ * it has fully stopped.
+ */
+_Messenger_['stop'] = function() {
+    return this._check(_pn_messenger_stop(this._messenger));
+};
+
+/**
+ * @return Returns true iff a Messenger is in the stopped state.
+ */
+_Messenger_['isStopped'] = function() {
+    return (_pn_messenger_stopped(this._messenger) > 0);
+};
+
+/**
+ * Subscribes the Messenger to messages originating from the
+ * specified source. The source is an address as specified in the
+ * Messenger introduction with the following addition. If the
+ * domain portion of the address begins with the '~' character, the
+ * Messenger will interpret the domain as host/port, bind to it,
+ * and listen for incoming messages. For example "~0.0.0.0",
+ * "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
+ * local interface and listen for incoming messages with the last
+ * variant only permitting incoming SSL connections.
+ * @param source the source address we're subscribing to.
+ * @return a subscription.
+ */
+_Messenger_['subscribe'] = function(source) {
+    if (!source) {
+        this._check(Module['Error']['ARG_ERR']);
+    }
+    var sp = Runtime.stackSave();
+    var subscription = _pn_messenger_subscribe(this._messenger,
+                                               allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
+    Runtime.stackRestore(sp);
+    if (!subscription) {
+        this._check(Module['Error']['ERR']);
+    }
+    return new Subscription(subscription);
+};
+
+/**
+ * Places the content contained in the message onto the outgoing queue
+ * of the Messenger. This method will never block, however it will send any
+ * unblocked Messages in the outgoing queue immediately and leave any blocked
+ * Messages remaining in the outgoing queue. The send call may be used to
+ * block until the outgoing queue is empty. The outgoing property may be
+ * used to check the depth of the outgoing queue.
+ *
+ * When the content in a given Message object is copied to the outgoing
+ * message queue, you may then modify or discard the Message object
+ * without having any impact on the content in the outgoing queue.
+ *
+ * This method returns an outgoing tracker for the Message.  The tracker
+ * can be used to determine the delivery status of the Message.
+ * @param message a Message to send.
+ * @return a tracker.
+ */
+_Messenger_['put'] = function(message) {
+    message._preEncode();
+    this._check(_pn_messenger_put(this._messenger, message._message));
+
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var low = _pn_messenger_outgoing_tracker(this._messenger);
+    var high = tempRet0;
+    return new Data.Long(low, high);
+};
+
+/**
+ * Gets the last known remote state of the delivery associated with the given tracker.
+ * @param tracker the tracker whose status is to be retrieved.
+ * @return one of None, PENDING, REJECTED, or ACCEPTED.
+ */
+_Messenger_['status'] = function(tracker) {
+    return _pn_messenger_status(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits());
+};
+
+/**
+ * Checks if the delivery associated with the given tracker is still waiting to be sent.
+ * @param tracker the tracker identifying the delivery.
+ * @return true if delivery is still buffered.
+ */
+_Messenger_['isBuffered'] = function(tracker) {
+    return (_pn_messenger_buffered(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits()) > 0);
+};
+
+/**
+ * Frees a Messenger from tracking the status associated with a given tracker.
+ * If you don't supply a tracker, all outgoing messages up to the most recent
+ * will be settled.
+ * @param tracker the tracker identifying the delivery.
+ */
+_Messenger_['settle'] = function(tracker) {
+console.log("settle: not fully tested yet");
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var flags = 0;
+    if (tracker == null) {
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = tempRet0;
+        tracker = new Data.Long(low, high);
+        flags = Module['Messenger'].PN_CUMULATIVE;
+    }
+
+    this._check(_pn_messenger_settle(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
+};
+
+/**
+ * Sends or receives any outstanding messages queued for a Messenger.
+ * For JavaScript the only timeout that makes sense is 0 == do not block.
+ * This method may also do I/O work other than sending and receiving messages.
+ * For example, closing connections after messenger.stop() has been called.
+ * @return 0 if no work to do, < 0 if error, or 1 if work was done.
+ */
+_Messenger_['work'] = function() {
+    return _pn_messenger_work(this._messenger, 0);
+};
+
+/**
+ * Receives up to limit messages into the incoming queue.  If no value for limit
+ * is supplied, this call will receive as many messages as it can buffer internally.
+ * @param limit the maximum number of messages to receive or -1 to to receive
+ *        as many messages as it can buffer internally.
+ */
+_Messenger_['recv'] = function(limit) {
+    this._check(_pn_messenger_recv(this._messenger, (limit ? limit : -1)));
+};
+
+/**
+ * Returns the capacity of the incoming message queue of messenger. Note this
+ * count does not include those messages already available on the incoming queue.
+ * @return the message queue capacity.
+ */
+_Messenger_['receiving'] = function() {
+    return _pn_messenger_receiving(this._messenger);
+};
+
+/**
+ * Moves the message from the head of the incoming message queue into the
+ * supplied message object. Any content in the message will be overwritten.
+ *
+ * A tracker for the incoming Message is returned. The tracker can later be
+ * used to communicate your acceptance or rejection of the Message.
+ *
+ * @param message the destination message object. If no Message object is
+ *        passed, the Message popped from the head of the queue is discarded.
+ * @return a tracker for the incoming Message.
+ */
+_Messenger_['get'] = function(message) {
+    var impl = null;
+    if (message) {
+        impl = message._message;
+    }
+
+    this._check(_pn_messenger_get(this._messenger, impl));
+
+    if (message) {
+        message._postDecode();
+    }
+
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var low = _pn_messenger_incoming_tracker(this._messenger);
+    var high = tempRet0;
+console.log("get low = " + low);
+console.log("get high = " + high);
+    return new Data.Long(low, high);
+};
+
+/**
+ * Returns the Subscription of the Message returned by the most recent call
+ * to get, or null if pn_messenger_get has not yet been called.
+ * @return a Subscription or null if get has never been called for this Messenger.
+ */
+_Messenger_['incomingSubscription'] = function() {row
+console.log("incomingSubscription: haven't yet proved this works yet");
+
+    var subscription = _pn_messenger_incoming_subscription(this._messenger);
+    if (subscription) {
+        return new Subscription(subscription);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Signal the sender that you have acted on the Message pointed to by the tracker.
+ * If no tracker is supplied, then all messages that have been returned by the
+ * get method are accepted, except those that have already been auto-settled
+ * by passing beyond your incoming window size.
+ * @param tracker the tracker identifying the delivery.
+ */
+_Messenger_['accept'] = function(tracker) {
+console.log("accept: not fully tested yet");
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var flags = 0;
+    if (tracker == null) {
+        var low = _pn_messenger_incoming_tracker(this._messenger);
+        var high = tempRet0;
+        tracker = new Data.Long(low, high);
+        flags = Module['Messenger'].PN_CUMULATIVE;
+    }
+
+    this._check(_pn_messenger_accept(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
+};
+
+/**
+ * Rejects the Message indicated by the tracker.  If no tracker is supplied,
+ * all messages that have been returned by the get method are rejected, except
+ * those already auto-settled by passing beyond your outgoing window size.
+ * @param tracker the tracker identifying the delivery.
+ */
+_Messenger_['reject'] = function(tracker) {
+console.log("reject: not fully tested yet");
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var flags = 0;
+    if (tracker == null) {
+        var low = _pn_messenger_incoming_tracker(this._messenger);
+        var high = tempRet0;
+        tracker = new Data.Long(low, high);
+        flags = Module['Messenger'].PN_CUMULATIVE;
+    }
+
+    this._check(_pn_messenger_reject(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
+};
+
+/**
+ * Returns the number of messages in the outgoing message queue of a messenger.
+ * @return the outgoing queue depth.
+ */
+_Messenger_['outgoing'] = function() {
+    return _pn_messenger_outgoing(this._messenger);
+};
+
+/**
+ * Returns the number of messages in the incoming message queue of a messenger.
+ * @return the incoming queue depth.
+ */
+_Messenger_['incoming'] = function() {
+    return _pn_messenger_incoming(this._messenger);
+};
+
+
+
+/**
+ * 
+ * @param pattern a glob pattern to select messages.
+ * @param address an address indicating outgoing address rewrite.
+ */
+_Messenger_['route'] = function(pattern, address) {
+console.log("route: not fully tested yet");
+    var sp = Runtime.stackSave();
+    this._check(_pn_messenger_route(this._messenger,
+                                    allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
+                                    allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Similar to route(), except that the destination of the Message is determined
+ * before the message address is rewritten.
+ *
+ * The outgoing address is only rewritten after routing has been finalized. If
+ * a message has an outgoing address of "amqp://0.0.0.0:5678", and a rewriting
+ * rule that changes its outgoing address to "foo", it will still arrive at the
+ * peer that is listening on "amqp://0.0.0.0:5678", but when it arrives there,
+ * the receiver will see its outgoing address as "foo".
+ *
+ * The default rewrite rule removes username and password from addresses
+ * before they are transmitted.
+ * @param pattern a glob pattern to select messages.
+ * @param address an address indicating outgoing address rewrite.
+ */
+_Messenger_['rewrite'] = function(pattern, address) {
+console.log("rewrite: not fully tested yet");
+    var sp = Runtime.stackSave();
+    this._check(_pn_messenger_rewrite(this._messenger,
+                                      allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
+                                      allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+
+
+
+// TODO This needs tweaking to enable working with multiple Messenger instances.
+_Messenger_['setNetworkCallback'] = function(callback) {
+//console.log("setting network callback");
+
+    // Expose messenger reference in the scope of Messenger.Messenger so that
+    // the _work function can correctly dereference it.
+    var messenger = this._messenger;
+
+    function _work() {
+        //console.log("                          *** internal work ***");
+
+        var err = _pn_messenger_work(messenger, 0);
+//console.log("err = " + err);
+
+        if (err >= 0) {
+            callback();
+        }
+
+        err = _pn_messenger_work(messenger, 0);
+//console.log("err = " + err);
+
+        if (err >= 0) {
+            callback();
+        }
+    };
+
+    // Set the emscripten network callback function.
+    Module['networkCallback'] = _work;
+};
+
+
+
+
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                               Subscription                                */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * This class is a wrapper for Messenger's subscriptions.
+ * Subscriptions should never be *directly* instantiated by client code only via
+ * Messenger.subscribe() or Messenger.incomingSubscription(), so we declare the
+ * constructor in the scope of the package and don't export it via Module.
+ */
+var Subscription = function(subscription) { // Subscription Constructor.
+    this._subscription = subscription;
+};
+
+/**
+ * TODO Not sure exactly what pn_subscription_get_context does.
+ * @return the Subscription's Context.
+ */
+Subscription.prototype['getContext'] = function() {
+    return _pn_subscription_get_context(this._subscription);
+};
+
+/**
+ * TODO Not sure exactly what pn_subscription_set_context does.
+ * @param context the Subscription's new Context.
+ */
+Subscription.prototype['setContext'] = function(context) {
+    _pn_subscription_set_context(this._subscription, context);
+};
+
+/**
+ * @return the Subscription's Address.
+ */
+Subscription.prototype['getAddress'] = function() {
+    return Pointer_stringify(_pn_subscription_address(this._subscription));
+};
+
+
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                  Message                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+Module['Message'] = function() { // Message Constructor.
+    this._message = _pn_message();
+
+    // ************************* Public properties ****************************
+
+    /**
+     * Delivery instructions for the Message.
+     * @type map
+     */
+    this['instructions'] = null;
+
+    /**
+     * Infrastructure defined Message annotations.
+     * @type map
+     */
+    this['annotations'] = null;
+
+    /**
+     * Application defined Message properties.
+     * @type map
+     */
+    this['properties'] = null;
+
+    /**
+     * Message body.
+     * @type bytes | unicode | map | list | int | long | float | UUID
+     */
+    this['body'] = null;
+};
+
+// Expose prototype as a variable to make method declarations less verbose.
+var _Message_ = Module['Message'].prototype;
+
+// ************************* Protected methods ********************************
+
+// We use the dot notation rather than associative array form for protected
+// methods so they are visible to this "package", but the Closure compiler will
+// minify and obfuscate names, effectively making a defacto "protected" method.
+
+/**
+ * This helper method checks the supplied error code, converts it into an
+ * exception and throws the exception. This method will try to use the message
+ * populated in pn_message_error(), if present, but if not it will fall
+ * back to using the basic error code rendering from pn_code().
+ * @param code the error code to check.
+ */
+_Message_._check = function(code) {
+    if (code < 0) {
+        var errno = this['getErrno']();
+        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
+
+        throw { // TODO Improve name and level.
+            name:     'Message Error', 
+            level:    'Show Stopper', 
+            message:  message, 
+            toString: function() {return this.name + ': ' + this.message} 
+        };
+    } else {
+        return code;
+    }
+};
+
+/**
+ * Encode the Message prior to sending on the wire.
+ */
+_Message_._preEncode = function() {
+    if (this.instructions) {
+console.log("Encoding instructions");
+        var inst = new Data(_pn_message_instructions(this._message));
+        inst.clear();
+        inst.putObject(this.instructions);
+    }
+
+    if (this.annotations) {
+console.log("Encoding annotations");
+        var ann = new Data(_pn_message_annotations(this._message));
+        ann.clear();
+        ann.putObject(this.annotations);
+    }
+
+    if (this.properties) {
+console.log("Encoding properties");
+        var props = new Data(_pn_message_properties(this._message));
+        props.clear();
+        props.putObject(this.properties);
+    }
+
+    if (this.body != null) {
+console.log("Encoding body");
+        var body = new Data(_pn_message_body(this._message));
+        body.clear();
+        body.putObject(this.body);
+    }
+};
+
+/**
+ * Decode the Message after receiving off the wire.
+ */
+_Message_._postDecode = function() {
+    var inst = new Data(_pn_message_instructions(this._message));
+    var ann = new Data(_pn_message_annotations(this._message));
+    var props = new Data(_pn_message_properties(this._message));
+    var body = new Data(_pn_message_body(this._message));
+
+    if (inst.next()) {
+        this.instructions = inst.getObject();
+    } else {
+        this.instructions = {};
+    }
+
+    if (ann.next()) {
+        this.annotations = ann.getObject();
+    } else {
+        this.annotations = {};
+    }
+
+    if (props.next()) {
+        this.properties = props.getObject();
+    } else {
+        this.properties = {};
+    }
+
+    if (body.next()) {
+        this.body = body.getObject();
+    } else {
+        this.body = null;
+    }
+};
+
+// *************************** Public methods *********************************
+
+/**
+ * Free the Message.
+ * N.B. This method has to be called explicitly in JavaScript as we can't
+ * intercept finalisers, so we need to remember to free before removing refs.
+ */
+_Message_['free'] = function() {
+    _pn_message_free(this._message);
+};
+
+/**
+ * @return the most recent error message code.
+ */
+_Message_['getErrno'] = function() {
+    return _pn_message_errno(this._message);
+};
+
+/**
+ * @return the most recent error message as a String.
+ */
+_Message_['getError'] = function() {
+    return Pointer_stringify(_pn_error_text(_pn_message_error(this._message)));
+};
+
+/**
+ * @return the address of the Message.
+ */
+_Message_['getAddress'] = function() {
+    return Pointer_stringify(_pn_message_get_address(this._message));
+};
+
+/**
+ * Set the address of the Message.
+ * @param address the address we want to send the Message to.
+ */
+_Message_['setAddress'] = function(address) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_address(this._message, allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * @return the subject of the Message.
+ */
+_Message_['getSubject'] = function() {
+    return Pointer_stringify(_pn_message_get_subject(this._message));
+};
+
+/**
+ * Set the subject of the Message.
+ * @param subject the subject we want to set for the Message.
+ */
+_Message_['setSubject'] = function(subject) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_subject(this._message, allocate(intArrayFromString(subject), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                    Data                                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * The Data class provides an interface for decoding, extracting, creating, and
+ * encoding arbitrary AMQP data. A Data object contains a tree of AMQP values.
+ * Leaf nodes in this tree correspond to scalars in the AMQP type system such as
+ * ints<INT> or strings<STRING>. Non-leaf nodes in this tree correspond to compound
+ * values in the AMQP type system such as lists<LIST>, maps<MAP>, arrays<ARRAY>,
+ * or described values<DESCRIBED>. The root node of the tree is the Data object
+ * itself and can have an arbitrary number of children.
+ *
+ * A Data object maintains the notion of the current sibling node and a current
+ * parent node. Siblings are ordered within their parent. Values are accessed
+ * and/or added by using the next, prev, enter, and exit methods to navigate to
+ * the desired location in the tree and using the supplied variety of put* and
+ * get* methods to access or add a value of the desired type.
+ *
+ * The put* methods will always add a value after the current node in the tree.
+ * If the current node has a next sibling the put* method will overwrite the value
+ * on this node. If there is no current node or the current node has no next
+ * sibling then one will be added. The put* methods always set the added/modified
+ * node to the current node. The get* methods read the value of the current node
+ * and do not change which node is current.                                                                         
+ */
+Module['Data'] = function(data) { // Data Constructor.
+    this._data = data;
+
+    if (!data) {
+        console.log("Warning Data created with null data");
+    }
+};
+
+// Expose constructor as package scope variable to make internal calls less verbose.
+var Data = Module['Data'];
+
+// Expose prototype as a variable to make method declarations less verbose.
+var _Data_ = Data.prototype;
+
+/**
+ * Look-up table mapping proton-c types to the accessor method used to
+ * deserialise the type. N.B. this is a simple Array and not a map because the
+ * types that we get back from pn_data_type are integers from the pn_type_t enum.
+ */
+Data.GetMappings = [
+    'getNull',            // 0
+    'getNull',            // PN_NULL = 1
+    'getBoolean',         // PN_BOOL = 2
+    'getUnsignedByte',    // PN_UBYTE = 3
+    'getByte',            // PN_BYTE = 4
+    'getUnsignedShort',   // PN_USHORT = 5
+    'getShort',           // PN_SHORT = 6
+    'getUnsignedInteger', // PN_UINT = 7
+    'getInteger',         // PN_INT = 8
+    'getChar',            // PN_CHAR = 9
+    'getUnsignedLong',    // PN_ULONG = 10
+    'getLong',            // PN_LONG = 11
+    'getTimestamp',       // PN_TIMESTAMP = 12
+    'getFloat',           // PN_FLOAT = 13
+    'getDouble',          // PN_DOUBLE = 14
+    'getDecimal32',       // PN_DECIMAL32 = 15
+    'getDecimal64',       // PN_DECIMAL64 = 16
+    'getDecimal128',      // PN_DECIMAL128 = 17
+    'getUUID',            // PN_UUID = 18
+    'getBinary',          // PN_BINARY = 19
+    'getString',          // PN_STRING = 20
+    'getSymbol',          // PN_SYMBOL = 21
+    'getDescribed',       // PN_DESCRIBED = 22
+    'getArray',           // PN_ARRAY = 23
+    'getJSArray',         // PN_LIST = 24
+    'getDictionary'       // PN_MAP = 25
+];
+
+// *************************** Class methods **********************************
+
+/**
+ * Test if a given Object is an Array.
+ * @param o the Object that we wish to test.
+ * @return true iff the Object is an Array.
+ */
+Data.isArray = Array.isArray || function(o) {
+console.log("Data.isArray");
+    return Object.prototype.toString.call(o) === '[object Array]';
+};
+
+/**
+ * Test if a given Object is a Number.
+ * @param o the Object that we wish to test.
+ * @return true iff the Object is a Number.
+ */
+Data.isNumber = function(o) {
+    return typeof o === 'number' || 
+          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object Number]');
+};
+
+/**
+ * Test if a given Object is a String.
+ * @param o the Object that we wish to test.
+ * @return true iff the Object is a String.
+ */
+Data.isString = function(o) {
+    return typeof o === 'string' ||
+          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object String]');
+};
+
+/**
+ * Test if a given Object is a Boolean.
+ * @param o the Object that we wish to test.
+ * @return true iff the Object is a Boolean.
+ */
+Data.isBoolean = function(o) {
+    return typeof o === 'boolean' ||
+          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object Boolean]');
+};
+
+// **************************** Inner Classes *********************************
+
+// --------------------------- proton.Data.UUID -------------------------------
+/**
+ * Create a proton.Data.UUID which is a type 4 UUID.
+ * @param u a UUID. If null a type 4 UUID is generated wich may use crypto if
+ *        supported by the platform. If u is an emscripten "pointer" we copy the
+ *        data from that. If u is a JavaScript Array we use it as-is. If u is a
+ *        String then we try to parse that as a UUID.
+ * @properties uuid is the compact array form of the UUID.
+ */
+Data['UUID'] = function(u) { // Data.UUID Constructor.
+    // Helper to copy from emscriptem allocated storage into JavaScript Array.
+    function _p2a(p) {
+        var uuid = new Array(16);
+        for (var i = 0; i < 16; i++) {
+            uuid[i] = getValue(p + i, 'i8') & 0xFF; // & 0xFF converts to unsigned.
+        }
+        return uuid;
+    };
+
+    if (!u) { // Generate UUID using emscriptem's uuid_generate implementation.
+        var sp = Runtime.stackSave();
+        var p = allocate(16, 'i8', ALLOC_STACK); // Create temporary pointer storage.
+        _uuid_generate(p);      // Generate UUID into allocated pointer.
+        this['uuid'] = _p2a(p); // Copy from allocated storage into JavaScript Array.
+        Runtime.stackRestore(sp);
+    } else if (Data.isNumber(u)) { // Use pointer that has been passed in.
+        this['uuid'] = _p2a(u);    // Copy from allocated storage into JavaScript Array.
+    } else if (Data.isArray(u)) { // Use array that has been passed in.
+        this['uuid'] = u; // Just use the JavaScript Array.
+    } else if (Data.isString(u)) { // Parse String form UUID.
+        if (u.length === 36) {
+            var i = 0;
+            var uuid = new Array(16);
+            u.toLowerCase().replace(/[0-9a-f]{2}/g, function(byte) {
+                if (i < 16) {
+                    uuid[i++] = parseInt(byte, 16);
+                }
+            });
+            this['uuid'] = uuid;
+        }
+    }
+    this.string = null;
+};
+
+/**
+ * @return the String form of a proton.Data.UUID.
+ */
+Data['UUID'].prototype.toString = function() {
+    if (!this.string) { // Check if we've cached the string version.
+        var i = 0;
+        var uu = this['uuid'];
+        var uuid = 'xxxx-xx-xx-xx-xxxxxx'.replace(/[x]/g, function(c) {
+            var r = uu[i].toString(16);
+            r = (r.length === 1) ? '0' + r : r; // Zero pad single digit hex values
+            i++;
+            return r;
+        });
+        this.string = uuid;
+    }
+    return this.string;
+};
+
+/**
+ * Compare two instances of proton.Data.UUID for equality.
+ * @param rhs the instance we wish to compare this instance with.
+ * @return true iff the two compared instances are equal.
+ */
+Data['UUID'].prototype['equals'] = function(rhs) {
+    return this.toString() === rhs.toString();
+};
+
+
+// ---------------------------- proton.Data.Symbol ---------------------------- 
+/**
+ * Create a proton.Data.Symbol.
+ * @param s a symbol
+ */
+Data['Symbol'] = function(s) { // Data.Symbol Constructor.
+    this.value = s;
+    this.length = this.value.length;
+};
+
+/**
+ * @return the String form of a proton.Data.Symbol.
+ */
+Data['Symbol'].prototype.toString = Data['Symbol'].prototype.valueOf = function() {
+    return this.value;
+};
+
+/**
+ * Compare two instances of proton.Data.Symbol for equality.
+ * @param rhs the instance we wish to compare this instance with.
+ * @return true iff the two compared instances are equal.
+ */
+Data['Symbol'].prototype['equals'] = function(rhs) {
+    return this.toString() === rhs.toString();
+};
+
+
+// ----------------------------- proton.Data.Long ----------------------------- 
+/**
+
+ */
+Data.Long = function(low, high) { // Data.Long Constructor.
+    this.low  = low  | 0;  // force into 32 signed bits.
+    this.high = high | 0;  // force into 32 signed bits.
+};
+
+// proton.Data.Long constants.
+Data.Long.TWO_PWR_16_DBL_ = 1 << 16;
+Data.Long.TWO_PWR_32_DBL_ = Data.Long.TWO_PWR_16_DBL_ * Data.Long.TWO_PWR_16_DBL_;
+Data.Long.TWO_PWR_64_DBL_ = Data.Long.TWO_PWR_32_DBL_ * Data.Long.TWO_PWR_32_DBL_;
+Data.Long.TWO_PWR_63_DBL_ = Data.Long.TWO_PWR_64_DBL_ / 2;
+Data.Long.MAX_VALUE = new Data.Long(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
+Data.Long.MIN_VALUE = new Data.Long(0, 0x80000000 | 0);
+Data.Long.ZERO = new Data.Long(0, 0);
+Data.Long.ONE  = new Data.Long(1, 0);
+
+Data.Long.fromNumber = function(value) {
+    if (isNaN(value) || !isFinite(value)) {
+        return Data.Long.ZERO;
+    } else if (value <= -Data.Long.TWO_PWR_63_DBL_) {
+        return Data.MIN_VALUE;
+    } else if (value + 1 >= Data.Long.TWO_PWR_63_DBL_) {
+        return Data.Long.MAX_VALUE;
+    } else if (value < 0) {
+        return Data.Long.fromNumber(-value).negate();
+    } else {
+      return new Data.Long(
+          (value % Data.Long.TWO_PWR_32_DBL_) | 0,
+          (value / Data.Long.TWO_PWR_32_DBL_) | 0);
+    }
+};
+
+Data.Long.prototype.negate = function() {
+    if (this.equals(Data.Long.MIN_VALUE)) {
+        return Data.Long.MIN_VALUE;
+    } else {
+        return this.not().add(Data.Long.ONE);
+    }
+};
+
+Data.Long.prototype.add = function(other) {
+    // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
+
+    var a48 = this.high >>> 16;
+    var a32 = this.high & 0xFFFF;
+    var a16 = this.low >>> 16;
+    var a00 = this.low & 0xFFFF;
+
+    var b48 = other.high >>> 16;
+    var b32 = other.high & 0xFFFF;
+    var b16 = other.low >>> 16;
+    var b00 = other.low & 0xFFFF;
+
+    var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+    c00 += a00 + b00;
+    c16 += c00 >>> 16;
+    c00 &= 0xFFFF;
+    c16 += a16 + b16;
+    c32 += c16 >>> 16;
+    c16 &= 0xFFFF;
+    c32 += a32 + b32;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c48 += a48 + b48;
+    c48 &= 0xFFFF;
+    return new Data.Long((c16 << 16) | c00, (c48 << 16) | c32);
+};
+
+Data.Long.prototype.not = function() {
+    return new Data.Long(~this.low, ~this.high);
+};
+
+Data.Long.prototype.equals = function(other) {
+    return (this.high == other.high) && (this.low == other.low);
+};
+
+Data.Long.prototype.getHighBits = function() {
+    return this.high;
+};
+
+Data.Long.prototype.getLowBits = function() {
+    return this.low;
+};
+
+Data.Long.prototype.getLowBitsUnsigned = function() {
+    return (this.low >= 0) ? this.low : Data.Long.TWO_PWR_32_DBL_ + this.low;
+};
+
+Data.Long.prototype.toNumber = function() {
+    return (this.high * Data.Long.TWO_PWR_32_DBL_) + this.getLowBitsUnsigned();
+};
+
+Data.Long.prototype.toString = function() {
+    return this.high + ":" + this.getLowBitsUnsigned();
+};
+
+// ---------------------------- proton.Data.Binary ---------------------------- 
+
+
+// ************************* Protected methods ********************************
+
+// We use the dot notation rather than associative array form for protected
+// methods so they are visible to this "package", but the Closure compiler will
+// minify and obfuscate names, effectively making a defacto "protected" method.
+
+/**
+ * This helper method checks the supplied error code, converts it into an
+ * exception and throws the exception. This method will try to use the message
+ * populated in pn_data_error(), if present, but if not it will fall
+ * back to using the basic error code rendering from pn_code().
+ * @param code the error code to check.
+ */
+_Data_._check = function(code) {
+    if (code < 0) {
+        var errno = this['getErrno']();
+        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
+
+        throw { // TODO Improve name and level.
+            name:     'Data Error', 
+            level:    'Show Stopper', 
+            message:  message, 
+            toString: function() {return this.name + ': ' + this.message} 
+        };
+    } else {
+        return code;
+    }
+};
+
+
+// *************************** Public methods *********************************
+
+/**
+ * @return the most recent error message code.
+ */
+_Data_['getErrno'] = function() {
+    return _pn_data_errno(this._data);
+};
+
+/**
+ * @return the most recent error message as a String.
+ */
+_Data_['getError'] = function() {
+    return Pointer_stringify(_pn_error_text(_pn_data_error(this._data)));
+};
+
+/**
+ * Clears the data object.
+ */
+_Data_['clear'] = function() {
+    _pn_data_clear(this._data);
+};
+
+/**
+ * Clears current node and sets the parent to the root node.  Clearing the
+ * current node sets it _before_ the first node, calling next() will advance
+ * to the first node.
+ */
+_Data_['rewind'] = function() {
+    _pn_data_rewind(this._data);
+};
+
+/**
+ * Advances the current node to its next sibling and returns its
+ * type. If there is no next sibling the current node remains
+ * unchanged and null is returned.
+ */
+_Data_['next'] = function() {
+    var found = _pn_data_next(this._data);
+    if (found) {
+        return this.type();
+    } else {
+        return null;  
+    }
+};
+
+/**
+ * Advances the current node to its previous sibling and returns its
+ * type. If there is no previous sibling the current node remains
+ * unchanged and null is returned.
+ */
+_Data_['prev'] = function() {
+    var found = _pn_data_prev(this._data);
+    if (found) {
+        return this.type();
+    } else {
+        return null;  
+    }
+};
+
+/**
+ * Sets the parent node to the current node and clears the current node.
+ * Clearing the current node sets it _before_ the first child,
+ * call next() advances to the first child.
+ */
+_Data_['enter'] = function() {
+    return (_pn_data_enter(this._data) > 0);
+};
+
+/**
+ * Sets the current node to the parent node and the parent node to
+ * its own parent.
+ */
+_Data_['exit'] = function() {
+    return (_pn_data_exit(this._data) > 0);
+};
+
+
+
+_Data_['lookup'] = function(name) {
+    var sp = Runtime.stackSave();
+    var lookup = _pn_data_lookup(this._data, allocate(intArrayFromString(name), 'i8', ALLOC_STACK));
+    Runtime.stackRestore(sp);
+    return (lookup > 0);
+};
+
+_Data_['narrow'] = function() {
+    _pn_data_narrow(this._data);
+};
+
+_Data_['widen'] = function() {
+    _pn_data_widen(this._data);
+};
+
+
+/**
+ * @return the type of the current node.
+ */
+_Data_['type'] = function() {
+    var dtype = _pn_data_type(this._data);
+    if (dtype === -1) {
+        return null;
+    } else {
+        return dtype;
+    }
+};
+
+// TODO encode and decode
+
+/**
+ * Puts a list value. Elements may be filled by entering the list
+ * node and putting element values.
+ *
+ *  data = new Data();
+ *  data.putList();
+ *  data.enter();
+ *  data.putInt(1);
+ *  data.putInt(2);
+ *  data.putInt(3);
+ *  data.exit();
+ */
+_Data_['putList'] = function() {
+    this._check(_pn_data_put_list(this._data));
+};
+
+/**
+ * Puts a map value. Elements may be filled by entering the map node
+ * and putting alternating key value pairs.
+ *
+ *  data = new Data();
+ *  data.putMap();
+ *  data.enter();
+ *  data.putString("key");
+ *  data.putString("value");
+ *  data.exit();
+ */
+_Data_['putMap'] = function() {
+    this._check(_pn_data_put_map(this._data));
+};
+
+// TODO putArray and putDescribed
+
+/**
+ * Puts a null value.
+ */
+_Data_['putNull'] = function() {
+    this._check(_pn_data_put_null(this._data));
+};
+
+/**
+ * Puts a boolean value.
+ * @param b a boolean value.
+ */
+_Data_['putBoolean'] = function(b) {
+    this._check(_pn_data_put_bool(this._data, b));
+};
+
+/**
+ * Puts a unsigned byte value.
+ * @param ub an integral value.
+ */
+_Data_['putUnsignedByte'] = function(ub) {
+    this._check(_pn_data_put_ubyte(this._data, ub));
+};
+
+/**
+ * Puts a signed byte value.
+ * @param b an integral value.
+ */
+_Data_['putByte'] = function(b) {
+    this._check(_pn_data_put_byte(this._data, b));
+};
+
+/**
+ * Puts a unsigned short value.
+ * @param us an integral value.
+ */
+_Data_['putUnsignedShort'] = function(us) {
+    this._check(_pn_data_put_ushort(this._data, us));
+};
+
+/**
+ * Puts a signed short value.
+ * @param s an integral value.
+ */
+_Data_['putShort'] = function(s) {
+    this._check(_pn_data_put_short(this._data, s));
+};
+
+/**
+ * Puts a unsigned integer value.
+ * @param ui an integral value.
+ */
+_Data_['putUnsignedInteger'] = function(ui) {
+    this._check(_pn_data_put_uint(this._data, ui));
+};
+
+/**
+ * Puts a signed integer value.
+ * @param i an integral value.
+ */
+_Data_['putInteger'] = function(i) {
+    this._check(_pn_data_put_int(this._data, i));
+};
+
+/**
+ * Puts a signed char value.
+ * @param c a single character.
+ */
+_Data_['putChar'] = function(c) {
+console.log("putChar not properly implemented yet");
+    this._check(_pn_data_put_char(this._data, c));
+};
+
+/**
+ * Puts a unsigned long value.
+ * @param ul an integral value.
+ */
+_Data_['putUnsignedLong'] = function(ul) {
+    this._check(_pn_data_put_ulong(this._data, ul));
+};
+
+/**
+ * Puts a signed long value.
+ * @param i an integral value.
+ */
+_Data_['putLong'] = function(l) {
+console.log("putLong " + l);
+
+    var long = Data.Long.fromNumber(l);
+    this._check(_pn_data_put_long(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
+};
+
+/**
+ * Puts a timestamp.
+ * @param t an integral value.
+ */
+_Data_['putTimestamp'] = function(t) {
+console.log("putTimestamp not properly implemented yet");
+    this._check(_pn_data_put_timestamp(this._data, t));
+};
+
+/**
+ * Puts a float value.
+ * @param f a floating point value.
+ */
+_Data_['putFloat'] = function(f) {
+    this._check(_pn_data_put_float(this._data, f));
+};
+
+/**
+ * Puts a double value.
+ * @param d a floating point value.
+ */
+_Data_['putDouble'] = function(d) {
+    this._check(_pn_data_put_double(this._data, d));
+};
+
+/**
+ * Puts a decimal32 value.
+ * @param d a decimal32 value.
+ */
+_Data_['putDecimal32'] = function(d) {
+    this._check(_pn_data_put_decimal32(this._data, d));
+};
+
+/**
+ * Puts a decimal64 value.
+ * @param d a decimal64 value.
+ */
+_Data_['putDecimal64'] = function(d) {
+    this._check(_pn_data_put_decimal64(this._data, d));
+};
+
+/**
+ * Puts a decimal128 value.
+ * @param d a decimal128 value.
+ */
+_Data_['putDecimal128'] = function(d) {
+    this._check(_pn_data_put_decimal128(this._data, d));
+};
+
+/**
+ * Puts a UUID value.
+ * @param u a uuid value
+ */
+_Data_['putUUID'] = function(u) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_data_put_uuid(this._data, allocate(u['uuid'], 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Puts a binary value.
+ * @param b a binary value.
+ */
+_Data_['putBinary'] = function(d) {
+console.log("putBinary not properly implemented yet");
+    this._check(_pn_data_put_binary(this._data, b));
+};
+
+/**
+ * Puts a unicode string value.
+ * @param s a unicode string value.
+ */
+_Data_['putString'] = function(s) {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_data_put_string(data, pn_bytes(strlen(text), text));
+
+    // First create an array from the JavaScript String using the intArrayFromString
+    // helper function (from emscripten/src/preamble.js). We use this idiom in a
+    // few places but here we create array as a separate var as we need its length.
+    var array = intArrayFromString(s);
+    // Allocate temporary storage for the array on the emscripten stack.
+    var str = allocate(array, 'i8', ALLOC_STACK);
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the compiled
+    // pn_bytes. The second parameter is the length of the array - 1 because it
+    // is a NULL terminated C style string at this point.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, array.length - 1, str);
+
+    // The compiled pn_data_put_string takes the pn_bytes_t by reference not value.
+    this._check(_pn_data_put_string(this._data, bytes));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Puts a symbolic value. According to the AMQP 1.0 Specification Symbols are
+ * values from a constrained domain. Although the set of possible domains is
+ * open-ended, typically the both number and size of symbols in use for any
+ * given application will be small, e.g. small enough that it is reasonable to
+ * cache all the distinct values. Symbols are encoded as ASCII characters.
+ * @param s the symbol name.
+ */
+_Data_['putSymbol'] = function(s) {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_data_put_symbol(data, pn_bytes(strlen(text), text));
+
+    // First create an array from the JavaScript String using the intArrayFromString
+    // helper function (from emscripten/src/preamble.js). We use this idiom in a
+    // few places but here we create array as a separate var as we need its length.
+    var array = intArrayFromString(s);
+    // Allocate temporary storage for the array on the emscripten stack.
+    var str = allocate(array, 'i8', ALLOC_STACK);
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the compiled
+    // pn_bytes. The second parameter is the length of the array - 1 because it
+    // is a NULL terminated C style string at this point.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, array.length - 1, str);
+
+    // The compiled pn_data_put_symbol takes the pn_bytes_t by reference not value.
+    this._check(_pn_data_put_symbol(this._data, bytes));
+    Runtime.stackRestore(sp);
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// TODO getArray and isDescribed
+
+/**
+ * @return a null value.
+ */
+_Data_['getNull'] = function() {
+    return null;
+};
+
+/**
+ * Checks if the current node is a null.
+ */
+_Data_['isNull'] = function() {
+    return _pn_data_is_null(this._data);
+};
+
+/**
+ * @return value if the current node is a boolean, returns false otherwise.
+ */
+_Data_['getBoolean'] = function() {
+    return (_pn_data_get_bool(this._data) > 0);
+};
+
+/**
+ * @return value if the current node is an unsigned byte, returns 0 otherwise.
+ */
+_Data_['getUnsignedByte'] = function() {
+    return _pn_data_get_ubyte(this._data);
+};
+
+/**
+ * @return value if the current node is a signed byte, returns 0 otherwise.
+ */
+_Data_['getByte'] = function() {
+    return _pn_data_get_byte(this._data);
+};
+
+/**
+ * @return value if the current node is an unsigned short, returns 0 otherwise.
+ */
+_Data_['getUnsignedShort'] = function() {
+    return _pn_data_get_ushort(this._data);
+};
+
+/**
+ * @return value if the current node is a signed short, returns 0 otherwise.
+ */
+_Data_['getShort'] = function() {
+    return _pn_data_get_short(this._data);
+};
+
+/**
+ * @return value if the current node is an unsigned int, returns 0 otherwise.
+ */
+_Data_['getUnsignedInteger'] = function() {
+    return _pn_data_get_uint(this._data);
+};
+
+/**
+ * @return value if the current node is a signed int, returns 0 otherwise.
+ */
+_Data_['getInteger'] = function() {
+    return _pn_data_put_int(this._data);
+};
+
+/**
+ * @return value if the current node is a character, returns 0 otherwise.
+ */
+_Data_['getChar'] = function() {
+console.log("getChar not properly implemented yet");
+return "character";
+    //return _pn_data_get_char(this._data);
+};
+
+/**
+ * @return value if the current node is an unsigned long, returns 0 otherwise.
+ */
+_Data_['getUnsignedLong'] = function() {
+    return _pn_data_get_ulong(this._data);
+};
+
+/**
+ * @return value if the current node is a signed long, returns 0 otherwise.
+ */
+_Data_['getLong'] = function() {
+console.log("getLong");
+    // Getting the long is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low = _pn_data_get_long(this._data);
+    var high = tempRet0;
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+
+console.log("Data.getLong() long = " + long);
+
+    return long;
+};
+
+/**
+ * @return value if the current node is a timestamp, returns 0 otherwise.
+ */
+_Data_['getTimestamp'] = function() {
+console.log("getTimestamp not properly implemented yet");
+return 123456;
+    //return _pn_data_get_timestamp(this._data);
+};
+
+/**
+ * @return value if the current node is a float, returns 0 otherwise.
+ */
+_Data_['getFloat'] = function() {
+    return _pn_data_get_float(this._data);
+};
+
+/**
+ * @return value if the current node is a double, returns 0 otherwise.
+ */
+_Data_['getDouble'] = function() {
+    return _pn_data_get_double(this._data);
+};
+
+/**
+ * @return value if the current node is a decimal32, returns 0 otherwise.
+ */
+_Data_['getDecimal32'] = function() {
+console.log("getDecimal32 not properly implemented yet");
+    return _pn_data_get_decimal32(this._data);
+};
+
+/**
+ * @return value if the current node is a decimal64, returns 0 otherwise.
+ */
+_Data_['getDecimal64'] = function() {
+console.log("getDecimal64 not properly implemented yet");
+    return _pn_data_get_decimal64(this._data);
+};
+
+/**
+ * @return value if the current node is a decimal128, returns 0 otherwise.
+ */
+_Data_['getDecimal128'] = function() {
+console.log("getDecimal128 not properly implemented yet");
+    return _pn_data_get_decimal128(this._data);
+};
+
+/**
+ * @return value if the current node is a UUID, returns null otherwise.
+ */
+_Data_['getUUID'] = function() {
+    var sp = Runtime.stackSave();
+
+    // Here's the quirky bit, pn_data_get_uuid actually returns pn_uuid_t
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 16 bytes storage for pn_uuid_t on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_uuid.
+    var bytes = allocate(16, 'i8', ALLOC_STACK); // pn_uuid_t is 16 bytes.
+    _pn_data_get_uuid(bytes, this._data);
+
+    // Create a new UUID from the bytes
+    var uuid = new Data['UUID'](bytes);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return uuid;
+};
+
+/**
+ * @return value if the current node is a Binary, returns null otherwise.
+ */
+_Data_['getBinary'] = function() {
+console.log("getBinary not properly implemented yet");
+    //this._check(_pn_data_put_binary(this._data, b));
+};
+
+/**
+ * @return value if the current node is a String, returns "" otherwise.
+ */
+_Data_['getString'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes bytes = pn_data_get_string(data);
+
+    // Here's the quirky bit, pn_data_get_string actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_string.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_data_get_string(bytes, this._data);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a native JavaScript String from the pn_bytes_t information.
+    var string = Pointer_stringify(start, size);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return string;
+};
+
+/**
+ * Gets a symbolic value. According to the AMQP 1.0 Specification Symbols are
+ * values from a constrained domain. Although the set of possible domains is
+ * open-ended, typically the both number and size of symbols in use for any
+ * given application will be small, e.g. small enough that it is reasonable to
+ * cache all the distinct values. Symbols are encoded as ASCII characters.
+
+
+ * @return value if the current node is a Symbol, returns "" otherwise.
+ */
+_Data_['getSymbol'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes bytes = pn_data_get_symbol(data);
+
+    // Here's the quirky bit, pn_data_get_symbol actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_symbol.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_data_get_symbol(bytes, this._data);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a native JavaScript String from the pn_bytes_t information.
+    var string = Pointer_stringify(start, size);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return new Data['Symbol'](string);
+};
+
+
+// TODO copy, format and dump
+
+
+
+
+/**
+ * Serialise a Native JavaScript Object into an AMQP Map.
+ * @param object the Native JavaScript Object that we wish to serialise.
+ */
+_Data_['putDictionary'] = function(object) {
+    this['putMap']();
+    this['enter']();
+    for (var key in object) {
+        if (object.hasOwnProperty(key)) {
+            this['putObject'](key);
+            this['putObject'](object[key]);
+        }
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Map into a Native JavaScript Object.
+ * @return the deserialised Native JavaScript Object.
+ */
+_Data_['getDictionary'] = function() {
+    if (this['enter']()) {
+        var result = {};
+        while (this['next']()) {
+            var key = this['getObject']();
+            var value = null;
+            if (this['next']()) {
+                value = this['getObject']()
+            }
+            result[key] = value;
+        }
+        this['exit']();
+        return result;
+    }
+};
+
+
+/**
+ * Serialise a Native JavaScript Array into an AMQP List.
+ * @param array the Native JavaScript Array that we wish to serialise.
+ */
+_Data_['putJSArray'] = function(array) {
+    this['putList']();
+    this['enter']();
+    for (var i = 0, len = array.length; i < len; i++) {
+        this['putObject'](array[i])
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP List into a Native JavaScript Array.
+ * @return the deserialised Native JavaScript Array.
+ */
+_Data_['getJSArray'] = function() {
+    if (this['enter']()) {
+        var result = [];
+        while (this['next']()) {
+            result.push(this['getObject']());
+        }
+        this['exit']();
+        return result;
+    }
+};
+
+
+
+
+
+
+
+
+
+/**
+ * This method is the entry point for serialising native JavaScript types into
+ * AMQP types. In an ideal world there would be a nice clean one to one mapping
+ * and we could employ a look-up table but in practice the JavaScript type system
+ * doesn't really lend itself to that and we have to employ extra checks,
+ * heuristics and inferences.
+ * @param obj the JavaScript Object or primitive to be serialised.
+ */
+_Data_['putObject'] = function(obj) {
+console.log("Data.putObject");
+
+
+console.log("obj = " + obj);
+//console.log("typeof obj = " + (typeof obj));
+//console.log("obj prototype = " + Object.prototype.toString.call(obj));
+
+    if (obj == null) { // == Checks for null and undefined.
+console.log("obj is null");
+        this['putNull']();
+    } else if (Data.isString(obj)) {
+console.log("obj is String");
+
+        var quoted = obj.match(/(['"])[^'"]*\1/);
+        if (quoted) {
+            quoted = quoted[0].slice(1, -1);
+console.log("obj is quoted String " + quoted);
+            this['putString'](quoted);
+        } else {
+            // TODO check for stringified numbers.
+            this['putString'](obj);
+        }   
+    } else if (obj instanceof Data['UUID']) {
+        this['putUUID'](obj);
+    } else if (obj instanceof Data['Symbol']) {
+        this['putSymbol'](obj);
+    } else if (Data.isNumber(obj)) {
+        /**
+         * Encoding JavaScript numbers is surprisingly complex and has several
+         * gotchas. The code here tries to do what the author believes is the
+         * most intuitive encoding of the native JavaScript Number. It first
+         * tries to identify if the number is an integer or floating point type
+         * by checking if the number modulo 1 is zero (i.e. if it has a remainder
+         * then it's a floating point type, which is encoded here as a double).
+         * If the number is an integer type a test is made to check if it is a
+         * 32 bit Int value. N.B. JavaScript automagically coerces floating
+         * point numbers with a zero Fractional Part into an exact integer so
+         * numbers like 1.0, 100.0 etc. will be encoded as int or long here,
+         * which is unlikely to be what is wanted. There's no easy way around this
+         * the two main options are to add a very small fractional number or to
+         * represent the number in a String literal e.g. "1.0f", "1.0d", "1l"
+         */
+        if (obj % 1 === 0) {
+console.log(obj + " is Integer Type " + (obj|0));
+            if (obj === (obj|0)) { // the |0 coerces to a 32 bit value.
+                // 32 bit integer - encode as an Integer.
+console.log(obj + " is Int ");
+                this['putInteger'](obj);
+            } else { // Longer than 32 bit - encode as a Long.
+console.log(obj + " is Long");
+                this['putLong'](obj);
+            }
+        } else { // Floating point type - encode as a Double
+console.log(obj + " is Float Type");
+            this['putDouble'](obj);
+        }
+    } else if (Data.isBoolean(obj)) {
+        this['putBoolean'](obj);
+    } else if (Data.isArray(obj)) { // Native JavaScript Array
+        this['putJSArray'](obj);
+    } else {
+        this['putDictionary'](obj);
+    }
+};
+_Data_.putObject = _Data_['putObject'];
+
+
+// TODO
+_Data_['getObject'] = function(obj) {
+console.log("Data.getObject: not fully implemented yet");
+
+    var type = this.type();
+console.log("type = " + type);
+
+    var getter = Data.GetMappings[type];
+
+console.log("getter = " + getter);
+
+    return this[getter]();
+};
+_Data_.getObject = _Data_['getObject'];
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+Module['Inflate'] = function(size) {
+    var _public = {};
+    var stream = _inflateInitialise();
+    var inputBuffer  = Buffer(size);
+    var outputBuffer = Buffer(size);
+
+    // Public methods
+    _public['destroy'] = function() {
+        _inflateDestroy(stream);
+        inputBuffer.destroy();
+        outputBuffer.destroy();
+    };
+
+    _public['reset'] = function() {
+        _inflateReset(stream);
+    };
+
+    _public['inflate'] = function(ptr) {
+        ptr = ptr ? ptr : outputBuffer.getRaw();
+        var inflatedSize; // Pass by reference variable - need to use Module.setValue to initialise it.
+        setValue(inflatedSize, outputBuffer.size, 'i32');
+        var err = _zinflate(stream, ptr, inflatedSize, inputBuffer.getRaw(), inputBuffer.size);
+        inflatedSize = getValue(inflatedSize, 'i32'); // Dereference the real inflatedSize value;
+        outputBuffer.setSize(inflatedSize);
+        return ((err < 0) ? err : inflatedSize); // Return the inflated size, or error code if inflation fails.
+    };
+
+    // Export methods from the input and output buffers for use by client code.
+    _public['setInputBufferSize'] = inputBuffer.setSize;
+    _public['getRawInputBuffer'] = inputBuffer.getRaw;
+    _public['getInputBuffer'] = inputBuffer.getBuffer;
+
+    _public['setOutputBufferSize'] = outputBuffer.setSize;
+    _public['getRawOutBuffer'] = outputBuffer.getRaw;
+    _public['getOutputBuffer'] = outputBuffer.getBuffer;
+
+    return _public;
+};
+*/
+
+


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


[29/51] [abbrv] qpid-proton git commit: Fix generation of JavaScript documentation using jsdoc

Posted by rh...@apache.org.
Fix generation of JavaScript documentation using jsdoc

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1624847 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/f1fc2503
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/f1fc2503
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/f1fc2503

Branch: refs/heads/master
Commit: f1fc2503ca0365c52e90415c0891294fdf73be56
Parents: 530d9fd
Author: fadams <fa...@unknown>
Authored: Sun Sep 14 13:06:37 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sun Sep 14 13:06:37 2014 +0000

----------------------------------------------------------------------
 proton-c/bindings/javascript/CMakeLists.txt |  4 +++-
 proton-c/bindings/javascript/binding.js     | 23 +++++++++++------------
 2 files changed, 14 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f1fc2503/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index 02f9ccb..a92509a 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -254,7 +254,9 @@ add_custom_target(
 # If the docs target is specified and the jsdoc3 package for node.js has been
 # installed then build the JavaScript API documentation.
 if (NODE_JSDOC_FOUND)
-    message(STATUS "Documentation Enabled")
+    set(JSDOC_EXE ${PROJECT_SOURCE_DIR}/node_modules/.bin/jsdoc)
+
+    message(STATUS "Documentation Enabled. Using ${JSDOC_EXE} to build JavaScript docs")
     add_custom_target(docs-js COMMAND ${JSDOC_EXE}
                       -d ${CMAKE_CURRENT_BINARY_DIR}/html
                       ${CMAKE_CURRENT_SOURCE_DIR}/binding.js)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f1fc2503/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index 7e71b88..05e08a8 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -35,7 +35,7 @@
  * be publicly visible from this package/module. We will use the associative
  * array form for declaring exported properties to prevent the Closure compiler
  * from minifying e.g. <pre>Module['Messenger'] = ...</pre>
- * Exported Objects can be used in client code using the appropriate namespace:
+ * Exported Objects can be used in client code using a more convenient namespace, e.g.:
  * <pre>
  * proton = require('qpid-proton');
  * var messenger = new proton.Messenger();
@@ -110,7 +110,7 @@ Module['Error'] = {
  * Constructs a proton.MessengerError instance.
  * @classdesc This class is a subclass of Error.
  * @constructor proton.MessengerError
- * @param the error message.
+ * @param {string} message the error message.
  */
 Module['MessengerError'] = function(message) { // MessengerError constructor.
     this.name = "MessengerError";
@@ -135,7 +135,7 @@ Module['MessengerError'].prototype.toString = function() {
  * Constructs a proton.MessageError instance.
  * @classdesc This class is a subclass of Error.
  * @constructor proton.MessageError
- * @param the error message.
+ * @param {string} message the error message.
  */
 Module['MessageError'] = function(message) { // MessageError constructor.
     this.name = "MessageError";
@@ -160,7 +160,7 @@ Module['MessageError'].prototype.toString = function() {
  * Constructs a proton.DataError instance.
  * @classdesc This class is a subclass of Error.
  * @constructor proton.DataError
- * @param the error message.
+ * @param {string} message the error message.
  */
 Module['DataError'] = function(message) { // DataError constructor.
     this.name = "DataError";
@@ -962,17 +962,16 @@ _Messenger_['rewrite'] = function(pattern, address) {
 /*****************************************************************************/
 
 /**
- * EventDispatch is a Singleton class that allows callbacks to be registered that
+ * EventDispatch is a Singleton class that allows callbacks to be registered which
  * will get triggered by the emscripten WebSocket network callbacks. Clients of
  * Messenger will register callbacks by calling:
  * <pre>
- * messenger.on('work', <callback function>);
+ * messenger.on('work', &lt;callback function&gt;);
  * </pre>
- * EventDispatch supports callback registration from multiple Messenger instances
- * and supports multiple callbacks being registered for each instance. The client
- * callbacks will actually be called when a given messenger has work available
- * or a WebSocket close has been occurred (in which case all registered callbacks
- * will be called).
+ * EventDispatch supports callback registration from multiple Messenger instances.
+ * The client callbacks will actually be called when a given messenger has work
+ * available or a WebSocket close has been occurred (in which case all registered
+ * callbacks will be called).
  * <p>
  * The approach implemented here allows the registered callbacks to follow a
  * similar pattern to _process_incoming and _process_outgoing in async.py
@@ -1557,7 +1556,7 @@ _Message_['getUserID'] = function() {
  * even if a string or {@link proton.Data.Uuid} has been passed to setUserID.
  * @method setUserID
  * @memberof! proton.Message#
- * @param {(string||proton.Data.Uuid)} id the new user id for the message.
+ * @param {(string|proton.Data.Uuid)} id the new user id for the message.
  */
 _Message_['setUserID'] = function(id) {
     // If the id parameter is a proton.Data.Binary use it otherwise create a Binary


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


[11/51] [abbrv] qpid-proton git commit: Implemented the remainder of the codec methods and ported the codec unit test suite to test it all

Posted by rh...@apache.org.
Implemented the remainder of the codec methods and ported the codec unit test suite to test it all

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1595519 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/6aed8542
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/6aed8542
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/6aed8542

Branch: refs/heads/master
Commit: 6aed854292de5e0a528b6c445dc21549e0fa3bc2
Parents: 80c9952
Author: fadams <fa...@unknown>
Authored: Sat May 17 17:24:16 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sat May 17 17:24:16 2014 +0000

----------------------------------------------------------------------
 examples/messenger/javascript/spout.js      |   38 +-
 proton-c/bindings/javascript/CMakeLists.txt |    2 +-
 proton-c/bindings/javascript/binding.js     | 1370 ++++++++++++++++------
 proton-c/bindings/javascript/data-test.js   |   77 --
 tests/javascript/codec.js                   |  544 +++++++++
 tests/javascript/unittest.js                |   45 +
 6 files changed, 1607 insertions(+), 469 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/examples/messenger/javascript/spout.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/spout.js b/examples/messenger/javascript/spout.js
index 071eb72..cfb9351 100644
--- a/examples/messenger/javascript/spout.js
+++ b/examples/messenger/javascript/spout.js
@@ -59,7 +59,6 @@ console.log("exiting");
         }
     };
 
-
     messenger.setOutgoingWindow(1024);
 
     messenger.setNetworkCallback(_process);
@@ -67,10 +66,27 @@ console.log("exiting");
 
     message.setAddress(address);
     message.setSubject(subject);
+
     //message.body = msgtext;
-    //message.body = new proton.Data.UUID();
+    //message.body = new proton.Data.Uuid();
     //message.body = new proton.Data.Symbol("My Symbol");
     //message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
+    //message.body = new proton.Data.Described("persian", "feline mammals");
+
+    //message.body = new Date();
+
+    //message.body = new proton.Data.Array('INT', [1, 3, 5, 7], "odd numbers");
+
+    //message.body = new proton.Data.Array('UINT', [1, 3, 5, 7], "odd");
+    //message.body = new proton.Data.Array('ULONG', [1, 3, 5, 7], "odd");
+    //message.body = new proton.Data.Array('FLOAT', [1, 3, 5, 7], "odd");
+    //message.body = new proton.Data.Array('STRING', ["1", "3", "5", "7"], "odd");
+
+    //message.body = new Uint8Array([1, 3, 5, 7]);
+
+    //message.body = new proton.Data.Array('UINT', new Uint8Array([1, 3, 5, 7]), "odd");
+
+    //message.body = new proton.Data.Array('UUID', [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()], "unique");
 
     /*message.body = new proton.Data.Binary(4);
     var buffer = message.body.getBuffer();
@@ -78,24 +94,28 @@ console.log("exiting");
     buffer[1] = 77;
     buffer[2] = 81;
     buffer[3] = 80;*/
+    message.body = new proton.Data.Binary([65, 77, 81, 80]);
 
-
+    //message.body = null;
     //message.body = true;
+    //message.body = 66..char();
     //message.body = "   \"127.0\"  ";
 
     //message.body = 2147483647; // int
     //message.body = -2147483649; // long
     //message.body = 12147483649; // long
+    //message.body = (12147483649).long(); // long
+    //message.body = (-12147483649).ulong(); // long
+    //message.body = (17223372036854778000).ulong(); // ulong
 
-
-    message.body = (121474.836490).asFloat(); // float TODO check me
-    //message.body = 12147483649.0.asFloat(); // float TODO check me
-    //message.body = (4294967296).asUnsignedInteger();
-    //message.body = (255).asUnsignedByte();
-
+    //message.body = (121474.836490).float(); // float TODO check me
+    //message.body = 12147483649.0.float(); // float TODO check me
+    //message.body = (4294967296).uint();
+    //message.body = (255).ubyte();
 
     //message.body = ['Rod', 'Jane', 'Freddy'];
     //message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
+    //message.body = {cat: true, donkey: 'hee haw'};
 
     tracker = messenger.put(message);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index e043adb..ef6d384 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -222,7 +222,7 @@ set_target_properties(
   # This build is optimised and minified
   #LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --pre-js
 
-  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_r
 ecv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array'
 , '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '
 _pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_r
 ecv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array'
 , '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_dec
 imal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
   )
 
 # This command packages up the compiled proton.js into a node.js package called


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


[05/51] [abbrv] qpid-proton git commit: Pulling in changes from proton r1590241

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
index df0afc4..1ca8b52 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
@@ -119,5 +119,4 @@ public class SenderImpl  extends LinkImpl implements Sender
             advance();
         }*/
     }
-
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
index 427ffeb..f95df27 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
@@ -24,6 +24,7 @@ import java.util.*;
 import org.apache.qpid.proton.engine.EndpointState;
 import org.apache.qpid.proton.engine.ProtonJSession;
 import org.apache.qpid.proton.engine.Session;
+import org.apache.qpid.proton.engine.Event;
 
 public class SessionImpl extends EndpointImpl implements ProtonJSession
 {
@@ -182,4 +183,12 @@ public class SessionImpl extends EndpointImpl implements ProtonJSession
         _outgoingDeliveries += delta;
     }
 
+    @Override
+    protected void localStateChanged()
+    {
+        EventImpl ev = getConnectionImpl().put(Event.Type.SESSION_LOCAL_STATE);
+        if (ev != null) {
+            ev.init(this);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
index 5e2c81e..1949652 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
@@ -76,8 +76,8 @@ public class TransportImpl extends EndpointImpl
     private boolean _isCloseSent;
 
     private boolean _headerWritten;
-    private TransportSession[] _remoteSessions;
-    private TransportSession[] _localSessions;
+    private Map<Integer, TransportSession> _remoteSessions = new HashMap<Integer, TransportSession>();
+    private Map<Integer, TransportSession> _localSessions = new HashMap<Integer, TransportSession>();
 
     private TransportInput _inputProcessor;
     private TransportOutput _outputProcessor;
@@ -198,10 +198,6 @@ public class TransportImpl extends EndpointImpl
         ((ConnectionImpl) conn).setTransport(this);
         _connectionEndpoint = (ConnectionImpl) conn;
 
-        _localSessions = new TransportSession[_connectionEndpoint.getMaxChannels()+1];
-        _remoteSessions = new TransportSession[_connectionEndpoint.getMaxChannels()+1];
-
-
         if(getRemoteState() != EndpointState.UNINITIALIZED)
         {
             _connectionEndpoint.handleOpen(_open);
@@ -802,22 +798,23 @@ public class TransportImpl extends EndpointImpl
 
     private int allocateLocalChannel(TransportSession transportSession)
     {
-        for( int i=0; i < _localSessions.length; i++)
+        for (int i = 0; i < _connectionEndpoint.getMaxChannels(); i++)
         {
-            if( _localSessions[i] == null )
+            if (!_localSessions.containsKey(i))
             {
-                _localSessions[i] = transportSession;
+                _localSessions.put(i, transportSession);
                 transportSession.setLocalChannel(i);
                 return i;
             }
         }
+
         return -1;
     }
 
     private int freeLocalChannel(TransportSession transportSession)
     {
         final int channel = transportSession.getLocalChannel();
-        _localSessions[channel] = null;
+        _localSessions.remove(channel);
         transportSession.freeLocalChannel();
         return channel;
     }
@@ -953,7 +950,7 @@ public class TransportImpl extends EndpointImpl
     public void handleBegin(Begin begin, Binary payload, Integer channel)
     {
         // TODO - check channel < max_channel
-        TransportSession transportSession = _remoteSessions[channel];
+        TransportSession transportSession = _remoteSessions.get(channel);
         if(transportSession != null)
         {
             // TODO - fail due to begin on begun session
@@ -969,16 +966,16 @@ public class TransportImpl extends EndpointImpl
             else
             {
                 // TODO check null
-                transportSession = _localSessions[begin.getRemoteChannel().intValue()];
+                transportSession = _localSessions.get(begin.getRemoteChannel().intValue());
                 session = transportSession.getSession();
 
             }
             transportSession.setRemoteChannel(channel);
             session.setRemoteState(EndpointState.ACTIVE);
             transportSession.setNextIncomingId(begin.getNextOutgoingId());
-            _remoteSessions[channel] = transportSession;
+            _remoteSessions.put(channel, transportSession);
 
-            EventImpl ev = _connectionEndpoint.put(Event.Type.SESSION_STATE);
+            EventImpl ev = _connectionEndpoint.put(Event.Type.SESSION_REMOTE_STATE);
             if (ev != null) {
                 ev.init(session);
             }
@@ -989,7 +986,7 @@ public class TransportImpl extends EndpointImpl
     @Override
     public void handleAttach(Attach attach, Binary payload, Integer channel)
     {
-        TransportSession transportSession = _remoteSessions[channel];
+        TransportSession transportSession = _remoteSessions.get(channel);
         if(transportSession == null)
         {
             // TODO - fail due to attach on non-begun session
@@ -1037,7 +1034,7 @@ public class TransportImpl extends EndpointImpl
 
             }
 
-            EventImpl ev = _connectionEndpoint.put(Event.Type.LINK_STATE);
+            EventImpl ev = _connectionEndpoint.put(Event.Type.LINK_REMOTE_STATE);
             if (ev != null) {
                 ev.init(link);
             }
@@ -1047,7 +1044,7 @@ public class TransportImpl extends EndpointImpl
     @Override
     public void handleFlow(Flow flow, Binary payload, Integer channel)
     {
-        TransportSession transportSession = _remoteSessions[channel];
+        TransportSession transportSession = _remoteSessions.get(channel);
         if(transportSession == null)
         {
             // TODO - fail due to attach on non-begun session
@@ -1063,7 +1060,7 @@ public class TransportImpl extends EndpointImpl
     public void handleTransfer(Transfer transfer, Binary payload, Integer channel)
     {
         // TODO - check channel < max_channel
-        TransportSession transportSession = _remoteSessions[channel];
+        TransportSession transportSession = _remoteSessions.get(channel);
         if(transportSession != null)
         {
             transportSession.handleTransfer(transfer, payload);
@@ -1077,7 +1074,7 @@ public class TransportImpl extends EndpointImpl
     @Override
     public void handleDisposition(Disposition disposition, Binary payload, Integer channel)
     {
-        TransportSession transportSession = _remoteSessions[channel];
+        TransportSession transportSession = _remoteSessions.get(channel);
         if(transportSession == null)
         {
             // TODO - fail due to attach on non-begun session
@@ -1091,7 +1088,7 @@ public class TransportImpl extends EndpointImpl
     @Override
     public void handleDetach(Detach detach, Binary payload, Integer channel)
     {
-        TransportSession transportSession = _remoteSessions[channel];
+        TransportSession transportSession = _remoteSessions.get(channel);
         if(transportSession == null)
         {
             // TODO - fail due to attach on non-begun session
@@ -1111,7 +1108,7 @@ public class TransportImpl extends EndpointImpl
                     link.getRemoteCondition().copyFrom(detach.getError());
                 }
 
-                EventImpl ev = _connectionEndpoint.put(Event.Type.LINK_STATE);
+                EventImpl ev = _connectionEndpoint.put(Event.Type.LINK_REMOTE_STATE);
                 if (ev != null) {
                     ev.init(link);
                 }
@@ -1126,14 +1123,14 @@ public class TransportImpl extends EndpointImpl
     @Override
     public void handleEnd(End end, Binary payload, Integer channel)
     {
-        TransportSession transportSession = _remoteSessions[channel];
+        TransportSession transportSession = _remoteSessions.get(channel);
         if(transportSession == null)
         {
             // TODO - fail due to attach on non-begun session
         }
         else
         {
-            _remoteSessions[channel] = null;
+            _remoteSessions.remove(channel);
             transportSession.receivedEnd();
             SessionImpl session = transportSession.getSession();
             session.setRemoteState(EndpointState.CLOSED);
@@ -1143,7 +1140,7 @@ public class TransportImpl extends EndpointImpl
                 session.getRemoteCondition().copyFrom(errorCondition);
             }
 
-            EventImpl ev = _connectionEndpoint.put(Event.Type.SESSION_STATE);
+            EventImpl ev = _connectionEndpoint.put(Event.Type.SESSION_REMOTE_STATE);
             if (ev != null) {
                 ev.init(session);
             }
@@ -1163,7 +1160,7 @@ public class TransportImpl extends EndpointImpl
                 _connectionEndpoint.getRemoteCondition().copyFrom(close.getError());
             }
 
-            EventImpl ev = _connectionEndpoint.put(Event.Type.CONNECTION_STATE);
+            EventImpl ev = _connectionEndpoint.put(Event.Type.CONNECTION_REMOTE_STATE);
             if (ev != null) {
                 ev.init(_connectionEndpoint);
             }
@@ -1368,4 +1365,8 @@ public class TransportImpl extends EndpointImpl
         }
     }
 
+    @Override
+    protected void localStateChanged()
+    {
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
index 560c137..272756d 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
@@ -44,6 +44,20 @@ public class MessageImpl implements ProtonJMessage
     private Section _body;
     private Footer _footer;
     private MessageFormat _format = MessageFormat.DATA;
+    
+    private static class EncoderDecoderPair {
+      DecoderImpl decoder = new DecoderImpl();
+      EncoderImpl encoder = new EncoderImpl(decoder);
+      {
+          AMQPDefinedTypes.registerAllTypes(decoder, encoder);
+      }
+    }
+
+    private static final ThreadLocal<EncoderDecoderPair> tlsCodec = new ThreadLocal<EncoderDecoderPair>() {
+          @Override protected EncoderDecoderPair initialValue() {
+            return new EncoderDecoderPair();
+          }
+      };
 
     /**
      * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
@@ -559,10 +573,7 @@ public class MessageImpl implements ProtonJMessage
     @Override
     public int decode(byte[] data, int offset, int length)
     {
-        DecoderImpl decoder = new DecoderImpl();
-        EncoderImpl encoder = new EncoderImpl(decoder);
-
-        AMQPDefinedTypes.registerAllTypes(decoder, encoder);
+        DecoderImpl decoder = tlsCodec.get().decoder;
         final ByteBuffer buffer = ByteBuffer.wrap(data, offset, length);
         decoder.setByteBuffer(buffer);
 
@@ -668,6 +679,8 @@ public class MessageImpl implements ProtonJMessage
 
         }
 
+        decoder.setByteBuffer(null);
+        
         return length-buffer.remaining();
 
     }
@@ -695,9 +708,7 @@ public class MessageImpl implements ProtonJMessage
     public int encode(WritableBuffer buffer)
     {
         int length = buffer.remaining();
-        DecoderImpl decoder = new DecoderImpl();
-        EncoderImpl encoder = new EncoderImpl(decoder);
-        AMQPDefinedTypes.registerAllTypes(decoder, encoder);
+        EncoderImpl encoder = tlsCodec.get().encoder;
         encoder.setByteBuffer(buffer);
 
         if(getHeader() != null)
@@ -728,6 +739,7 @@ public class MessageImpl implements ProtonJMessage
         {
             encoder.writeObject(getFooter());
         }
+        encoder.setByteBuffer((WritableBuffer)null);
 
         return length - buffer.remaining();
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
index be94189..ff9fbbe 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
@@ -87,12 +87,24 @@ class Address
             hp = uphp;
         }
 
-        int colon = hp.indexOf(':');
-        if (colon >= 0) {
-            _host = hp.substring(0, colon);
-            _port = hp.substring(colon + 1);
-        } else {
-            _host = hp;
+        if (hp.startsWith("[")) {
+            int close = hp.indexOf(']');
+            if (close >= 0) {
+                _host = hp.substring(1, close);
+                if (hp.substring(close + 1).startsWith(":")) {
+                    _port = hp.substring(close + 2);
+                }
+            }
+        }
+
+        if (_host == null) {
+            int colon = hp.indexOf(':');
+            if (colon >= 0) {
+                _host = hp.substring(0, colon);
+                _port = hp.substring(colon + 1);
+            } else {
+                _host = hp;
+            }
         }
 
         if (_host.startsWith("~")) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/resources/cengine.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/cengine.py b/proton-j/src/main/resources/cengine.py
index c61da07..320f539 100644
--- a/proton-j/src/main/resources/cengine.py
+++ b/proton-j/src/main/resources/cengine.py
@@ -938,9 +938,14 @@ def pn_transport_error(trans):
 
 from org.apache.qpid.proton.engine import Event
 
-PN_CONNECTION_STATE = Event.Type.CONNECTION_STATE
-PN_SESSION_STATE = Event.Type.SESSION_STATE
-PN_LINK_STATE = Event.Type.LINK_STATE
+PN_EVENT_CATEGORY_PROTOCOL = Event.Category.PROTOCOL
+
+PN_CONNECTION_LOCAL_STATE = Event.Type.CONNECTION_LOCAL_STATE
+PN_CONNECTION_REMOTE_STATE = Event.Type.CONNECTION_REMOTE_STATE
+PN_SESSION_LOCAL_STATE = Event.Type.SESSION_LOCAL_STATE
+PN_SESSION_REMOTE_STATE = Event.Type.SESSION_REMOTE_STATE
+PN_LINK_LOCAL_STATE = Event.Type.LINK_LOCAL_STATE
+PN_LINK_REMOTE_STATE = Event.Type.LINK_REMOTE_STATE
 PN_LINK_FLOW = Event.Type.LINK_FLOW
 PN_DELIVERY = Event.Type.DELIVERY
 PN_TRANSPORT = Event.Type.TRANSPORT
@@ -957,6 +962,9 @@ def pn_collector_peek(coll):
 def pn_collector_pop(coll):
   coll.pop()
 
+def pn_collector_free(coll):
+  pass
+
 def pn_event_connection(event):
   return wrap(event.getConnection(), pn_connection_wrapper)
 
@@ -972,8 +980,14 @@ def pn_event_delivery(event):
 def pn_event_transport(event):
   return wrap(event.getTransport(), pn_transport_wrapper)
 
+def pn_event_class(event):
+  return event.getClass()
+
 def pn_event_type(event):
   return event.getType()
 
 def pn_event_type_name(etype):
   return str(etype)
+
+def pn_event_category(event):
+  return event.getCategory()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java b/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
index 3efc683..c0d2d92 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
@@ -24,7 +24,20 @@ public class AddressTest {
 		testParse("user@host", null, "user", null, "host", null, null);
 		testParse("user:1243^&^:pw@host:423", null, "user", "1243^&^:pw", "host", "423", null);
 		testParse("user:1243^&^:pw@host:423/Foo.bar:90087", null, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087");
-		testParse("user:1243^&^:pw@host:423/Foo.bar:90087@somewhere", null, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087@somewhere");
+        testParse("user:1243^&^:pw@host:423/Foo.bar:90087@somewhere", null, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087@somewhere");
+        testParse("[::1]", null, null, null, "::1", null, null);
+        testParse("[::1]:amqp", null, null, null, "::1", "amqp", null);
+        testParse("user@[::1]", null, "user", null, "::1", null, null);
+        testParse("user@[::1]:amqp", null, "user", null, "::1", "amqp", null);
+        testParse("user:1243^&^:pw@[::1]:amqp", null, "user", "1243^&^:pw", "::1", "amqp", null);
+        testParse("user:1243^&^:pw@[::1]:amqp/Foo.bar:90087", null, "user", "1243^&^:pw", "::1", "amqp", "Foo.bar:90087");
+        testParse("user:1243^&^:pw@[::1:amqp/Foo.bar:90087", null, "user", "1243^&^:pw", "[", ":1:amqp", "Foo.bar:90087");
+        testParse("user:1243^&^:pw@::1]:amqp/Foo.bar:90087", null, "user", "1243^&^:pw", "", ":1]:amqp", "Foo.bar:90087");
+        testParse("amqp://user@[::1]", "amqp", "user", null, "::1", null, null);
+        testParse("amqp://user@[::1]:amqp", "amqp", "user", null, "::1", "amqp", null);
+        testParse("amqp://user@[1234:52:0:1260:f2de:f1ff:fe59:8f87]:amqp", "amqp", "user", null, "1234:52:0:1260:f2de:f1ff:fe59:8f87", "amqp", null);
+        testParse("amqp://user:1243^&^:pw@[::1]:amqp", "amqp", "user", "1243^&^:pw", "::1", "amqp", null);
+        testParse("amqp://user:1243^&^:pw@[::1]:amqp/Foo.bar:90087", "amqp", "user", "1243^&^:pw", "::1", "amqp", "Foo.bar:90087");
 		testParse("amqp://host", "amqp", null, null, "host", null, null);
 		testParse("amqp://user@host", "amqp", "user", null, "host", null, null);
 		testParse("amqp://user@host/path:%", "amqp", "user", null, "host", null, "path:%");

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/tests/python/proton_tests/common.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/common.py b/tests/python/proton_tests/common.py
index 82781fb..d597c2f 100644
--- a/tests/python/proton_tests/common.py
+++ b/tests/python/proton_tests/common.py
@@ -333,6 +333,7 @@ class MessengerApp(object):
         self.certificate = None
         self.privatekey = None
         self.password = None
+        self._output = None
 
     def start(self, verbose=False):
         """ Begin executing the test """
@@ -363,8 +364,15 @@ class MessengerApp(object):
 
     def stdout(self):
         #self._process.communicate()[0]
+        if not self._output or not self._output[0]:
+            return "*** NO STDOUT ***"
         return self._output[0]
 
+    def stderr(self):
+        if not self._output or not self._output[1]:
+            return "*** NO STDERR ***"
+        return self._output[1]
+
     def cmdline(self):
         if not self._cmdline:
             self._build_command()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/tests/python/proton_tests/engine.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/engine.py b/tests/python/proton_tests/engine.py
index 1797b14..243e5bc 100644
--- a/tests/python/proton_tests/engine.py
+++ b/tests/python/proton_tests/engine.py
@@ -2102,7 +2102,7 @@ class EventTest(Test):
     self.expect(coll)
     c2.open()
     self.pump()
-    self.expect(coll, Event.CONNECTION_STATE)
+    self.expect(coll, Event.CONNECTION_REMOTE_STATE)
     self.pump()
     self.expect(coll)
 
@@ -2113,7 +2113,21 @@ class EventTest(Test):
 
     self.expect(coll)
     self.pump()
-    self.expect(coll, Event.SESSION_STATE, Event.LINK_STATE)
+    self.expect(coll, Event.SESSION_REMOTE_STATE, Event.LINK_REMOTE_STATE)
+
+    c1.open()
+    ssn2 = c1.session()
+    ssn2.open()
+    rcv = ssn2.receiver("receiver")
+    rcv.open()
+    self.pump()
+    self.expect(coll,
+                Event.CONNECTION_LOCAL_STATE,
+                Event.TRANSPORT,
+                Event.SESSION_LOCAL_STATE,
+                Event.TRANSPORT,
+                Event.LINK_LOCAL_STATE,
+                Event.TRANSPORT)
 
   def testFlowEvents(self):
     snd, rcv = self.link("test-link")
@@ -2122,7 +2136,7 @@ class EventTest(Test):
     rcv.open()
     rcv.flow(10)
     self.pump()
-    self.expect(coll, Event.LINK_STATE, Event.LINK_FLOW)
+    self.expect(coll, Event.LINK_REMOTE_STATE, Event.LINK_FLOW)
     rcv.flow(10)
     self.pump()
     self.expect(coll, Event.LINK_FLOW)
@@ -2135,7 +2149,7 @@ class EventTest(Test):
     rcv.open()
     rcv.flow(10)
     self.pump()
-    self.expect(coll, Event.TRANSPORT, Event.TRANSPORT)
+    self.expect(coll, Event.LINK_LOCAL_STATE, Event.TRANSPORT, Event.TRANSPORT)
     snd.delivery("delivery")
     snd.send("Hello World!")
     snd.advance()
@@ -2143,7 +2157,7 @@ class EventTest(Test):
     self.expect(coll)
     snd.open()
     self.pump()
-    self.expect(coll, Event.LINK_STATE, Event.DELIVERY)
+    self.expect(coll, Event.LINK_REMOTE_STATE, Event.DELIVERY)
 
   def testDeliveryEventsDisp(self):
     snd, rcv, coll = self.testFlowEvents()
@@ -2151,7 +2165,11 @@ class EventTest(Test):
     dlv = snd.delivery("delivery")
     snd.send("Hello World!")
     assert snd.advance()
-    self.expect(coll, Event.TRANSPORT, Event.TRANSPORT, Event.TRANSPORT)
+    self.expect(coll,
+                Event.LINK_LOCAL_STATE,
+                Event.TRANSPORT,
+                Event.TRANSPORT,
+                Event.TRANSPORT)
     self.pump()
     self.expect(coll)
     rdlv = rcv.current

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/tests/python/proton_tests/soak.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/soak.py b/tests/python/proton_tests/soak.py
index f6a62da..94ce488 100644
--- a/tests/python/proton_tests/soak.py
+++ b/tests/python/proton_tests/soak.py
@@ -44,31 +44,31 @@ class AppTests(Test):
 
     @property
     def iterations(self):
-        return int(self.default("iterations", 2, fast=1, valgrind=1))
+        return int(self.default("iterations", 2, fast=1, valgrind=2))
 
     @property
     def send_count(self):
-        return int(self.default("send_count", 17, fast=1, valgrind=1))
+        return int(self.default("send_count", 17, fast=1, valgrind=2))
 
     @property
     def target_count(self):
-        return int(self.default("target_count", 5, fast=1, valgrind=1))
+        return int(self.default("target_count", 5, fast=1, valgrind=2))
 
     @property
     def send_batch(self):
-        return int(self.default("send_batch", 7, fast=1, valgrind=1))
+        return int(self.default("send_batch", 7, fast=1, valgrind=2))
 
     @property
     def forward_count(self):
-        return int(self.default("forward_count", 5, fast=1, valgrind=1))
+        return int(self.default("forward_count", 5, fast=1, valgrind=2))
 
     @property
     def port_count(self):
-        return int(self.default("port_count", 3, fast=1, valgrind=1))
+        return int(self.default("port_count", 3, fast=1, valgrind=2))
 
     @property
     def sender_count(self):
-        return int(self.default("sender_count", 3, fast=1, valgrind=1))
+        return int(self.default("sender_count", 3, fast=1, valgrind=2))
 
     def valgrind_test(self):
         self.is_valgrind = True
@@ -94,13 +94,21 @@ class AppTests(Test):
                 S.wait()
                 #print("SENDER OUTPUT:")
                 #print( S.stdout() )
-                assert S.status() == 0, "Command '%s' failed" % str(S.cmdline())
+                assert S.status() == 0, ("Command '%s' failed status=%d: '%s' '%s'"
+                                         % (str(S.cmdline()),
+                                            S.status(),
+                                            S.stdout(),
+                                            S.stderr()))
 
         for R in self.receivers:
             R.wait()
             #print("RECEIVER OUTPUT")
             #print( R.stdout() )
-            assert R.status() == 0, "Command '%s' failed" % str(R.cmdline())
+            assert R.status() == 0, ("Command '%s' failed status=%d: '%s' '%s'"
+                                     % (str(R.cmdline()),
+                                        R.status(),
+                                        R.stdout(),
+                                        R.stderr()))
 
 #
 # Traffic passing tests based on the Messenger apps

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/tests/python/proton_tests/ssl.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl.py b/tests/python/proton_tests/ssl.py
index db19e6f..ed2e25d 100644
--- a/tests/python/proton_tests/ssl.py
+++ b/tests/python/proton_tests/ssl.py
@@ -18,7 +18,10 @@
 #
 
 import os, common
+import random
+import string
 import subprocess
+
 from proton import *
 from common import Skipped, pump
 
@@ -877,7 +880,9 @@ class MessengerSSLTests(common.Test):
 
         msg = Message()
         msg.address = "amqps://127.0.0.1:12345"
-        msg.body = "Hello World!"
+        # make sure a large, uncompressible message body works!
+        msg.body = "".join(random.choice(string.ascii_letters)
+                           for x in range(10099))
         trk = self.client.put(msg)
         self.client.send()
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/tools/cmake/Modules/FindJava.cmake
----------------------------------------------------------------------
diff --git a/tools/cmake/Modules/FindJava.cmake b/tools/cmake/Modules/FindJava.cmake
index dae56bc..1664fe1 100644
--- a/tools/cmake/Modules/FindJava.cmake
+++ b/tools/cmake/Modules/FindJava.cmake
@@ -107,7 +107,7 @@ if(Java_JAVA_EXECUTABLE)
       # 2. OpenJDK 1.6
       # 3. GCJ 1.5
       # 4. Kaffe 1.4.2
-      if(var MATCHES "java version \"[0-9]+\\.[0-9]+\\.[0-9_.]+.*\".*")
+      if(var MATCHES "(java|openjdk) version \"[0-9]+\\.[0-9]+\\.[0-9_.]+.*\".*")
         # This is most likely Sun / OpenJDK, or maybe GCJ-java compat layer
         string( REGEX REPLACE ".* version \"([0-9]+\\.[0-9]+\\.[0-9_.]+.*)\".*"
                 "\\1" Java_VERSION_STRING "${var}" )


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


[47/51] [abbrv] qpid-proton git commit: Improve error handling a bit, still something of a work in progress

Posted by rh...@apache.org.
Improve error handling a bit, still something of a work in progress

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1628232 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/0d44f572
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/0d44f572
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/0d44f572

Branch: refs/heads/master
Commit: 0d44f57218ac58e4f1cf503e92fe60abc3e16920
Parents: 92b8098
Author: fadams <fa...@unknown>
Authored: Mon Sep 29 17:40:38 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Mon Sep 29 17:40:38 2014 +0000

----------------------------------------------------------------------
 examples/messenger/javascript/send.html   | 19 ++++---
 proton-c/bindings/javascript/messenger.js | 70 +++++++-------------------
 proton-c/bindings/javascript/module.js    | 55 ++++++++++++++++++--
 proton-c/include/proton/io.h              | 46 +++++++++++++++++
 proton-c/src/windows/iocp.c               | 11 +++-
 proton-c/src/windows/schannel.c           | 13 +++--
 tests/python/proton_tests/common.py       |  2 +-
 tests/python/proton_tests/messenger.py    |  5 ++
 8 files changed, 149 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d44f572/examples/messenger/javascript/send.html
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html
index f9aae90..f38a78e 100644
--- a/examples/messenger/javascript/send.html
+++ b/examples/messenger/javascript/send.html
@@ -65,17 +65,20 @@ console.log("body = " + body);
     messenger.put(message);
 };
 
-messenger.on('error', function(error) {
+var errorHandler = function(error) {
     console.log("Received error " + error);
 
-// Error recovery seems to require a new Messenger instance.
-messenger.stop();
-messenger.free();
-messenger = new proton.Messenger();
-messenger.start();
-console.log("Restarted");
-});
+    // Error recovery seems to require a new Messenger instance.
+    messenger.stop();
+    messenger.free();
+    messenger = new proton.Messenger();
+
+    messenger.on('error', errorHandler);
+    messenger.start();
+    console.log("Restarted");
+};
 
+messenger.on('error', errorHandler);
 messenger.start();
 
 </script>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d44f572/proton-c/bindings/javascript/messenger.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/messenger.js b/proton-c/bindings/javascript/messenger.js
index 69267ff..80eec5b 100644
--- a/proton-c/bindings/javascript/messenger.js
+++ b/proton-c/bindings/javascript/messenger.js
@@ -127,34 +127,6 @@ Module['Messenger'] = function(name) { // Messenger Constructor.
 
     // This call ensures that the emscripten network callback functions are initialised.
     Module.EventDispatch.registerMessenger(this);
-
-
-    // TODO improve error handling mechanism.
-    /*
-     * The emscripten websocket error event could get triggered by any Messenger
-     * and it's hard to determine which one without knowing which file descriptors
-     * are associated with which instance. As a workaround we set the _checkErrors
-     * flag when we call put or subscribe and reset it when work succeeds.
-     */
-    this._checkErrors = false;
-
-    /**
-     * TODO update to handle multiple Messenger instances
-     * Handle the emscripten websocket error and use it to trigger a MessengerError
-     * Note that the emscripten websocket error passes an array containing the
-     * file descriptor, the errno and the message, we just use the message here.
-     */
-    var that = this;
-    Module['websocket']['on']('error', function(error) {
-
-console.log("Module['websocket']['on'] caller is " + arguments.callee.caller.toString());
-
-console.log("that._checkErrors = " + that._checkErrors);
-console.log("error = " + error);
-        if (that._checkErrors) {
-            that._emit('error', new Module['MessengerError'](error[2]));
-        }
-    });
 };
 
 Module['Messenger'].PN_CUMULATIVE = 0x1; // Protected Class attribute.
@@ -176,22 +148,21 @@ var _Messenger_ = Module['Messenger'].prototype;
  * @param {number} code the error code to check.
  */
 _Messenger_._check = function(code) {
-    if (code < 0) {
-        if (code === Module['Error']['INPROGRESS']) {
-            return code;
-        }
-
+    if (code < 0 && code !== Module['Error']['INPROGRESS']) {
         var errno = this['getErrno']();
         var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
-
-        if (this._callbacks['error']) {
-            this._emit('error', new Module['MessengerError'](message));
-        } else {
-            throw new Module['MessengerError'](message);
+        if (message !== 'PN_TIMEOUT') {
+            if (this._callbacks['error']) {
+console.log("emitting " + message);
+                this._emit('error', new Module['MessengerError'](message));
+            } else {
+console.log("throwing " + message);
+                throw new Module['MessengerError'](message);
+            }
         }
-    } else {
-        return code;
     }
+
+    return code;
 };
 
 /**
@@ -486,9 +457,10 @@ _Messenger_['subscribe'] = function(source) {
         this._check(Module['Error']['ARG_ERR']);
     }
     var sp = Runtime.stackSave();
-    this._checkErrors = true; // TODO improve error handling mechanism.
+    Module.EventDispatch.setCurrentMessenger(this);
     var subscription = _pn_messenger_subscribe(this._messenger,
                                                allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
+    Module.EventDispatch.setCurrentMessenger(null);
     Runtime.stackRestore(sp);
 
     if (!subscription) {
@@ -532,12 +504,13 @@ _Messenger_['subscribe'] = function(source) {
 _Messenger_['put'] = function(message, flush) {
     flush = flush === false ? false : true; // Defaults to true if not explicitly specified.
     message._preEncode();
-    this._checkErrors = true; // TODO improve error handling mechanism.
+    Module.EventDispatch.setCurrentMessenger(this);
     this._check(_pn_messenger_put(this._messenger, message._message));
+    Module.EventDispatch.setCurrentMessenger(null);
 
     // If flush is set invoke pn_messenger_work.
     if (flush) {
-        _pn_messenger_work(this._messenger, 0);
+        this._check(_pn_messenger_work(this._messenger, 0));
     }
 
     // Getting the tracker is a little tricky as it is a 64 bit number. The way
@@ -617,16 +590,7 @@ _Messenger_['settle'] = function(tracker) {
  * @returns {boolean} true if there is work still to do, false otherwise.
  */
 _Messenger_['work'] = function() {
-    var err = _pn_messenger_work(this._messenger, 0);
-    if (err === Module['Error']['TIMEOUT']) {
-console.log("work = false");
-        return false;
-    } else {
-        this._checkErrors = false; // TODO improve error handling mechanism.
-        this._check(err);
-console.log("work = true");
-        return true;
-    }
+    return (this._check(_pn_messenger_work(this._messenger, 0)) > 0);
 };
 
 /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d44f572/proton-c/bindings/javascript/module.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/module.js b/proton-c/bindings/javascript/module.js
index e0e8373..aefceca 100644
--- a/proton-c/bindings/javascript/module.js
+++ b/proton-c/bindings/javascript/module.js
@@ -119,8 +119,17 @@ if (typeof process === 'object' && typeof require === 'function') {
  */
 Module.EventDispatch = new function() { // Note the use of new to create a Singleton.
     var _firstCall = true; // Flag used to check the first time registerMessenger is called.
+    /**
+     * We employ a cheat/hack to map file descriptors to the Messenger instance
+     * that owns them. In put/subscribe we set the current Messenger and then we
+     * intercept the library socket call with our own, which makes a call to
+     * the real library socket but also maps the file descriptor to _currentMessenger.
+     */
+    var _currentMessenger = null;
     var _messengers = {};
 
+    var _fd2Messenger = {};
+
     /**
      * Provides functionality roughly equivalent to the following C code:
      * while (1) {
@@ -135,21 +144,30 @@ Module.EventDispatch = new function() { // Note the use of new to create a Singl
      * we bypass the _pn_messenger_work test as it will never succeed after closing.
      */
     var _pump = function(fd, closing) {
+//console.log("\t_pump entry " + fd + ", " + closing);
         for (var i in _messengers) {
             if (_messengers.hasOwnProperty(i)) {
                 var messenger = _messengers[i];
+                //var messenger = _fd2Messenger[fd];
 
                 if (closing) {
+//console.log("_pump closing");
                     messenger._emit('work');
                 } else {
-                    while (_pn_messenger_work(messenger._messenger, 0) >= 0) {
+//console.log("_pump while start");
+                    while (_pn_messenger_work(messenger._messenger, 0) > 0) {
+                    //while (messenger['work']()) {
+                    //while (messenger._check(_pn_messenger_work(messenger._messenger, 0)) > 0) {
+//console.log("A");
                         messenger._checkSubscriptions();
-                        messenger._checkErrors = false; // TODO improve error handling mechanism.
                         messenger._emit('work');
+//console.log("B");
                     }
+//console.log("_pump while finish");
                 }
             }
         }
+//console.log("\t_pump exit");
     };
 
     /**
@@ -157,9 +175,39 @@ Module.EventDispatch = new function() { // Note the use of new to create a Singl
      * passing a flag to indicate that the socket is closing.
      */
     var _close = function(fd) {
+//console.log("calling close fd = " + fd);
         _pump(fd, true);
+        delete _fd2Messenger[fd];
     };
 
+    var _error = function(error) {
+        var fd = error[0];
+        var messenger = _fd2Messenger[fd];
+        messenger._emit('error', new Module['MessengerError'](error[2]));
+        delete _fd2Messenger[fd];
+    };
+
+    /**
+     * This code cheekily replaces the library socket call with our own one.
+     * The real socket call returns a file descriptor so we harvest that and use
+     * that as a key to map file descriptors to their owning Messenger.
+     */
+    var realsocket = _socket;
+    _socket = function(domain, type, protocol) {
+        var fd = realsocket(domain, type, protocol);
+//console.log("calling socket fd = " + fd);
+        if (_currentMessenger) {
+            _fd2Messenger[fd] = _currentMessenger;
+        } else {
+            console.error("Error: file descriptor " + fd + " cannot be mapped to a Messenger.");
+        }
+        return fd;
+    }
+
+    this.setCurrentMessenger = function(messenger) {
+        _currentMessenger = messenger;
+    }
+
     /**
      * Register the specified Messenger as being interested in network events.
      */
@@ -175,11 +223,12 @@ Module.EventDispatch = new function() { // Note the use of new to create a Singl
             Module['websocket']['on']('connection', _pump);
             Module['websocket']['on']('message', _pump);
             Module['websocket']['on']('close', _close);
+            Module['websocket']['on']('error', _error);
             _firstCall = false;
         }
 
         var name = messenger.getName();
-        _messengers[name] = messenger; 
+        _messengers[name] = messenger;
     };
 
     /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d44f572/proton-c/include/proton/io.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/io.h b/proton-c/include/proton/io.h
index 2d56736..36ffe23 100644
--- a/proton-c/include/proton/io.h
+++ b/proton-c/include/proton/io.h
@@ -31,6 +31,22 @@
 extern "C" {
 #endif
 
+/**
+ * A ::pn_socket_t provides an abstract handle to an IO stream.  The
+ * pipe version is uni-directional.  The network socket version is
+ * bi-directional.  Both are non-blocking.
+ *
+ * pn_socket_t handles from ::pn_pipe() may only be used with
+ * ::pn_read(), ::pn_write(), ::pn_close() and pn_selector_select().
+ *
+ * pn_socket_t handles from ::pn_listen(), ::pn_accept() and
+ * ::pn_connect() must perform further IO using Proton functions.
+ * Mixing Proton io.h functions with native IO functions on the same
+ * handles will result in undefined behavior.
+ *
+ * pn_socket_t handles may only be used with a single pn_io_t during
+ * their lifetime.
+ */
 #if defined(_WIN32) && ! defined(__CYGWIN__)
 #ifdef _WIN64
 typedef unsigned __int64 pn_socket_t;
@@ -43,7 +59,37 @@ typedef int pn_socket_t;
 #define PN_INVALID_SOCKET (-1)
 #endif
 
+/**
+ * A ::pn_io_t manages IO for a group of pn_socket_t handles.  A
+ * pn_io_t object may have zero or one pn_selector_t selectors
+ * associated with it (see ::pn_io_selector()).  If one is associated,
+ * all the pn_socket_t handles managed by a pn_io_t must use that
+ * pn_selector_t instance.
+ *
+ * The pn_io_t interface is single-threaded. All methods are intended
+ * to be used by one thread at a time, except that multiple threads
+ * may use:
+ *
+ *   ::pn_write()
+ *   ::pn_send()
+ *   ::pn_recv()
+ *   ::pn_close()
+ *   ::pn_selector_select()
+ *
+ * provided at most one thread is calling ::pn_selector_select() and
+ * the other threads are operating on separate pn_socket_t handles.
+ */
 typedef struct pn_io_t pn_io_t;
+
+/**
+ * A ::pn_selector_t provides a selection mechanism that allows
+ * efficient monitoring of a large number of Proton connections and
+ * listeners.
+ *
+ * External (non-Proton) sockets may also be monitored, either solely
+ * for event notification (read, write, and timer) or event
+ * notification and use with pn_io_t interfaces.
+ */
 typedef struct pn_selector_t pn_selector_t;
 
 PN_EXTERN pn_io_t *pn_io(void);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d44f572/proton-c/src/windows/iocp.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/iocp.c b/proton-c/src/windows/iocp.c
index 3c0451a..7b03b42 100644
--- a/proton-c/src/windows/iocp.c
+++ b/proton-c/src/windows/iocp.c
@@ -964,8 +964,15 @@ static void drain_zombie_completions(iocp_t *iocp)
     }
   }
 
+  unsigned shutdown_grace = 2000;
+  char *override = getenv("PN_SHUTDOWN_GRACE");
+  if (override) {
+    int grace = atoi(override);
+    if (grace > 0 && grace < 60000)
+      shutdown_grace = (unsigned) grace;
+  }
   pn_timestamp_t now = pn_i_now();
-  pn_timestamp_t deadline = now + 2000;
+  pn_timestamp_t deadline = now + shutdown_grace;
 
   while (pn_list_size(iocp->zombie_list)) {
     if (now >= deadline)
@@ -977,7 +984,7 @@ static void drain_zombie_completions(iocp_t *iocp)
     }
     now = pn_i_now();
   }
-  if (now >= deadline && pn_list_size(iocp->zombie_list))
+  if (now >= deadline && pn_list_size(iocp->zombie_list) && iocp->iocp_trace)
     // Should only happen if really slow TCP handshakes, i.e. total network failure
     iocp_log("network failure on Proton shutdown\n");
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d44f572/proton-c/src/windows/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/schannel.c b/proton-c/src/windows/schannel.c
index 7aaf464..385267f 100644
--- a/proton-c/src/windows/schannel.c
+++ b/proton-c/src/windows/schannel.c
@@ -220,9 +220,9 @@ static int ssl_failed(pn_ssl_t *ssl, char *reason)
     reason = buf;
   }
   ssl->ssl_closed = true;
-  ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
-  ssl->transport->tail_closed = true;
+  ssl->app_input_closed = ssl->app_output_closed = PN_EOS;
   ssl->state = SSL_CLOSED;
+  pni_close_tail(ssl->transport);
   pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: %s", reason);
   return PN_EOS;
 }
@@ -255,6 +255,8 @@ static void ssl_session_free( pn_ssl_session_t *ssn)
 
 pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
 {
+  if (mode == PN_SSL_MODE_SERVER)
+    return NULL;  // Temporary: not ready for ctest, hide from isSSLPresent()
   pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t));
   if (!domain) return NULL;
 
@@ -284,8 +286,9 @@ pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
 
 void pn_ssl_domain_free( pn_ssl_domain_t *domain )
 {
-  if (--domain->ref_count == 0) {
+  if (!domain) return;
 
+  if (--domain->ref_count == 0) {
     if (domain->cert_context)
       CertFreeCertificateContext(domain->cert_context);
     if (domain->cert_store)
@@ -1118,7 +1121,7 @@ static ssize_t process_input_ssl(pn_io_layer_t *io_layer, const char *input_data
 static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t max_len)
 {
   pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
-  if (!ssl) return PN_ERR;
+  if (!ssl) return PN_EOS;
   ssl_log( ssl, "process_output_ssl( max_len=%d )\n",max_len );
 
   ssize_t written = 0;
@@ -1129,7 +1132,7 @@ static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t
     // output buffers eclusively for internal handshake use until negotiation complete
     client_handshake_init(ssl);
     if (ssl->state == SSL_CLOSED)
-      return PN_ERR;
+      return PN_EOS;
     ssl->state = NEGOTIATING;
   }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d44f572/tests/python/proton_tests/common.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/common.py b/tests/python/proton_tests/common.py
index 05e01fd..cfb7e3d 100644
--- a/tests/python/proton_tests/common.py
+++ b/tests/python/proton_tests/common.py
@@ -82,7 +82,7 @@ def isSSLPresent():
     """ True if a suitable SSL library is available.
     """
     try:
-        xxx = SSLDomain(SSLDomain.MODE_CLIENT)
+        xxx = SSLDomain(SSLDomain.MODE_SERVER)
         return True
     except SSLUnavailable, e:
         # SSL libraries not installed

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d44f572/tests/python/proton_tests/messenger.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/messenger.py b/tests/python/proton_tests/messenger.py
index f3dcda4..db815b7 100644
--- a/tests/python/proton_tests/messenger.py
+++ b/tests/python/proton_tests/messenger.py
@@ -984,6 +984,11 @@ class Pump:
 class SelectableMessengerTest(common.Test):
 
   def testSelectable(self, count = 1):
+    if os.name=="nt":
+      # Conflict between native OS select() in Pump and IOCP based pn_selector_t
+      # makes this fail on Windows (see PROTON-668).
+      raise Skipped("Invalid test on Windows with IOCP.")
+
     mrcv = Messenger()
     mrcv.passive = True
     mrcv.subscribe("amqp://~0.0.0.0:1234")


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


[50/51] [abbrv] qpid-proton git commit: added tests to main build

Posted by rh...@apache.org.
added tests to main build


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/a5cb27e7
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/a5cb27e7
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/a5cb27e7

Branch: refs/heads/master
Commit: a5cb27e7319cd3f2177e5c9ce90716aeca737225
Parents: 726a49b
Author: Rafael Schloming <rh...@alum.mit.edu>
Authored: Fri Nov 28 07:44:34 2014 -0500
Committer: Rafael Schloming <rh...@alum.mit.edu>
Committed: Fri Nov 28 07:44:34 2014 -0500

----------------------------------------------------------------------
 proton-c/CMakeLists.txt     | 5 +++++
 tests/javascript/codec.js   | 0
 tests/javascript/message.js | 0
 3 files changed, 5 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5cb27e7/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 7872801..27bebcc 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -553,5 +553,10 @@ endif (RUBY_EXE)
 
 mark_as_advanced (RUBY_EXE RSPEC_EXE)
 
+if (BUILD_JAVASCRIPT)
+  add_test (javascript-codec ${PYTHON_EXECUTABLE} ${env_py} node ${pn_test_root}/javascript/codec.js)
+  add_test (javascript-message ${PYTHON_EXECUTABLE} ${env_py} node ${pn_test_root}/javascript/message.js)
+endif (BUILD_JAVASCRIPT)
+
 # build examples to make sure they still work
 add_subdirectory(../examples ../examples)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5cb27e7/tests/javascript/codec.js
----------------------------------------------------------------------
diff --git a/tests/javascript/codec.js b/tests/javascript/codec.js
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5cb27e7/tests/javascript/message.js
----------------------------------------------------------------------
diff --git a/tests/javascript/message.js b/tests/javascript/message.js
old mode 100644
new mode 100755


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


[36/51] [abbrv] qpid-proton git commit: Add a mechanism to allow the emscripten virtual heap size to be specified at run-time by applications rather than having to change it at compile-time. Improve the documentation especially the main README

Posted by rh...@apache.org.
Add a mechanism to allow the emscripten virtual heap size to be specified at run-time by applications rather than having to change it at compile-time. Improve the documentation especially the main README

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1626584 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/2cf80a9e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/2cf80a9e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/2cf80a9e

Branch: refs/heads/master
Commit: 2cf80a9e7181f2929dea5aa2c6adc935af6262bc
Parents: 929eab4
Author: fadams <fa...@unknown>
Authored: Sun Sep 21 14:44:57 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sun Sep 21 14:44:57 2014 +0000

----------------------------------------------------------------------
 examples/messenger/javascript/send.html       |  14 +-
 examples/messenger/javascript/send.js         |   3 +-
 proton-c/bindings/javascript/README           | 381 ++++++++++++++++++++-
 proton-c/bindings/javascript/TODO             |  48 ++-
 proton-c/bindings/javascript/binding-close.js |  12 +-
 proton-c/bindings/javascript/module.js        |  51 ++-
 6 files changed, 471 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/examples/messenger/javascript/send.html
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html
index 382b293..dc8b448 100644
--- a/examples/messenger/javascript/send.html
+++ b/examples/messenger/javascript/send.html
@@ -26,18 +26,24 @@
 	<meta http-equiv="content-type" content="text/html;charset=utf-8" />
 
 <!--
-  Import JavaScript Messenger Binding proton.js. Note that this simple example pulls
-  it from the node_modules/qpid-proton/lib which is created by the build process
+  Import the Messenger Binding proton.js. Note that this simple example pulls
+  it from the node_modules/qpid-proton/lib, which is created by the build process
   so that the node.js based examples "just work", in a real Web App you would need
-  to copy the proton.js to your own server. 
+  to copy the proton.js to your own server.
+
   In actual fact the CMake build actually builds proton.js into the directory:
   <build>/proton-c/bindings/javascript
   where <build> is the build directory created to run cmake from.
+
+  In this example we also set the global variable PROTON_HEAP_SIZE in order to
+  increase the virtual heap available to the emscripten compiled C runtime. It
+  is not really necessary to do this for this application as the default value
+  of 16777216 is fine, it is simply done here to illustrate how to do it.
 -->
+<script type="text/javascript">PROTON_HEAP_SIZE = 50000000;</script>
 <script type="text/javascript" src="../../../node_modules/qpid-proton/lib/proton.js"></script>
 
 <script type="text/javascript">
-
 var message = new proton.Message();
 var messenger = new proton.Messenger();
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/examples/messenger/javascript/send.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.js b/examples/messenger/javascript/send.js
index 9c48fab..0ca3a7e 100644
--- a/examples/messenger/javascript/send.js
+++ b/examples/messenger/javascript/send.js
@@ -20,11 +20,12 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
+if (typeof process !== 'object' || typeof require !== 'function') {
     console.error("send.js should be run in Node.js");
     return;
 }
 
+PROTON_HEAP_SIZE = 50000000;
 var proton = require("qpid-proton");
 
 var address = "amqp://0.0.0.0";

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/proton-c/bindings/javascript/README
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/README b/proton-c/bindings/javascript/README
index 1998a47..a29352d 100644
--- a/proton-c/bindings/javascript/README
+++ b/proton-c/bindings/javascript/README
@@ -4,6 +4,115 @@ Qpid Proton JavaScript Language Bindings
 The code contained herein provides JavaScript language bindings for working
 with the Qpid Proton AMQP 1.0 protocol engine and messenger library.
 
+Important Note - Modern Browser Needed
+======================================
+
+The JavaScript binding requires ArrayBuffer/TypeArray and WebSocket support.
+Both of these are available in most "modern" browser versions. The author has
+only tried running on FireFox and Chrome, though recent Safari, Opera and IE10+
+*should* work too - YMMV. It might be possible to polyfill for older browsers
+but the author hasn't tried this.
+
+Important Note - WebSocket Transport!!!
+=======================================
+
+Before going any further it is really important to realise that the JavaScript
+bindings to Proton are somewhat different to the bindings for other languages
+because of the restrictions of the execution environment. In particular it is
+very important to note that the JavaScript bindings by default use a WebSocket
+transport and not a TCP transport, so whilst it's possible to create Server style
+applications that clients can connect to (e.g. recv.js and send.js) it is very
+important to note that:
+
+JavaScript clients cannot *directly* talk to "normal" AMQP applications such as
+qpidd or the Java Broker because they use the traditional TCP transport.
+
+This is a slightly irksome issue, but there's no getting away from it because
+it's a security restriction imposed by the browser environment.
+
+
+At the moment even for Node.js we are limited to using a WebSocket transport, but
+it is on the author's "TODO" list to look at providing a means to use either a
+WebSocket transport or a native TCP transport (via node's net library). It should
+also be possible to use native TCP for Chrome "packaged apps", but again this is
+only on the TODO list so if you want to talk to a "normal" AMQP application you
+must live with the WebSocket constraints.
+
+Option 1. proxy from WebSockets to TCP sockets
+<proton>/examples/messenger/javascript/proxy.js
+is a simple Node.js WebSocket<->TCP Socket proxy, simple doing:
+
+node proxy.js
+
+will stand up a proxy listening by default on WebSocket port 5673 and forwarding
+to TCP port 5672 (this is configurable for options do: node proxy.js -h)
+
+Rather than using a stand-alone proxy it is possible to have applications stand
+up their own proxy (where lport = listen port, thost = target host and
+tport = target port):
+
+var proxy = require('./ws2tcp.js');
+proxy.ws2tcp(lport, thost, tport);
+
+For talking to the C++ broker unfortunately proxying is currently the only option
+as qpidd does not have a WebSocket transport.
+
+Option 2. The Java Broker's WebSocket transport.
+Recent releases of the Qpid Java Broker provide a native WebSocket transport which
+means that the JavaScript binding can talk to it with no additional requirements.
+It is necessary to configure the Java Broker as the WebSocket transport is not
+enabled by default. In <qpid-work>/config.json in the "ports" array you need to add:
+
+{
+    "authenticationProvider" : "passwordFile",
+    "name" : "AMQP-WS",
+    "port" : "5673",
+    "transports" : [ "WS" ]
+}
+
+This sets the JavaBroker to listen on WebSocket port 5673 similar to the proxy.
+
+
+One gotcha that still bites the author *** DO NOT FORGET *** that you will be
+using ports that you are not used to!! If you are not connecting check that the
+proxy is running and that you are specifying the right ports. I still mess up :-(
+
+WebRTC Transport
+================
+
+A WebRTC Transport is supported by emscripten, though the author has not tried it.
+If you wan to play with this you are very much on your own at the moment YMMV.
+
+This is configured by adding to the LINK_FLAGS in CMakeLists.txt
+-s \"SOCKET_WEBRTC=1\"
+
+  /* WebRTC sockets supports several options on the Module object.
+
+     * Module['host']: true if this peer is hosting, false otherwise
+     * Module['webrtc']['broker']: hostname for the p2p broker that this peer should use
+     * Module['webrtc']['session']: p2p session for that this peer will join, or undefined if this peer is hosting
+     * Module['webrtc']['hostOptions']: options to pass into p2p library if this peer is hosting
+     * Module['webrtc']['onpeer']: function(peer, route), invoked when this peer is ready to connect
+     * Module['webrtc']['onconnect']: function(peer), invoked when a new peer connection is ready
+     * Module['webrtc']['ondisconnect']: function(peer), invoked when an existing connection is closed
+     * Module['webrtc']['onerror']: function(error), invoked when an error occurs
+   */
+
+If you wanted to play with these you'd likely have to tweak the module.js code in
+<proton>/proton-c/bindings/javascript
+
+The emscripten documentation is a bit light on the WebRTC Transport too, though
+
+emscripten/tests/test_sockets.py
+emscripten/tests/sockets/webrtc_host.c
+emscripten/tests/sockets/webrtc_peer.c
+emscripten/tests/sockets/p2p/broker/p2p-broker.js
+emscripten/tests/sockets/p2p/client/p2p-client.js
+
+Look like they provide a starting point.
+Very much TODO......
+
+
 Creating The Bindings
 =====================
 
@@ -11,26 +120,35 @@ To generate the JavaScript bindings we actually cross-compile from proton-c
 
 You will need to have emscripten (https://github.com/kripken/emscripten) installed
 to do the cross-compilation and in addition you will require a few things that
-emscripten itself depends upon. https://github.com/kripken/emscripten/wiki/Emscripten-SDK
+emscripten itself depends upon.
+
+http://kripken.github.io/emscripten-site/docs/building_from_source/index.html#installing-from-source
+http://kripken.github.io/emscripten-site/docs/building_from_source/toolchain_what_is_needed.html
+provides instructions for installing emscripten and the "fastcomp" LLVM backend.
+This approach lets users use the "bleeding edge" version of emscripten on the
+"incoming" branch (pretty much analogous to building qpid/proton off svn trunk).
+This is the approach that the author of the JavaScript Bindings tends to use.
+
+
+http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
 provides some fairly easy to follow instructions for getting started on several
 platforms the main dependencies are as follows (on Windows the SDK includes these):
 
-* The Emscripten code, from github (git clone git://github.com/kripken/emscripten.git.
-  The documentation suggests master branch but in the short term incoming is
-  probably better as a few updates to emscripten have been added to help get
-  proton working and these may take a little while to get merged back to master.
+* The Emscripten code, from github (git clone git://github.com/kripken/emscripten.git).
 * LLVM with Clang. Emscripten uses LLVM and Clang, but at the moment the JavaScript
   back-end for LLVM is off on a branch so you can't use a stock LLVM/Clang.
-  https://github.com/kripken/emscripten/wiki/LLVM-Backend has lots of explanation
-  and some easy to follow instructions for downloading and building fast-comp
+  http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html
+  http://kripken.github.io/emscripten-site/docs/building_from_source/building_fastcomp_manually_from_source.html#building-fastcomp-from-source
+  has lots of explanation and some easy to follow instructions for downloading
+  and building fastcomp
 * Node.js (0.8 or above; 0.10.17 or above to run websocket-using servers in node)
 * Python 2.7.3
 * Java is required in order to use the Closure Compiler to minify the code.
   
 
 If you haven't run Emscripten before it's a good idea to have a play with the
-tutorial https://github.com/kripken/emscripten/wiki/Tutorial
-
+tutorial here:
+http://kripken.github.io/emscripten-site/docs/getting_started/Tutorial.html
 
 
 
@@ -44,7 +162,8 @@ the root directory) it's:
   cmake ..
   make
 
-and you should be all set, to test it's all working do:
+and you should be all set, to test it's all working do (from the build directory):
+  cd proton-c/bindings/javascript/examples
 
   node recv-async.js
 
@@ -52,14 +171,243 @@ in one window and
 
   node send-async.js
 
-in another
+in another.
+
+These examples are actually JavaScript applications that have been directly
+compiled from recv-async.c and send-async.c in <proton>/examples/messenger/c
+if you'd prefer to write applications in C and compile them to JavaScript that
+is a perfectly valid approach and these examples provide a reasonable starting
+point for doing so.
+
+Documentation
+=============
+
+When you've successfully got a successful build do:
+
+  make docs
+
+Which will make all of the proton documentation including the JavaScript docs.
+If successful the JSDoc generated documentation should be found here:
+
+<proton>/build/proton-c/bindings/javascript/html/index.html
+
+
+Using "native" JavaScript
+=========================
+
+The examples in <proton>/examples/messenger/javascript are the best starting point.
+
+In practice the examples follow a fairly similar pattern to the Python bindings
+the most important thing to bear in mind though is that JavaScript is completely
+asynchronous/non-blocking, which can catch the unwary.
+
+An application follows the following (rough) steps:
+
+1. (optional) Set the heap size.
+It's important to realise that most of the library code is compiled C code and
+the runtime uses a "virtual heap" to support the underlying malloc/free. This is
+implemented internally as an ArrayBuffer with a default size of 16777216.
+
+To allocate a larger heap an application must set the PROTON_HEAP_SIZE global.
+In Node.js this would look like (see send.js):
+PROTON_HEAP_SIZE = 50000000; // Note no var - it needs to be global.
+
+In a browser it would look like (see send.html):
+<script type="text/javascript">PROTON_HEAP_SIZE = 50000000;</script>
+
+2. Load the library and create a message and messenger.
+In Node.js this would look like (see send.js):
+var proton = require("qpid-proton");
+var message = new proton.Message();
+var messenger = new proton.Messenger();
 
+In a browser it would look like (see send.html):
+<script type="text/javascript" src="../../../node_modules/qpid-proton/lib/proton.js"></script>
 
-KNOWN ISSUES
-============
+<script type="text/javascript">
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+....
 
-send-async and recv-async are both pretty hacky at the moment.
+3. Set up event handlers as necessary.
 
+messenger.on('error', <error callback>);
+messenger.on('work', <work callback>);
+messenger.on('subscription', <subscription callback>);
+
+The work callback is triggered on WebSocket events, so in general you would use
+this to send and receive messages, for example in recv.js we have:
+
+var pumpData = function() {
+    while (messenger.incoming()) {
+        var t = messenger.get(message);
+
+        console.log("Address: " + message.getAddress());
+        console.log("Subject: " + message.getSubject());
+
+        // body is the body as a native JavaScript Object, useful for most real cases.
+        //console.log("Content: " + message.body);
+
+        // data is the body as a proton.Data Object, used in this case because
+        // format() returns exactly the same representation as recv.c
+        console.log("Content: " + message.data.format());
+
+        messenger.accept(t);
+    }
+};
+
+messenger.on('work', pumpData);
+
+
+The subscription callback is triggered when the address provided in a call to
+messenger.subscribe(<address>);
+
+Gets resolved. An example of its usage can be found in qpid-config.js which is
+a fully functioning and complete port of the python qpid-config tool. It also
+illustrates how to do asynchronous request/response based applications.
+
+Aside from the asynchronous aspects the rest of the API is essentially the same
+as the Python binding aside from minor things such as camel casing method names etc.
+
+Serialisation/Deserialisation, Types etc.
+=========================================
+
+The JavaScript binding tries to be as simple, intuitive and natural as possible
+so when sending a message all native JavaScript types including Object literals
+and Arrays are transparently supported, for example.
+
+var message = new proton.Message();
+message.setAddress('amqp://localhost');
+message.setSubject('UK.NEWS');
+message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
+
+
+The main things to bear in mind is that (particularly for sending messages) we
+may need to use "adapters" to make sure values are correctly interpreted and
+encoded to the correct type in the AMQP type system. This is especially important
+when interoperating with a peer written in a strongly typed language (C/C++/Java).
+
+Some examples of available types follow:
+
+// UUID
+message.body = new proton.Data.Uuid();
+
+// AMQP Symbol
+message.body = new proton.Data.Symbol("My Symbol");
+
+// Binary data (created from a String in this case).
+message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
+
+// Binary data (Get a Uint8Array view of the data and directly access that).
+message.body = new proton.Data.Binary(4);
+var buffer = message.body.getBuffer();
+buffer[0] = 65;
+buffer[1] = 77;
+buffer[2] = 81;
+buffer[3] = 80;
+
+// Binary Data (Created from an Array, you can use an ArrayBuffer/TypedArray too).
+message.body = new proton.Data.Binary([65, 77, 81, 80]);
+
+
+Note that the implementation of proton.Data.Binary tries to minimise copying so
+it accesses the internal emscripten heap *directly* this requires memory management
+which is mostly handled transparently, but users need to be aware that the
+underlying memory is "owned" by the Message Object so if Binary data needs to
+be maintained after the next call to messenger.get(message); it must be
+*explicitly* copied. For more detail do "make docs" and see:
+<proton>/build/proton-c/bindings/javascript/html/proton.Data.Binary.html
+
+
+// AMQP Described (value, descriptor)
+message.body = new proton.Data.Described('persian, 'com.cheezburger.icanhas');
+
+// AMQP Timestamp maps to native JavaScript Date.
+message.body = new Date();
+
+// Various AMQP Array examples.
+message.body = new proton.Data.Array('INT', [1, 3, 5, 7], "odd numbers");
+message.body = new proton.Data.Array('UINT', [1, 3, 5, 7], "odd");
+message.body = new proton.Data.Array('ULONG', [1, 3, 5, 7], "odd");
+message.body = new proton.Data.Array('FLOAT', [1, 3, 5, 7], "odd");
+message.body = new proton.Data.Array('STRING', ["1", "3", "5", "7"], "odd");
+
+// A JavaScript TypedArray will map directly to and from an AMQP Array of the
+// appropriate type (Internally sets a descriptor of 'TypedArray').
+message.body = new Uint8Array([1, 3, 5, 7]);
+
+// UUID Array
+message.body = new proton.Data.Array('UUID', [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()], "unique");
+
+// Null
+message.body = null;
+
+// Boolean
+message.body = true;
+
+// Native JavaScript Array maps to an AMQP List
+message.body = ['Rod', 'Jane', 'Freddy'];
+
+// Native JavaScript Object maps to an AMQP Map
+message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
+
+// JavaScript only has a "number" type so the binding provides "decorator"
+// methods added to the JavaScript Number class. To access this from number
+// primitives it is necessary to either use braces or use a "double dot" so that
+// the interpreter can disambiguate from a simple decimal point. The binding will
+// attempt to use the correct type such that message.body = 2147483647; would be
+// sent as an AMQP integer but because of the way JavaScript coerces integers
+// message.body = 2147483647.0; would also be sent as an AMQP integer because
+// 2147483647.0 gets transparently conveted to 2147483647 by the interpreter so
+// to explicitly send this as an AMQP float we'd need to do:
+// message.body = 2147483647.0.float();
+
+// Some more number examples:
+message.body = 66..char();  // char
+message.body = 2147483647;  // int
+message.body = -2147483649; // long
+message.body = 12147483649; // long
+message.body = (12147483649).long(); // long
+message.body = (17223372036854778000).ulong(); // ulong
+message.body = (121474.836490).float(); // float
+message.body = 12147483649.0.float(); // float
+message.body = (4294967296).uint(); // uint
+message.body = (255).ubyte(); // ubyte
+
+Note too that floats are subject to a loss of precision
+
+
+Fortunately most of these quirks only affect serialisation.when the binding
+receives a message it will attempt to decode it into the most "natural" native
+JavaScript type.
+
+
+One additional decoding "quirk" can be caused by C++ qpid::messaging clients. It
+is unfortunately quite common for C++ clients to incorrectly encode Strings as
+AMQP Binary by neglecting to provide an encoding. The QMF Management Agent is one
+such culprit. This is a bit of a pain, especially because of proton.Data.Binary
+memory management quirks and having to remember to explicitly copy the data
+on each call to messenger.get(message); In order to cater for this an overloaded
+messenger.get(message, true); has been provided. Setting the second parameter to
+true forces any received Binary payloads to be decoded as Strings. If you know
+that producers might behave in this way and you are not expecting any "real"
+Binary data from the producer this convenience mechanism results in nice clean
+JavaScript Objects being received and is extremely useful for things like QMF.
+
+JSON
+====
+
+As well as allowing native JavaScript Objects and Arrays to be transparently
+serialised and deserialised via the AMQP type system it is also possible to
+serialise/deserialise as JSON.
+
+message.setAddress('amqp://localhost');
+message.setContentType('application/json');
+message.body = {array: [1, 2, 3, 4], object: {name: "John Smith", age: 65}};
+
+On the wire the above will be encoded as an opaque binary in an AMQP data section
+but will be deserialised into a JavaScript Object in exactly the same was as the
+previous examples that use the AMQP type system.
 
 SUPPORT
 =======
@@ -69,5 +417,10 @@ a tracker request:
 
     https://issues.apache.org/jira/browse/PROTON
 
+The main support channel is the qpid-users mailing list, see:
+
+    http://qpid.apache.org/discussion.html#mailing-lists
+
 You can also directly interact with the development team and other users
 in the #qpid channel on irc.freenode.net.
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/proton-c/bindings/javascript/TODO
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/TODO b/proton-c/bindings/javascript/TODO
index bd1d158..092ee2e 100644
--- a/proton-c/bindings/javascript/TODO
+++ b/proton-c/bindings/javascript/TODO
@@ -1,11 +1,49 @@
 Qpid Proton JavaScript Language Bindings TODO List
 ==================================================
 
-The code base contains some tweaked emscripten library code, this is ultimately going
-to get done properly, commited back to emscripten and removed from here.
+Network code is currently limited to a WebSocket transport, including for Node.js
+It would be good to allow a configurable transport so that Node.js and Chrome
+packaged apps could use native TCP sockets.
 
+The JavaScript binding is pure JavaScript, that has been  trans-compiled from C
+to JavaScript using emscripten. This allows the same code to be used in a browser
+and Node.js, but it potentially has a performance penalty in Node.js. An alternative
+for Node.js might be to build a SWIG binding (recent versions of SWIG support
+JavaScript). This should be viewed as a complementary not competing approach as
+it would only work for environments like Node.js and definitely *not* browser
+environments which clearly require pure JavaScript.
+
+Optimisation are enabled for compiling and linking but there hasn't been any
+profiling done yet. The binding code *shouldn't* be the bottleneck but it's
+always possible that I messed up.
+
+Error handling is nowhere near as good as it should be, though this is mostly
+because Messenger itself is a bit lacking on the error handling/recovery front.
+
+Although described as "Proton" this is currently a JavaScript binding for Messenger
+and associated Message & Data classes. There has been some talk on the user list
+of an alternative reactive API based on proton Engine. This might ultimately be
+a better fit for JavaScript but it is very much in its infancy and I haven't
+really looked at it yet.
+
+proton-j seems to use hawt-dispatch, which is modelled after Grand Central
+Dispatch so I need to work out what it's using it do do and whether there are
+parallels in proton-c
+
+Although the WebSocket transport uses the sub-protocol 'AMQPWSB10' as specified
+in http://docs.oasis-open.org/amqp-bindmap/amqp-wsb/v1.0/amqp-wsb-v1.0.html
+section 2.1 is is not technically compliant with the spec. as the AMQP data is
+created by the proton-c code, which produces a data-stream for the TCP transport
+whereas the WebSocket spec. seems to want to make use of the fact that WebSocket
+is a frame based transport (whereas TCP is not). This is quite hard to resolve
+as the binding simply sends the contents of the octet buffer created by proton
+over the transport and thus to make this binding compliant with the spec. would
+require a change to the underlying proton-c code! It is possible that this may be
+done in future as any SCTP would require the ability to push AMQP frames too.
+In the mean time fortunately the Java Broker WebSocket transport is actually
+tolerant of this off-spec. behaviour. My personal view is that both approaches
+should be valid and in particular using the standard TCP framing means that it
+is straightforward to create WebSocket<->TCP proxies, which is useful given that
+only the Java Broker currently has a native WebSocket transport.
 
-The example send-async.c and recv-async.c are both pretty hacky at the moment.
 
-proton-j seems to use hawt-dispatch, which is modelled after Grand Central Dispatch so I need to
-work out what it's using it do do and whether there are parallels in proton-c

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/proton-c/bindings/javascript/binding-close.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding-close.js b/proton-c/bindings/javascript/binding-close.js
index b7f1d93..07b68c2 100644
--- a/proton-c/bindings/javascript/binding-close.js
+++ b/proton-c/bindings/javascript/binding-close.js
@@ -18,10 +18,16 @@
  *
  */
 
-// These values are essentially constants sitting in the proton namespace.
-// We have to set them after pn_get_version_major/pn_get_version_minor have been
-// defined so we must do it here in binding-close.js as it's a --post-js block.
+/**
+ * These values are essentially constants sitting in the proton namespace
+ * that is to say they will be exported via:
+ * proton.VERSION_MAJOR
+ * proton.VERSION_MINOR
+ * We have to set them after pn_get_version_major/pn_get_version_minor have been
+ * defined so we must do it here in binding-close.js as it's a --post-js block.
+ */
 Module['VERSION_MAJOR'] = _pn_get_version_major();
 Module['VERSION_MINOR'] = _pn_get_version_minor();
 
 })(); // End of self calling lambda used to wrap library.
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2cf80a9e/proton-c/bindings/javascript/module.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/module.js b/proton-c/bindings/javascript/module.js
index 0fdb803..cf64700 100644
--- a/proton-c/bindings/javascript/module.js
+++ b/proton-c/bindings/javascript/module.js
@@ -19,9 +19,13 @@
  */
 
 /**
- * This file provides a JavaScript wrapper around the Proton Messenger API.
- * It will be used to wrap the emscripten compiled proton-c code and be minified by
- * the Closure compiler, so all comments will be stripped from the actual library.
+ * This file defines the Module Object which provides a namespace around the Proton
+ * Messenger API. The Module object is used extensively by the emscripten runtime,
+ * however for convenience it is exported with the name "proton" and not "Module".
+ * <p>
+ * The emscripten compiled proton-c code and the JavaScript binding code will be 
+ * minified by the Closure compiler, so all comments will be stripped from the
+ * actual library.
  * <p>
  * This JavaScript wrapper provides a somewhat more idiomatic object oriented
  * interface which abstracts the low-level emscripten based implementation details
@@ -32,25 +36,50 @@
 /**
  * The Module Object is exported by emscripten for all execution platforms, we
  * use it as a namespace to allow us to selectively export only what we wish to
- * be publicly visible from this package/module.
+ * be publicly visible from this package/module, which is wrapped in a closure.
  * <p>
  * Internally the binding code uses the associative array form for declaring
  * exported properties to prevent the Closure compiler from minifying e.g.
  * <pre>Module['Messenger'] = ...</pre>
- * Exported Objects can be used in client code using a more convenient namespace, e.g.:
+ * Exported Objects can however be used in client code using a more convenient
+ * and obvious proton namespace, e.g.:
  * <pre>
- * proton = require('qpid-proton');
+ * var proton = require('qpid-proton');
  * var messenger = new proton.Messenger();
  * var message = new proton.Message();
+ * ...
+ * </pre>
+ * The core part of this library is actually proton-c compiled into JavaScript.
+ * In order to provide C style memory management (malloc/free) emscripten uses
+ * a "virtual heap", which is actually a pre-allocated ArrayBuffer. The size of
+ * this virtual heap is set as part of the runtime initialisation and cannot be
+ * changed subsequently (the default size is 16*1024*1024 = 16777216).
+ * <p>
+ * Applications can specify the size of virtual heap that they require via the
+ * global variable PROTON_HEAP_SIZE, this must be set <b>before</b> the library is
+ * loaded e.g. in Node.js an application would do:
+ * <pre>
+ * PROTON_HEAP_SIZE = 50000000; // Note no var - it needs to be global.
+ * var proton = require('qpid-proton');
+ * ...
+ * </pre>
+ * A browser based application would do:
+ * <pre>
+ * &lt;script type="text/javascript"&gt;PROTON_HEAP_SIZE = 50000000;&lt;/script&gt;
+ * &lt;script type="text/javascript" src="proton.js">&lt;/script&gt;
  * </pre>
  * @namespace proton
  */
+var Module = {};
 
-var Module = {
-    // Prevent emscripten runtime exiting, we will be enabling network callbacks.
-    'noExitRuntime' : true,
-};
-
+// If the global variable PROTON_HEAP_SIZE has been set by the application this
+// will result in the emscripten heap getting set to the next multiple of
+// 16777216 above PROTON_HEAP_SIZE.
+if (typeof process === 'object' && typeof require === 'function' && global['PROTON_HEAP_SIZE']) {
+    Module['TOTAL_MEMORY'] = global['PROTON_HEAP_SIZE'];
+} else if (typeof window === 'object' && window['PROTON_HEAP_SIZE']) {
+    Module['TOTAL_MEMORY'] = window['PROTON_HEAP_SIZE'];
+}
 
 /*****************************************************************************/
 /*                                                                           */


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


[30/51] [abbrv] qpid-proton git commit: Refactor JavaScript binding from a single ludicrously huge binding.js into a set of sub-modules that should hopefully make maintenance much simpler

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/message.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/message.js b/proton-c/bindings/javascript/message.js
new file mode 100644
index 0000000..564cc6e
--- /dev/null
+++ b/proton-c/bindings/javascript/message.js
@@ -0,0 +1,848 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                  Message                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.Message instance.
+ * @classdesc This class is a mutable holder of message content that may be used
+ * to generate and encode or decode and access AMQP formatted message data.
+ * @constructor proton.Message
+ * @property {object} instructions delivery instructions for the message.
+ * @property {object} annotations infrastructure defined message annotations.
+ * @property {object} properties application defined message properties.
+ * @property {object} body message body as a native JavaScript Object.
+ * @property {object} data message body as a proton.Data Object.
+ */
+Module['Message'] = function() { // Message Constructor.
+    this._message = _pn_message();
+    this._id = new Data(_pn_message_id(this._message));
+    this._correlationId = new Data(_pn_message_correlation_id(this._message));
+
+    // ************************* Public properties ****************************
+
+    this['instructions'] = null;
+    this['annotations'] = null;
+
+    // Intitialise with an empty Object so we can set properties in a natural way.
+    // message.properties.prop1 = "foo";
+    // message.properties.prop2 = "bar";
+    this['properties'] = {};
+
+    this['body'] = null;
+    this['data'] = null;
+};
+
+// Expose constructor as package scope variable to make internal calls less verbose.
+var Message = Module['Message'];
+
+// Expose prototype as a variable to make method declarations less verbose.
+var _Message_ = Message.prototype;
+
+// ************************** Class properties ********************************
+
+Message['DEFAULT_PRIORITY'] = 4; /** Default priority for messages.*/
+
+// ************************* Protected methods ********************************
+
+// We use the dot notation rather than associative array form for protected
+// methods so they are visible to this "package", but the Closure compiler will
+// minify and obfuscate names, effectively making a defacto "protected" method.
+
+/**
+ * This helper method checks the supplied error code, converts it into an
+ * exception and throws the exception. This method will try to use the message
+ * populated in pn_message_error(), if present, but if not it will fall
+ * back to using the basic error code rendering from pn_code().
+ * @param code the error code to check.
+ */
+_Message_._check = function(code) {
+    if (code < 0) {
+        var errno = this['getErrno']();
+        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
+
+        throw new Module['MessageError'](message);
+    } else {
+        return code;
+    }
+};
+
+/**
+ * Encode the Message prior to sending on the wire.
+ */
+_Message_._preEncode = function() {
+    // A Message Object may be reused so we create new Data instances and clear
+    // the state for them each time put() gets called.
+    var inst = new Data(_pn_message_instructions(this._message));
+    var ann = new Data(_pn_message_annotations(this._message));
+    var props = new Data(_pn_message_properties(this._message));
+    var body = new Data(_pn_message_body(this._message));
+
+    inst.clear();
+    if (this['instructions']) {
+        inst['putObject'](this['instructions']);
+    }
+
+    ann.clear();
+    if (this['annotations']) {
+        ann['putObject'](this['annotations']);
+    }
+
+    props.clear();
+    if (this['properties']) {
+        props['putObject'](this['properties']);
+    }
+
+    body.clear();
+    if (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']);
+        }
+    }
+};
+
+/**
+ * Decode the Message after receiving off the wire.
+ * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
+ *        objects as strings. This can be useful as the data in Binary objects
+ *        will be overwritten with subsequent calls to get, so they must be
+ *        explicitly copied. Needless to say it is only safe to set this flag if
+ *        you know that the data you are dealing with is actually a string, for
+ *        example C/C++ applications often seem to encode strings as AMQP binary,
+ *        a common cause of interoperability problems.
+ */
+_Message_._postDecode = function(decodeBinaryAsString) {
+    var inst = new Data(_pn_message_instructions(this._message));
+    var ann = new Data(_pn_message_annotations(this._message));
+    var props = new Data(_pn_message_properties(this._message));
+    var body = new Data(_pn_message_body(this._message), decodeBinaryAsString);
+
+    if (inst.next()) {
+        this['instructions'] = inst['getObject']();
+    } else {
+        this['instructions'] = {};
+    }
+
+    if (ann.next()) {
+        this['annotations'] = ann['getObject']();
+    } else {
+        this['annotations'] = {};
+    }
+
+    if (props.next()) {
+        this['properties'] = props['getObject']();
+    } else {
+        this['properties'] = {};
+    }
+
+    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;
+    }
+};
+
+// *************************** Public methods *********************************
+
+/**
+ * Free the Message.
+ * <p>
+ * N.B. This method has to be called explicitly in JavaScript as we can't
+ * intercept finalisers, so we need to remember to free before removing refs.
+ * @method free
+ * @memberof! proton.Message#
+ */
+_Message_['free'] = function() {
+    _pn_message_free(this._message);
+};
+
+/**
+ * @method getErrno
+ * @memberof! proton.Message#
+ * @returns {number the most recent error message code.
+ */
+_Message_['getErrno'] = function() {
+    return _pn_message_errno(this._message);
+};
+
+/**
+ * @method getError
+ * @memberof! proton.Message#
+ * @returns {string} the most recent error message as a String.
+ */
+_Message_['getError'] = function() {
+    return Pointer_stringify(_pn_error_text(_pn_message_error(this._message)));
+};
+
+/**
+ * Clears the contents of the Message. All fields will be reset to their default values.
+ * @method clear
+ * @memberof! proton.Message#
+ */
+_Message_['clear'] = function() {
+    _pn_message_clear(this._message);
+    this['instructions'] = null;
+    this['annotations'] = null;
+    this['properties'] = {};
+    this['body'] = null;
+    this['data'] = null;
+};
+
+/**
+ * Get the inferred flag for a message.
+ * <p>
+ * The inferred flag for a message indicates how the message content
+ * is encoded into AMQP sections. If inferred is true then binary and
+ * list values in the body of the message will be encoded as AMQP DATA
+ * and AMQP SEQUENCE sections, respectively. If inferred is false,
+ * then all values in the body of the message will be encoded as AMQP
+ * VALUE sections regardless of their type. Use
+ * {@link proton.Message.setInferred} to set the value.
+ * @method isInferred
+ * @memberof! proton.Message#
+ * @returns {boolean} true iff the inferred flag for the message is set.
+ */
+_Message_['isInferred'] = function() {
+    return (_pn_message_is_inferred(this._message) > 0);
+};
+
+/**
+ * Set the inferred flag for a message. See {@link proton.Message.isInferred} 
+ * for a description of what the inferred flag is.
+ * @method setInferred
+ * @memberof! proton.Message#
+ * @param {boolean} inferred the new value of the inferred flag.
+ */
+_Message_['setInferred'] = function(inferred) {
+    this._check(_pn_message_set_inferred(this._message, inferred));
+};
+
+/**
+ * Get the durable flag for a message.
+ * <p>
+ * The durable flag indicates that any parties taking responsibility
+ * for the message must durably store the content. Use
+ * {@link proton.Message.setDurable} to set the value.
+ * @method isDurable
+ * @memberof! proton.Message#
+ * @returns {boolean} true iff the durable flag for the message is set.
+ */
+_Message_['isDurable'] = function() {
+    return (_pn_message_is_durable(this._message) > 0);
+};
+
+/**
+ * Set the durable flag for a message. See {@link proton.Message.isDurable} 
+ * for a description of what the durable flag is.
+ * @method setDurable
+ * @memberof! proton.Message#
+ * @param {boolean} durable the new value of the durable flag.
+ */
+_Message_['setDurable'] = function(durable) {
+    this._check(_pn_message_set_durable(this._message, durable));
+};
+
+/**
+ * Get the priority for a message.
+ * <p>
+ * The priority of a message impacts ordering guarantees. Within a
+ * given ordered context, higher priority messages may jump ahead of
+ * lower priority messages. Priority range is 0..255
+ * @method getPriority
+ * @memberof! proton.Message#
+ * @returns {number} the priority of the Message.
+ */
+_Message_['getPriority'] = function() {
+    return _pn_message_get_priority(this._message) & 0xFF; // & 0xFF converts to unsigned.
+};
+
+/**
+ * Set the priority of the Message. See {@link proton.Message.getPriority}
+ * for details on message priority.
+ * @method setPriority
+ * @memberof! proton.Message#
+ * @param {number} priority the address we want to send the Message to.
+ */
+_Message_['setPriority'] = function(priority) {
+    this._check(_pn_message_set_priority(this._message, priority));
+};
+
+/**
+ * Get the ttl for a message.
+ * <p>
+ * The ttl for a message determines how long a message is considered
+ * live. When a message is held for retransmit, the ttl is
+ * decremented. Once the ttl reaches zero, the message is considered
+ * dead. Once a message is considered dead it may be dropped. Use
+ * {@link proton.Message.setTTL} to set the ttl for a message.
+ * @method getTTL
+ * @memberof! proton.Message#
+ * @returns {number} the ttl in milliseconds.
+ */
+_Message_['getTTL'] = function() {
+    return _pn_message_get_ttl(this._message);
+};
+
+/**
+ * Set the ttl for a message. See {@link proton.Message.getTTL}
+ * for a detailed description of message ttl.
+ * @method setTTL
+ * @memberof! proton.Message#
+ * @param {number} ttl the new value for the message ttl in milliseconds.
+ */
+_Message_['setTTL'] = function(ttl) {
+    this._check(_pn_message_set_ttl(this._message, ttl));
+};
+
+/**
+ * Get the first acquirer flag for a message.
+ * <p>
+ * When set to true, the first acquirer flag for a message indicates
+ * that the recipient of the message is the first recipient to acquire
+ * the message, i.e. there have been no failed delivery attempts to
+ * other acquirers. Note that this does not mean the message has not
+ * been delivered to, but not acquired, by other recipients.
+ * @method isFirstAcquirer
+ * @memberof! proton.Message#
+ * @returns {boolean} true iff the first acquirer flag for the message is set.
+ */
+_Message_['isFirstAcquirer'] = function() {
+    return (_pn_message_is_first_acquirer(this._message) > 0);
+};
+
+/**
+ * Set the first acquirer flag for a message. See {@link proton.Message.isFirstAcquirer} 
+ * for details on the first acquirer flag.
+ * @method setFirstAcquirer
+ * @memberof! proton.Message#
+ * @param {boolean} first the new value of the first acquirer flag.
+ */
+_Message_['setFirstAcquirer'] = function(first) {
+    this._check(_pn_message_set_first_acquirer(this._message, first));
+};
+
+/**
+ * Get the delivery count for a message.
+ * <p>
+ * The delivery count field tracks how many attempts have been made to
+ * deliver a message. Use {@link proton.Message.setDeliveryCount} to set
+ * the delivery count for a message.
+ * @method getDeliveryCount
+ * @memberof! proton.Message#
+ * @returns {number} the delivery count for the message.
+ */
+_Message_['getDeliveryCount'] = function() {
+    return _pn_message_get_delivery_count(this._message);
+};
+
+/**
+ * Set the delivery count for a message. See {@link proton.Message.getDeliveryCount}
+ * for details on what the delivery count means.
+ * @method setDeliveryCount
+ * @memberof! proton.Message#
+ * @param {number} count the new delivery count.
+ */
+_Message_['setDeliveryCount'] = function(count) {
+    this._check(_pn_message_set_delivery_count(this._message, count));
+};
+
+/**
+ * Get the id for a message.
+ * <p>
+ * The message id provides a globally unique identifier for a message.
+ * A message id can be an a string, an unsigned long, a uuid or a binary value.
+ * @method getID
+ * @memberof! proton.Message#
+ * @returns {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} the message id.
+ */
+_Message_['getID'] = function() {
+    return this._id['getObject']();
+};
+
+/**
+ * Set the id for a message. See {@link proton.Message.getID}
+ * for more details on the meaning of the message id. Note that only string,
+ * unsigned long, uuid, or binary values are permitted.
+ * @method setID
+ * @memberof! proton.Message#
+ * @param {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} id the
+ *        new value of the message id.
+ */
+_Message_['setID'] = function(id) {
+    this._id['rewind']();
+    if (Data.isNumber(id)) {
+        this._id['putULONG'](id);
+    } else {
+        this._id['putObject'](id);
+    }
+};
+
+/**
+ * Get the user id of the message creator.
+ * <p>
+ * The underlying raw data of the returned {@link proton.Data.Binary} will be
+ * valid until any one of the following operations occur:
+ * <pre>
+ *  - {@link proton.Message.free}
+ *  - {@link proton.Message.clear}
+ *  - {@link proton.Message.setUserID}
+ * </pre>
+ * @method getUserID
+ * @memberof! proton.Message#
+ * @returns {proton.Data.Binary} the message's user id.
+ */
+_Message_['getUserID'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes_t bytes = pn_message_get_user_id(message);
+
+    // Here's the quirky bit, pn_message_get_user_id actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_message_get_user_id.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_message_get_user_id(bytes, this._message);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a proton.Data.Binary from the pn_bytes_t information.
+    var binary = new Data['Binary'](size, start);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return binary;
+};
+
+/**
+ * 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}, 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
+ * @memberof! proton.Message#
+ * @param {(string|proton.Data.Uuid)} id the new user id for the message.
+ */
+_Message_['setUserID'] = function(id) {
+    // If the id parameter is a proton.Data.Binary use it otherwise create a Binary
+    // using the string form of the parameter that was passed.
+    id = (id instanceof Data['Binary']) ? id : new Data['Binary']('' + id);
+
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_message_set_user_id(message, pn_bytes(id.size, id.start));
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, id.size, id.start);
+
+    // The compiled pn_message_set_user_id takes the pn_bytes_t by reference not value.
+    this._check(_pn_message_set_user_id(this._message, bytes));
+
+    // After calling _pn_message_set_user_id the underlying Message object "owns" the
+    // binary data, so we can call free on the proton.Data.Binary instance to
+    // release any storage it has acquired back to the emscripten heap.
+    id['free']();
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the address for a message.
+ * @method getAddress
+ * @memberof! proton.Message#
+ * @returns {string} the address of the Message.
+ */
+_Message_['getAddress'] = function() {
+    return Pointer_stringify(_pn_message_get_address(this._message));
+};
+
+/**
+ * Set the address of the Message.
+ * @method setAddress
+ * @memberof! proton.Message#
+ * @param {string} address the address we want to send the Message to.
+ */
+_Message_['setAddress'] = function(address) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_address(this._message, allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the subject for a message.
+ * @method getSubject
+ * @memberof! proton.Message#
+ * @returns {string} the subject of the Message.
+ */
+_Message_['getSubject'] = function() {
+    return Pointer_stringify(_pn_message_get_subject(this._message));
+};
+
+/**
+ * Set the subject of the Message.
+ * @method setSubject
+ * @memberof! proton.Message#
+ * @param {string} subject the subject we want to set for the Message.
+ */
+_Message_['setSubject'] = function(subject) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_subject(this._message, allocate(intArrayFromString(subject), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the reply to for a message.
+ * @method getReplyTo
+ * @memberof! proton.Message#
+ * @returns {string} the reply to of the Message.
+ */
+_Message_['getReplyTo'] = function() {
+    return Pointer_stringify(_pn_message_get_reply_to(this._message));
+};
+
+/**
+ * Set the reply to for a message.
+ * @method setReplyTo
+ * @memberof! proton.Message#
+ * @param {string} reply the reply to we want to set for the Message.
+ */
+_Message_['setReplyTo'] = function(reply) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_reply_to(this._message, allocate(intArrayFromString(reply), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the correlation id for a message.
+ * <p>
+ * A correlation id can be an a string, an unsigned long, a uuid or a binary value.
+ * @method getCorrelationID
+ * @memberof! proton.Message#
+ * @returns {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} the message id.
+ */
+_Message_['getCorrelationID'] = function() {
+    return this._correlationId['getObject']();
+};
+
+/**
+ * Set the correlation id for a message. See {@link proton.Message.getCorrelationID}
+ * for more details on the meaning of the correlation id. Note that only string,
+ * unsigned long, uuid, or binary values are permitted.
+ * @method setCorrelationID
+ * @memberof! proton.Message#
+ * @param {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} id the
+ *        new value of the correlation id.
+ */
+_Message_['setCorrelationID'] = function(id) {
+    this._correlationId['rewind']();
+    if (Data.isNumber(id)) {
+        this._correlationId['putULONG'](id);
+    } else {
+        this._correlationId['putObject'](id);
+    }
+};
+
+/**
+ * Get the content type for a message.
+ * @method getContentType
+ * @memberof! proton.Message#
+ * @returns {string} the content type of the Message.
+ */
+_Message_['getContentType'] = function() {
+    return Pointer_stringify(_pn_message_get_content_type(this._message));
+};
+
+/**
+ * Set the content type for a message.
+ * @method setContentType
+ * @memberof! proton.Message#
+ * @param {string} type the content type we want to set for the Message.
+ */
+_Message_['setContentType'] = function(type) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_content_type(this._message, allocate(intArrayFromString(type), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the content encoding for a message.
+ * @method getContentEncoding
+ * @memberof! proton.Message#
+ * @returns {string} the content encoding of the Message.
+ */
+_Message_['getContentEncoding'] = function() {
+    return Pointer_stringify(_pn_message_get_content_encoding(this._message));
+};
+
+/**
+ * Set the content encoding for a message.
+ * @method setContentEncoding
+ * @memberof! proton.Message#
+ * @param {string} encoding the content encoding we want to set for the Message.
+ */
+_Message_['setContentEncoding'] = function(encoding) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_content_encoding(this._message, allocate(intArrayFromString(encoding), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the expiry time for a message.
+ * A zero value for the expiry time indicates that the message will
+ * never expire. This is the default value.
+ * @method getExpiryTime
+ * @memberof! proton.Message#
+ * @returns {Date} the expiry time for the message.
+ */
+_Message_['getExpiryTime'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_message_get_expiry_time(this._message);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
+};
+
+/**
+ * Set the expiry time for a message.
+ * @method setExpiryTime
+ * @memberof! proton.Message#
+ * @param {(number|Date)} time the new expiry time for the message.
+ */
+_Message_['setExpiryTime'] = function(time) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(time.valueOf());
+    this._check(_pn_message_set_expiry_time(this._message, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
+};
+
+/**
+ * Get the creation time for a message.
+ * A zero value for the creation time indicates that the creation time
+ * has not been set. This is the default value.
+ * @method getCreationTime
+ * @memberof! proton.Message#
+ * @returns {Date} the creation time for the message.
+ */
+_Message_['getCreationTime'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_message_get_creation_time(this._message);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
+};
+
+/**
+ * Set the creation time for a message.
+ * @method setCreationTime
+ * @memberof! proton.Message#
+ * @param {(number|Date)} time the new creation time for the message.
+ */
+_Message_['setCreationTime'] = function(time) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(time.valueOf());
+    this._check(_pn_message_set_creation_time(this._message, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
+};
+
+/**
+ * Get the group id for a message.
+ * @method getGroupID
+ * @memberof! proton.Message#
+ * @returns {string} the group id of the Message.
+ */
+_Message_['getGroupID'] = function() {
+    return Pointer_stringify(_pn_message_get_group_id(this._message));
+};
+
+/**
+ * Set the group id for a message.
+ * @method setGroupID
+ * @memberof! proton.Message#
+ * @param {string} id the group id we want to set for the Message.
+ */
+_Message_['setGroupID'] = function(id) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_group_id(this._message, allocate(intArrayFromString(id), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the group sequence for a message.
+ * <p>
+ * The group sequence of a message identifies the relative ordering of
+ * messages within a group. The default value for the group sequence
+ * of a message is zero.
+ * @method getGroupSequence
+ * @memberof! proton.Message#
+ * @returns {number} the group sequence for the message.
+ */
+_Message_['getGroupSequence'] = function() {
+    return _pn_message_get_group_sequence(this._message);
+};
+
+/**
+ * Set the group sequence for a message. See {@link proton.Message.getGroupSequence}
+ * for details on what the group sequence means.
+ * @method setGroupSequence
+ * @memberof! proton.Message#
+ * @param {number} n the new group sequence for the message.
+ */
+_Message_['setGroupSequence'] = function(n) {
+    this._check(_pn_message_set_group_sequence(this._message, n));
+};
+
+/**
+ * Get the reply to group id for a message.
+ * @method getReplyToGroupID
+ * @memberof! proton.Message#
+ * @returns {string} the reply to group id of the Message.
+ */
+_Message_['getReplyToGroupID'] = function() {
+    return Pointer_stringify(_pn_message_get_reply_to_group_id(this._message));
+};
+
+/**
+ * Set the reply to group id for a message.
+ * @method setReplyToGroupID
+ * @memberof! proton.Message#
+ * @param {string} id the reply to group id we want to set for the Message.
+ */
+_Message_['setReplyToGroupID'] = function(id) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_reply_to_group_id(this._message, allocate(intArrayFromString(id), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * The following methods are marked as deprecated and are not implemented.
+ * pn_message_get_format()
+ * pn_message_set_format()
+ * pn_message_load()
+ * pn_message_load_data()
+ * pn_message_load_text()
+ * pn_message_load_amqp()
+ * pn_message_load_json()
+ * pn_message_save()
+ * pn_message_save_data()
+ * pn_message_save_text()
+ * pn_message_save_amqp()
+ * pn_message_save_json()
+ * pn_message_data()
+ */
+
+/**
+ * Return a Binary representation of the message encoded in AMQP format. N.B. the
+ * returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
+ * responsible for freeing it or passing it to a method that consumes a Binary
+ * such as {@link proton.Message.decode}.
+ * @method encode
+ * @memberof! proton.Message#
+ * @returns {proton.Data.Binary} a representation of the message encoded in AMQP format.
+ */
+_Message_['encode'] = function() {
+    this._preEncode();
+    var size = 1024;
+    while (true) {
+        setValue(size, size, 'i32'); // Set pass by reference variable.
+        var bytes = _malloc(size);   // Allocate storage from emscripten heap.
+        var err = _pn_message_encode(this._message, bytes, size);
+        var size = getValue(size, 'i32'); // Dereference the real size value;
+
+        if (err === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else if (err >= 0) {
+            return new Data['Binary'](size, bytes);
+        } else {
+            _free(bytes);
+            this._check(err);
+            return;
+        }
+    }
+};
+
+/**
+ * Decodes and loads the message content from supplied Binary AMQP data  N.B. 
+ * this method "consumes" data from a {@link proton.Data.Binary} in other words
+ * it takes responsibility for the underlying data and frees the raw data from
+ * the Binary.
+ * @method decode
+ * @memberof! proton.Message#
+ * @param {proton.Data.Binary} encoded the AMQP encoded binary message.
+ */
+_Message_['decode'] = function(encoded) {
+    var err = _pn_message_decode(this._message, encoded.start, encoded.size);
+    encoded['free'](); // Free the original Binary.
+    if (err >= 0) {
+        this._postDecode();
+    }
+    this._check(err);
+};
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/messenger.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/messenger.js b/proton-c/bindings/javascript/messenger.js
new file mode 100644
index 0000000..993670f
--- /dev/null
+++ b/proton-c/bindings/javascript/messenger.js
@@ -0,0 +1,799 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                 Messenger                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.Messenger instance giving it an (optional) name. If name
+ * is supplied that will be used as the name of the Messenger, otherwise a UUID
+ * will be used. The Messenger is initialised to non-blocking mode as it makes
+ * little sense to have blocking behaviour in a JavaScript implementation.
+ * @classdesc This class is
+ * @constructor proton.Messenger
+ * @param {string} name the name of this Messenger instance.
+ */
+Module['Messenger'] = function(name) { // Messenger Constructor.
+    /**
+     * The emscripten idiom below is used in a number of places in the JavaScript
+     * bindings to map JavaScript Strings to C style strings. ALLOC_STACK will
+     * increase the stack and place the item there. When the stack is next restored
+     * (by calling Runtime.stackRestore()), that memory will be automatically
+     * freed. In C code compiled by emscripten saving and restoring of the stack
+     * is automatic, but if we want to us ALLOC_STACK from native JavaScript we
+     * need to explicitly save and restore the stack using Runtime.stackSave()
+     * and Runtime.stackRestore() or we will leak emscripten heap memory.
+     * See https://github.com/kripken/emscripten/wiki/Interacting-with-code
+     * The _pn_messenger constructor copies the char* passed to it.
+     */
+    var sp = Runtime.stackSave();
+    this._messenger = _pn_messenger(name ? allocate(intArrayFromString(name), 'i8', ALLOC_STACK) : 0);
+    Runtime.stackRestore(sp);
+
+    /**
+     * Initiate Messenger non-blocking mode. For JavaScript we make this the
+     * default behaviour and don't export this method because JavaScript is
+     * fundamentally an asynchronous non-blocking execution environment.
+     */
+    _pn_messenger_set_blocking(this._messenger, false);
+
+    // Subscriptions that haven't yet completed, used for managing subscribe events.
+    this._pendingSubscriptions = [];
+
+    // Used in the Event registration mechanism (in the 'on' and 'emit' methods).
+    this._callbacks = {};
+
+    // This call ensures that the emscripten network callback functions are initialised.
+    Module.EventDispatch.registerMessenger(this);
+
+
+    // TODO improve error handling mechanism.
+    /*
+     * The emscripten websocket error event could get triggered by any Messenger
+     * and it's hard to determine which one without knowing which file descriptors
+     * are associated with which instance. As a workaround we set the _checkErrors
+     * flag when we call put or subscribe and reset it when work succeeds.
+     */
+    this._checkErrors = false;
+
+    /**
+     * TODO update to handle multiple Messenger instances
+     * Handle the emscripten websocket error and use it to trigger a MessengerError
+     * Note that the emscripten websocket error passes an array containing the
+     * file descriptor, the errno and the message, we just use the message here.
+     */
+    var that = this;
+    Module['websocket']['on']('error', function(error) {
+
+console.log("Module['websocket']['on'] caller is " + arguments.callee.caller.toString());
+
+console.log("that._checkErrors = " + that._checkErrors);
+console.log("error = " + error);
+        if (that._checkErrors) {
+            that._emit('error', new Module['MessengerError'](error[2]));
+        }
+    });
+};
+
+Module['Messenger'].PN_CUMULATIVE = 0x1; // Protected Class attribute.
+
+// Expose prototype as a variable to make method declarations less verbose.
+var _Messenger_ = Module['Messenger'].prototype;
+
+// ************************* Protected methods ********************************
+
+// We use the dot notation rather than associative array form for protected
+// methods so they are visible to this "package", but the Closure compiler will
+// minify and obfuscate names, effectively making a defacto "protected" method.
+
+/**
+ * This helper method checks the supplied error code, converts it into an
+ * exception and throws the exception. This method will try to use the message
+ * populated in pn_messenger_error(), if present, but if not it will fall
+ * back to using the basic error code rendering from pn_code().
+ * @param code the error code to check.
+ */
+_Messenger_._check = function(code) {
+    if (code < 0) {
+        if (code === Module['Error']['INPROGRESS']) {
+            return code;
+        }
+
+        var errno = this['getErrno']();
+        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
+
+        if (this._callbacks['error']) {
+            this._emit('error', new Module['MessengerError'](message));
+        } else {
+            throw new Module['MessengerError'](message);
+        }
+    } else {
+        return code;
+    }
+};
+
+/**
+ * Invokes the callbacks registered for a specified event.
+ * @method _emit
+ * @memberof! proton.Messenger#
+ * @param event {string} the event we want to emit.
+ * @param param {object} the parameter we'd like to pass to the event callback.
+ */
+_Messenger_._emit = function(event, param) {
+    var callbacks = this._callbacks[event];
+    if (callbacks) {
+        for (var i = 0; i < callbacks.length; i++) {
+            var callback = callbacks[i];
+            if ('function' === typeof callback) {
+                callback.call(this, param);
+            }
+        }
+    }
+};
+
+/**
+ * Checks any pending subscriptions and when a source address becomes available
+ * emit a subscription event passing the Subscription that triggered the event.
+ * Note that this doesn't seem to work for listen/bind style subscriptions,
+ * that is to say subscriptions of the form amqp://~0.0.0.0 don't know why?
+ */
+_Messenger_._checkSubscriptions = function() {
+    // Check for completed subscriptions, and emit subscribe event.
+    var subscriptions = this._pendingSubscriptions;
+    if (subscriptions.length) {
+        var pending = []; // Array of any subscriptions that remain pending.
+        for (var j = 0; j < subscriptions.length; j++) {
+            subscription = subscriptions[j];
+            if (subscription['getAddress']()) {
+                this._emit('subscription', subscription);
+            } else {
+                pending.push(subscription);
+            }
+        }
+        this._pendingSubscriptions = pending;
+    }
+};
+
+
+// *************************** Public methods *****************************
+
+/**
+ * N.B. The following methods are not exported by the JavaScript Messenger
+ * binding for reasons described below.
+ *
+ * For these methods it is expected that security would be implemented via
+ * a secure WebSocket. TODO what happens if we decide to implement TCP sockets
+ * via Node.js net library. If we do that we may want to compile OpenSSL
+ * using emscripten and include these methods.
+ * pn_messenger_set_certificate()
+ * pn_messenger_get_certificate()
+ * pn_messenger_set_private_key()
+ * pn_messenger_get_private_key()
+ * pn_messenger_set_password()
+ * pn_messenger_get_password()
+ * pn_messenger_set_trusted_certificates()
+ * pn_messenger_get_trusted_certificates()
+ *
+ * For these methods the implementation is fairly meaningless because JavaScript
+ * is a fundamentally asynchronous non-blocking environment.
+ * pn_messenger_set_timeout()
+ * pn_messenger_set_blocking()
+ * pn_messenger_interrupt()
+ * pn_messenger_send() // Not sure if this is useful in JavaScript.
+ */
+
+/**
+ * Registers a listener callback for a specified event.
+ * @method on
+ * @memberof! proton.Messenger#
+ * @param {string} event the event we want to listen for.
+ * @param {function} callback the callback function to be registered for the specified event.
+ */
+_Messenger_['on'] = function(event, callback) {
+    if ('function' === typeof callback) {
+        if (!this._callbacks[event]) {
+            this._callbacks[event] = [];
+        }
+
+        this._callbacks[event].push(callback);
+    }
+};
+
+/**
+ * Removes a listener callback for a specified event.
+ * @method removeListener
+ * @memberof! proton.Messenger#
+ * @param {string} event the event we want to detach from.
+ * @param {function} callback the callback function to be removed for the specified event.
+ *        if no callback is specified all callbacks are removed for the event.
+ */
+_Messenger_['removeListener'] = function(event, callback) {
+    if (callback) {
+        var callbacks = this._callbacks[event];
+        if ('function' === typeof callback && callbacks) {
+            // Search for the specified callback.
+            for (var i = 0; i < callbacks.length; i++) {
+                if (callback === callbacks[i]) {
+                    // If we find the specified callback delete it and return.
+                    callbacks.splice(i, 1);
+                    return;
+                }
+            }
+        }
+    } else {
+        // If we call remove with no callback we remove all callbacks.
+        delete this._callbacks[event];
+    }
+};
+
+/**
+ * Retrieves the name of a Messenger.
+ * @method getName
+ * @memberof! proton.Messenger#
+ * @returns {string} the name of the messenger.
+ */
+_Messenger_['getName'] = function() {
+    return Pointer_stringify(_pn_messenger_name(this._messenger));
+};
+
+/**
+ * Retrieves the timeout for a Messenger.
+ * @method getTimeout
+ * @memberof! proton.Messenger#
+ * @returns {number} zero because JavaScript is fundamentally non-blocking.
+ */
+_Messenger_['getTimeout'] = function() {
+    return 0;
+};
+
+/**
+ * Accessor for messenger blocking mode.
+ * @method isBlocking
+ * @memberof! proton.Messenger#
+ * @returns {boolean} false because JavaScript is fundamentally non-blocking.
+ */
+_Messenger_['isBlocking'] = function() {
+    return false;
+};
+
+/**
+ * Free the Messenger. This will close all connections that are managed
+ * by the Messenger. Call the stop method before destroying the Messenger.
+ * <p>
+ * N.B. This method has to be called explicitly in JavaScript as we can't
+ * intercept finalisers, so we need to remember to free before removing refs.
+ * @method free
+ * @memberof! proton.Messenger#
+ */
+_Messenger_['free'] = function() {
+    // This call ensures that the emscripten network callback functions are removed.
+    Module.EventDispatch.unregisterMessenger(this);
+    _pn_messenger_free(this._messenger);
+};
+
+/**
+ * @method getErrno
+ * @memberof! proton.Messenger#
+ * @returns {number} the most recent error message code.
+ */
+_Messenger_['getErrno'] = function() {
+    return _pn_messenger_errno(this._messenger);
+};
+
+/**
+ * @method getError
+ * @memberof! proton.Messenger#
+ * @returns {string} the most recent error message as a String.
+ */
+_Messenger_['getError'] = function() {
+    return Pointer_stringify(_pn_error_text(_pn_messenger_error(this._messenger)));
+};
+
+/**
+ * Returns the size of the outgoing window that was set with setOutgoingWindow.
+ * The default is 0.
+ * @method getOutgoingWindow
+ * @memberof! proton.Messenger#
+ * @returns {number} the outgoing window size.
+ */
+_Messenger_['getOutgoingWindow'] = function() {
+    return _pn_messenger_get_outgoing_window(this._messenger);
+};
+
+/**
+ * Sets the outgoing tracking window for the Messenger. The Messenger will
+ * track the remote status of this many outgoing deliveries after calling
+ * send. Defaults to zero.
+ * <p>
+ * A Message enters this window when you call put() with the Message.
+ * If your outgoing window size is n, and you call put() n+1 times, status
+ * information will no longer be available for the first Message.
+ * @method setOutgoingWindow
+ * @memberof! proton.Messenger#
+ * @param {number} window the size of the tracking window in messages.
+ */
+_Messenger_['setOutgoingWindow'] = function(window) {
+    this._check(_pn_messenger_set_outgoing_window(this._messenger, window));
+};
+
+/**
+ * Returns the size of the incoming window that was set with setIncomingWindow.
+ * The default is 0.
+ * @method getIncomingWindow
+ * @memberof! proton.Messenger#
+ * @returns {number} the incoming window size.
+ */
+_Messenger_['getIncomingWindow'] = function() {
+    return _pn_messenger_get_incoming_window(this._messenger);
+};
+
+/**
+ * Sets the incoming tracking window for the Messenger. The Messenger will
+ * track the remote status of this many incoming deliveries after calling
+ * send. Defaults to zero.
+ * <p>
+ * Messages enter this window only when you take them into your application
+ * using get(). If your incoming window size is n, and you get() n+1 messages
+ * without explicitly accepting or rejecting the oldest message, then the
+ * Message that passes beyond the edge of the incoming window will be assigned
+ * the default disposition of its link.
+ * @method setIncomingWindow
+ * @memberof! proton.Messenger#
+ * @param {number} window the size of the tracking window in messages.
+ */
+_Messenger_['setIncomingWindow'] = function(window) {
+    this._check(_pn_messenger_set_incoming_window(this._messenger, window));
+};
+
+/**
+ * Currently a no-op placeholder. For future compatibility, do not send or
+ * recv messages before starting the Messenger.
+ * @method start
+ * @memberof! proton.Messenger#
+ */
+_Messenger_['start'] = function() {
+    this._check(_pn_messenger_start(this._messenger));
+};
+
+/**
+ * Transitions the Messenger to an inactive state. An inactive Messenger
+ * will not send or receive messages from its internal queues. A Messenger
+ * should be stopped before being discarded to ensure a clean shutdown
+ * handshake occurs on any internally managed connections.
+ * <p>
+ * The Messenger may require some time to stop if it is busy, and in that
+ * case will return {@link proton.Error.INPROGRESS}. In that case, call isStopped
+ * to see if it has fully stopped.
+ * @method stop
+ * @memberof! proton.Messenger#
+ * @returns {@link proton.Error.INPROGRESS} if still busy.
+ */
+_Messenger_['stop'] = function() {
+    return this._check(_pn_messenger_stop(this._messenger));
+};
+
+/**
+ * Returns true iff a Messenger is in the stopped state.
+ * @method isStopped
+ * @memberof! proton.Messenger#
+ * @returns {boolean} true iff a Messenger is in the stopped state.
+ */
+_Messenger_['isStopped'] = function() {
+    return (_pn_messenger_stopped(this._messenger) > 0);
+};
+
+/**
+ * Subscribes the Messenger to messages originating from the
+ * specified source. The source is an address as specified in the
+ * Messenger introduction with the following addition. If the
+ * domain portion of the address begins with the '~' character, the
+ * Messenger will interpret the domain as host/port, bind to it,
+ * and listen for incoming messages. For example "~0.0.0.0",
+ * "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
+ * local interface and listen for incoming messages with the last
+ * variant only permitting incoming SSL connections.
+ * @method subscribe
+ * @memberof! proton.Messenger#
+ * @param {string} source the source address we're subscribing to.
+ * @returns {Subscription} a subscription.
+ */
+_Messenger_['subscribe'] = function(source) {
+    if (!source) {
+        this._check(Module['Error']['ARG_ERR']);
+    }
+    var sp = Runtime.stackSave();
+    this._checkErrors = true; // TODO improve error handling mechanism.
+    var subscription = _pn_messenger_subscribe(this._messenger,
+                                               allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
+    Runtime.stackRestore(sp);
+
+    if (!subscription) {
+        this._check(Module['Error']['ERR']);
+    }
+
+    subscription = new Subscription(subscription)
+    this._pendingSubscriptions.push(subscription);
+    return subscription;
+};
+
+/**
+ * Places the content contained in the message onto the outgoing queue
+ * of the Messenger. This method will never block, however it will send any
+ * unblocked Messages in the outgoing queue immediately and leave any blocked
+ * Messages remaining in the outgoing queue. The outgoing property may be
+ * used to check the depth of the outgoing queue.
+ * <p>
+ * When the content in a given Message object is copied to the outgoing
+ * message queue, you may then modify or discard the Message object
+ * without having any impact on the content in the outgoing queue.
+ * <p>
+ * This method returns an outgoing tracker for the Message.  The tracker
+ * can be used to determine the delivery status of the Message.
+ * @method put
+ * @memberof! proton.Messenger#
+ * @param {proton.Message} message a Message to send.
+ * @param {boolean} flush if this is set true or is undefined then messages are
+ *        flushed (this is the default). If explicitly set to false then messages
+ *        may not be sent immediately and might require an explicit call to work().
+ *        This may be used to "batch up" messages and *may* be more efficient.
+ * @returns {proton.Data.Long} a tracker.
+ */
+_Messenger_['put'] = function(message, flush) {
+    flush = flush === false ? false : true;
+    message._preEncode();
+    this._checkErrors = true; // TODO improve error handling mechanism.
+    this._check(_pn_messenger_put(this._messenger, message._message));
+
+    // If flush is set invoke pn_messenger_work.
+    if (flush) {
+        _pn_messenger_work(this._messenger, 0);
+    }
+
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var low = _pn_messenger_outgoing_tracker(this._messenger);
+    var high = Runtime.getTempRet0();
+    return new Data.Long(low, high);
+};
+
+/**
+ * Gets the last known remote state of the delivery associated with the given tracker.
+ * @method status
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker whose status is to be retrieved.
+ * @returns {proton.Status} one of None, PENDING, REJECTED, or ACCEPTED.
+ */
+_Messenger_['status'] = function(tracker) {
+    if (tracker == null) {
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+    }
+
+    return _pn_messenger_status(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits());
+};
+
+/**
+ * Checks if the delivery associated with the given tracker is still waiting to be sent.
+ * @method isBuffered
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
+ * @returns {boolean} true if delivery is still buffered.
+ */
+_Messenger_['isBuffered'] = function(tracker) {
+    if (tracker == null) {
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+    }
+
+    return (_pn_messenger_buffered(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits()) > 0);
+};
+
+/**
+ * Frees a Messenger from tracking the status associated with a given tracker.
+ * If you don't supply a tracker, all outgoing messages up to the most recent
+ * will be settled.
+ * @method settle
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
+ */
+_Messenger_['settle'] = function(tracker) {
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var flags = 0;
+    if (tracker == null) {
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+        flags = Module['Messenger'].PN_CUMULATIVE;
+    }
+
+    this._check(_pn_messenger_settle(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
+};
+
+/**
+ * Sends or receives any outstanding messages queued for a Messenger.
+ * For JavaScript the only timeout that makes sense is 0 (do not block).
+ * This method may also do I/O work other than sending and receiving messages.
+ * For example, closing connections after messenger.stop() has been called.
+ * @method work
+ * @memberof! proton.Messenger#
+ * @returns {boolean} true if there is work still to do, false otherwise.
+ */
+_Messenger_['work'] = function() {
+    var err = _pn_messenger_work(this._messenger, 0);
+    if (err === Module['Error']['TIMEOUT']) {
+console.log("work = false");
+        return false;
+    } else {
+        this._checkErrors = false; // TODO improve error handling mechanism.
+        this._check(err);
+console.log("work = true");
+        return true;
+    }
+};
+
+/**
+ * Receives up to limit messages into the incoming queue.  If no value for limit
+ * is supplied, this call will receive as many messages as it can buffer internally.
+ * @method recv
+ * @memberof! proton.Messenger#
+ * @param {number} limit the maximum number of messages to receive or -1 to to receive
+ *        as many messages as it can buffer internally.
+ */
+_Messenger_['recv'] = function(limit) {
+    this._check(_pn_messenger_recv(this._messenger, (limit ? limit : -1)));
+};
+
+/**
+ * Returns the capacity of the incoming message queue of messenger. Note this
+ * count does not include those messages already available on the incoming queue.
+ * @method receiving
+ * @memberof! proton.Messenger#
+ * @returns {number} the message queue capacity.
+ */
+_Messenger_['receiving'] = function() {
+    return _pn_messenger_receiving(this._messenger);
+};
+
+/**
+ * Moves the message from the head of the incoming message queue into the
+ * supplied message object. Any content in the message will be overwritten.
+ * <p>
+ * A tracker for the incoming Message is returned. The tracker can later be
+ * used to communicate your acceptance or rejection of the Message.
+ * @method get
+ * @memberof! proton.Messenger#
+ * @param {proton.Message} message the destination message object. If no Message
+ *        object is supplied, the Message popped from the head of the queue is discarded.
+ * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
+ *        objects as strings. This can be useful as the data in Binary objects
+ *        will be overwritten with subsequent calls to get, so they must be
+ *        explicitly copied. Needless to say it is only safe to set this flag if
+ *        you know that the data you are dealing with is actually a string, for
+ *        example C/C++ applications often seem to encode strings as AMQP binary,
+ *        a common cause of interoperability problems.
+ * @returns {proton.Data.Long} a tracker for the incoming Message.
+ */
+_Messenger_['get'] = function(message, decodeBinaryAsString) {
+    var impl = null;
+    if (message) {
+        impl = message._message;
+    }
+
+    this._check(_pn_messenger_get(this._messenger, impl));
+
+    if (message) {
+        message._postDecode(decodeBinaryAsString);
+    }
+
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var low = _pn_messenger_incoming_tracker(this._messenger);
+    var high = Runtime.getTempRet0();
+
+    return new Data.Long(low, high);
+};
+
+/**
+ * Returns the Subscription of the Message returned by the most recent call
+ * to get, or null if pn_messenger_get has not yet been called.
+ * @method incomingSubscription
+ * @memberof! proton.Messenger#
+ * @returns {Subscription} a Subscription or null if get has never been called
+ *          for this Messenger.
+ */
+_Messenger_['incomingSubscription'] = function() {
+    var subscription = _pn_messenger_incoming_subscription(this._messenger);
+    if (subscription) {
+        return new Subscription(subscription);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Signal the sender that you have acted on the Message pointed to by the tracker.
+ * If no tracker is supplied, then all messages that have been returned by the
+ * get method are accepted, except those that have already been auto-settled
+ * by passing beyond your incoming window size.
+ * @method accept
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
+ */
+_Messenger_['accept'] = function(tracker) {
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var flags = 0;
+    if (tracker == null) {
+        var low = _pn_messenger_incoming_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+        flags = Module['Messenger'].PN_CUMULATIVE;
+    }
+
+    this._check(_pn_messenger_accept(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
+};
+
+/**
+ * Rejects the Message indicated by the tracker.  If no tracker is supplied,
+ * all messages that have been returned by the get method are rejected, except
+ * those already auto-settled by passing beyond your outgoing window size.
+ * @method reject
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
+ */
+_Messenger_['reject'] = function(tracker) {
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var flags = 0;
+    if (tracker == null) {
+        var low = _pn_messenger_incoming_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+        flags = Module['Messenger'].PN_CUMULATIVE;
+    }
+
+    this._check(_pn_messenger_reject(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
+};
+
+/**
+ * Returns the number of messages in the outgoing message queue of a messenger.
+ * @method outgoing
+ * @memberof! proton.Messenger#
+ * @returns {number} the outgoing queue depth.
+ */
+_Messenger_['outgoing'] = function() {
+    return _pn_messenger_outgoing(this._messenger);
+};
+
+/**
+ * Returns the number of messages in the incoming message queue of a messenger.
+ * @method incoming
+ * @memberof! proton.Messenger#
+ * @returns {number} the incoming queue depth.
+ */
+_Messenger_['incoming'] = function() {
+    return _pn_messenger_incoming(this._messenger);
+};
+
+/**
+ * Adds a routing rule to a Messenger's internal routing table.
+ * <p>
+ * The route method may be used to influence how a messenger will internally treat
+ * a given address or class of addresses. Every call to the route method will
+ * result in messenger appending a routing rule to its internal routing table.
+ * <p>
+ * Whenever a message is presented to a messenger for delivery, it will match the
+ * address of this message against the set of routing rules in order. The first
+ * rule to match will be triggered, and instead of routing based on the address
+ * presented in the message, the messenger will route based on the address supplied
+ * in the rule.
+ * <p>
+ * The pattern matching syntax supports two types of matches, a '' will match any
+ * character except a '/', and a '*' will match any character including a '/'.
+ * <p>
+ * A routing address is specified as a normal AMQP address, however it may
+ * additionally use substitution variables from the pattern match that triggered
+ * the rule.
+ * <p>
+ * Any message sent to "foo" will be routed to "amqp://foo.com":
+ * <pre>
+ * route("foo", "amqp://foo.com");
+ * </pre>
+ * Any message sent to "foobar" will be routed to "amqp://foo.com/bar":
+ * <pre>
+ * route("foobar", "amqp://foo.com/bar");
+ * </pre>
+ * Any message sent to bar/<path> will be routed to the corresponding path within
+ * the amqp://bar.com domain:
+ * <pre>
+ * route("bar/*", "amqp://bar.com/$1");
+ * </pre>
+ * Supply credentials for foo.com:
+ * <pre>
+ * route("amqp://foo.com/*", "amqp://user:password@foo.com/$1");
+ * </pre>
+ * Supply credentials for all domains:
+ * <pre>
+ * route("amqp://*", "amqp://user:password@$1");
+ * </pre>
+ * Route all addresses through a single proxy while preserving the original destination:
+ * <pre>
+ * route("amqp://%/*", "amqp://user:password@proxy/$1/$2");
+ * </pre>
+ * Route any address through a single broker:
+ * <pre>
+ * route("*", "amqp://user:password@broker/$1");
+ * </pre>
+ * @method route
+ * @memberof! proton.Messenger#
+ * @param {string} pattern a glob pattern to select messages.
+ * @param {string} address an address indicating outgoing address rewrite.
+ */
+_Messenger_['route'] = function(pattern, address) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_messenger_route(this._messenger,
+                                    allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
+                                    allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Rewrite message addresses prior to transmission.
+ * <p>
+ * Similar to route(), except that the destination of the Message is determined
+ * before the message address is rewritten.
+ * <p>
+ * The outgoing address is only rewritten after routing has been finalized. If
+ * a message has an outgoing address of "amqp://0.0.0.0:5678", and a rewriting
+ * rule that changes its outgoing address to "foo", it will still arrive at the
+ * peer that is listening on "amqp://0.0.0.0:5678", but when it arrives there,
+ * the receiver will see its outgoing address as "foo".
+ * <p>
+ * The default rewrite rule removes username and password from addresses
+ * before they are transmitted.
+ * @method rewrite
+ * @memberof! proton.Messenger#
+ * @param {string} pattern a glob pattern to select messages.
+ * @param {string} address an address indicating outgoing address rewrite.
+ */
+_Messenger_['rewrite'] = function(pattern, address) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_messenger_rewrite(this._messenger,
+                                      allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
+                                      allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/module.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/module.js b/proton-c/bindings/javascript/module.js
new file mode 100644
index 0000000..0fdb803
--- /dev/null
+++ b/proton-c/bindings/javascript/module.js
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * This file provides a JavaScript wrapper around the Proton Messenger API.
+ * It will be used to wrap the emscripten compiled proton-c code and be minified by
+ * the Closure compiler, so all comments will be stripped from the actual library.
+ * <p>
+ * This JavaScript wrapper provides a somewhat more idiomatic object oriented
+ * interface which abstracts the low-level emscripten based implementation details
+ * from client code. Any similarities to the Proton Python binding are deliberate.
+ * @file
+ */
+
+/**
+ * The Module Object is exported by emscripten for all execution platforms, we
+ * use it as a namespace to allow us to selectively export only what we wish to
+ * be publicly visible from this package/module.
+ * <p>
+ * Internally the binding code uses the associative array form for declaring
+ * exported properties to prevent the Closure compiler from minifying e.g.
+ * <pre>Module['Messenger'] = ...</pre>
+ * Exported Objects can be used in client code using a more convenient namespace, e.g.:
+ * <pre>
+ * proton = require('qpid-proton');
+ * var messenger = new proton.Messenger();
+ * var message = new proton.Message();
+ * </pre>
+ * @namespace proton
+ */
+
+var Module = {
+    // Prevent emscripten runtime exiting, we will be enabling network callbacks.
+    'noExitRuntime' : true,
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                               EventDispatch                               */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * EventDispatch is a Singleton class that allows callbacks to be registered which
+ * will get triggered by the emscripten WebSocket network callbacks. Clients of
+ * Messenger will register callbacks by calling:
+ * <pre>
+ * messenger.on('work', &lt;callback function&gt;);
+ * </pre>
+ * EventDispatch supports callback registration from multiple Messenger instances.
+ * The client callbacks will actually be called when a given messenger has work
+ * available or a WebSocket close has been occurred (in which case all registered
+ * callbacks will be called).
+ * <p>
+ * The approach implemented here allows the registered callbacks to follow a
+ * similar pattern to _process_incoming and _process_outgoing in async.py
+ * @memberof proton
+ */
+Module.EventDispatch = new function() { // Note the use of new to create a Singleton.
+    var _firstCall = true; // Flag used to check the first time registerMessenger is called.
+    var _messengers = {};
+
+    /**
+     * Provides functionality roughly equivalent to the following C code:
+     * while (1) {
+     *     pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
+     *     process();
+     * }
+     * The blocking call isn't viable in JavaScript as it is entirely asynchronous
+     * and we wouldn't want to replace the while(1) with a timed loop either!!
+     * This method gets triggered asynchronously by the emscripten socket events and
+     * we then perform an equivalent loop for each messenger, triggering every
+     * registered callback whilst there is work remaining. If triggered by close
+     * we bypass the _pn_messenger_work test as it will never succeed after closing.
+     */
+    var _pump = function(fd, closing) {
+        for (var i in _messengers) {
+            if (_messengers.hasOwnProperty(i)) {
+                var messenger = _messengers[i];
+
+                if (closing) {
+                    messenger._emit('work');
+                } else {
+                    while (_pn_messenger_work(messenger._messenger, 0) >= 0) {
+                        messenger._checkSubscriptions();
+                        messenger._checkErrors = false; // TODO improve error handling mechanism.
+                        messenger._emit('work');
+                    }
+                }
+            }
+        }
+    };
+
+    /**
+     * Listener for the emscripten socket close event. Delegates to _pump()
+     * passing a flag to indicate that the socket is closing.
+     */
+    var _close = function(fd) {
+        _pump(fd, true);
+    };
+
+    /**
+     * Register the specified Messenger as being interested in network events.
+     */
+    this.registerMessenger = function(messenger) {
+        if (_firstCall) {
+            /**
+             * Initialises the emscripten network callback functions. This needs
+             * to be done the first time we call registerMessenger rather than
+             * when we create the Singleton because emscripten's socket filesystem
+             * has to be mounted before can listen for any of these events.
+             */
+            Module['websocket']['on']('open', _pump);
+            Module['websocket']['on']('connection', _pump);
+            Module['websocket']['on']('message', _pump);
+            Module['websocket']['on']('close', _close);
+            _firstCall = false;
+        }
+
+        var name = messenger.getName();
+        _messengers[name] = messenger; 
+    };
+
+    /**
+     * Unregister the specified Messenger from interest in network events.
+     */
+    this.unregisterMessenger = function(messenger) {
+        var name = messenger.getName();
+        delete _messengers[name];
+    };
+};
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/subscription.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/subscription.js b/proton-c/bindings/javascript/subscription.js
new file mode 100644
index 0000000..83ede80
--- /dev/null
+++ b/proton-c/bindings/javascript/subscription.js
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                               Subscription                                */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a Subscription instance.
+ * @classdesc This class is a wrapper for Messenger's subscriptions.
+ * Subscriptions should never be *directly* instantiated by client code only via
+ * Messenger.subscribe() or Messenger.incomingSubscription(), so we declare the
+ * constructor in the scope of the package and don't export it via Module.
+ * @constructor Subscription                                                              
+ */
+var Subscription = function(subscription) { // Subscription Constructor.
+    this._subscription = subscription;
+};
+
+/**
+ * TODO Not sure exactly what pn_subscription_get_context does.
+ * @method getContext
+ * @memberof! Subscription#
+ * @returns the Subscription's Context.
+ */
+Subscription.prototype['getContext'] = function() {
+    return _pn_subscription_get_context(this._subscription);
+};
+
+/**
+ * TODO Not sure exactly what pn_subscription_set_context does.
+ * @method setContext
+ * @memberof! Subscription#
+ * @param context the Subscription's new Context.
+ */
+Subscription.prototype['setContext'] = function(context) {
+    _pn_subscription_set_context(this._subscription, context);
+};
+
+/**
+ * @method getAddress
+ * @memberof! Subscription#
+ * @returns the Subscription's Address.
+ */
+Subscription.prototype['getAddress'] = function() {
+    return Pointer_stringify(_pn_subscription_address(this._subscription));
+};
+


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


[19/51] [abbrv] qpid-proton git commit: Update with merge of latest proton codebase and checked against latest emscripten incoming branch

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactoryImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactoryImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactoryImpl.java
deleted file mode 100644
index 4238a6a..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactoryImpl.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton;
-
-public class ProtonFactoryImpl implements ProtonFactory
-{
-    @Override
-    public final ImplementationType getImplementationType()
-    {
-        return ImplementationType.PROTON_J;
-    }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactoryLoader.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactoryLoader.java b/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactoryLoader.java
deleted file mode 100644
index 9ce1ad9..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactoryLoader.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton;
-
-import java.util.Iterator;
-import java.util.ServiceLoader;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.apache.qpid.proton.ProtonFactory.ImplementationType;
-
-/**
- * A thin wrapper around {@link ServiceLoader} intended for loading Proton object factories.
- *
- * If system property {@value #IMPLEMENTATION_TYPE_PROPERTY} if set, loads a factory
- * whose {@link ImplementationType} matches its value.
- */
-public class ProtonFactoryLoader<C extends ProtonFactory>
-{
-    public static final String IMPLEMENTATION_TYPE_PROPERTY = "qpid.proton.implementationtype";
-
-    private static final Logger LOGGER = Logger.getLogger(ProtonFactoryLoader.class.getName());
-    private final Class<C> _factoryInterface;
-    private final ImplementationType _implementationType;
-
-    /**
-     * Use this constructor if you intend to explicitly provide factory interface later,
-     * i.e. by calling {@link #loadFactory(Class)}. This is useful if you want to use the same
-     * ProtonFactoryLoader instance for loading multiple factory types.
-     */
-    public ProtonFactoryLoader()
-    {
-        this(null);
-    }
-
-    public ProtonFactoryLoader(Class<C> factoryInterface)
-    {
-        this(factoryInterface, getImpliedImplementationType());
-    }
-
-    static ImplementationType getImpliedImplementationType()
-    {
-        String implementationTypeFromSystemProperty = System.getProperty(IMPLEMENTATION_TYPE_PROPERTY);
-        if(implementationTypeFromSystemProperty != null)
-        {
-            return ImplementationType.valueOf(implementationTypeFromSystemProperty);
-        }
-        else
-        {
-            return ImplementationType.ANY;
-        }
-    }
-
-    /**
-     * @param factoryInterface will be used as the factory interface class in calls to {@link #loadFactory()}.
-     */
-    public ProtonFactoryLoader(Class<C> factoryInterface, ImplementationType implementationType)
-    {
-        _factoryInterface = factoryInterface;
-        _implementationType = implementationType;
-    }
-
-    /**
-     * Returns the Proton factory that implements the stored {@link ProtonFactoryLoader#_factoryInterface} class.
-     */
-    public C loadFactory()
-    {
-        return loadFactory(_factoryInterface);
-    }
-
-    public C loadFactory(Class<C> factoryInterface)
-    {
-        if(factoryInterface == null)
-        {
-            throw new IllegalStateException("factoryInterface has not been set.");
-        }
-        ServiceLoader<C> serviceLoader = ServiceLoader.load(factoryInterface);
-        Iterator<C> serviceLoaderIterator = serviceLoader.iterator();
-        while(serviceLoaderIterator.hasNext())
-        {
-            C factory = serviceLoaderIterator.next();
-            if(_implementationType == ImplementationType.ANY || factory.getImplementationType() == _implementationType)
-            {
-                if(LOGGER.isLoggable(Level.FINE))
-                {
-                    LOGGER.fine("loadFactory returning " + factory + " for loader's implementation type " + _implementationType);
-                }
-                return factory;
-            }
-        }
-        throw new IllegalStateException("Can't find service loader for " + factoryInterface.getName() +
-                                        " for implementation type " + _implementationType);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/DeliveryAnnotations.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/DeliveryAnnotations.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/DeliveryAnnotations.java
index 8472c04..9ea5504 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/DeliveryAnnotations.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/DeliveryAnnotations.java
@@ -25,17 +25,18 @@ package org.apache.qpid.proton.amqp.messaging;
 
 import java.util.Map;
 
-public final class DeliveryAnnotations
-      implements Section
+import org.apache.qpid.proton.amqp.Symbol;
+
+public final class DeliveryAnnotations implements Section
 {
-    private final Map _value;
+    private final Map<Symbol, Object> _value;
 
-    public DeliveryAnnotations(Map value)
+    public DeliveryAnnotations(Map<Symbol, Object> value)
     {
         _value = value;
     }
 
-    public Map getValue()
+    public Map<Symbol, Object> getValue()
     {
         return _value;
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/MessageAnnotations.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/MessageAnnotations.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/MessageAnnotations.java
index 925093a..9bf82d6 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/MessageAnnotations.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/MessageAnnotations.java
@@ -23,20 +23,22 @@
 
 package org.apache.qpid.proton.amqp.messaging;
 
+import org.apache.qpid.proton.amqp.Symbol;
+
 import java.util.Map;
 
 
 public final class MessageAnnotations implements Section
 {
 
-    private final Map _value;
+    private final Map<Symbol, Object> _value;
 
-    public MessageAnnotations(Map value)
+    public MessageAnnotations(Map<Symbol, Object> value)
     {
         _value = value;
     }
 
-    public Map getValue()
+    public Map<Symbol, Object> getValue()
     {
         return _value;
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/codec/Codec.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/Codec.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/Codec.java
new file mode 100644
index 0000000..1aa2143
--- /dev/null
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/Codec.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.proton.codec;
+
+/**
+ * Codec
+ *
+ */
+
+public final class Codec
+{
+
+    private Codec()
+    {
+    }
+
+    public static Data data(long capacity)
+    {
+        return Data.Factory.create();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/codec/Data.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/Data.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/Data.java
index 1252542..4f42488 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/Data.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/Data.java
@@ -37,9 +37,19 @@ import org.apache.qpid.proton.amqp.UnsignedInteger;
 import org.apache.qpid.proton.amqp.UnsignedLong;
 import org.apache.qpid.proton.amqp.UnsignedShort;
 
+import org.apache.qpid.proton.codec.impl.DataImpl;
+
 public interface Data
 {
 
+    public static final class Factory {
+
+        public static Data create() {
+            return new DataImpl();
+        }
+
+    }
+
 
     enum DataType
     {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/codec/DataFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/DataFactory.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/DataFactory.java
deleted file mode 100644
index 5a622e0..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/DataFactory.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.proton.codec;
-
-import org.apache.qpid.proton.ProtonFactory;
-
-public interface DataFactory extends ProtonFactory
-{
-    Data createData(long capacity);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/DataFactoryImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/DataFactoryImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/DataFactoryImpl.java
deleted file mode 100644
index 480e7a0..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/DataFactoryImpl.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.proton.codec.impl;
-
-import org.apache.qpid.proton.ProtonFactoryImpl;
-import org.apache.qpid.proton.ProtonUnsupportedOperationException;
-import org.apache.qpid.proton.codec.Data;
-import org.apache.qpid.proton.codec.DataFactory;
-
-public class DataFactoryImpl extends ProtonFactoryImpl implements DataFactory
-{
-    @Override
-    public Data createData(final long capacity)
-    {
-        return new DataImpl();
-    }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java
index c9eeeb3..2564f05 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java
@@ -21,8 +21,10 @@
 
 package org.apache.qpid.proton.driver;
 
+import java.io.IOException;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.ServerSocketChannel;
+import org.apache.qpid.proton.driver.impl.DriverImpl;
 
 /**
  * A driver for the proton engine.
@@ -40,6 +42,14 @@ import java.nio.channels.ServerSocketChannel;
  */
 public interface Driver
 {
+
+    public static final class Factory
+    {
+        public static Driver create() throws IOException {
+            return new DriverImpl();
+        }
+    }
+
     /**
      * Force {@link #doWait(long)} to return.
      *

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/driver/DriverFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/DriverFactory.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/DriverFactory.java
deleted file mode 100644
index c78779c..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/DriverFactory.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.proton.driver;
-
-import java.io.IOException;
-
-import org.apache.qpid.proton.ProtonFactory;
-
-public interface DriverFactory extends ProtonFactory
-{
-    Driver createDriver() throws IOException;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java
index e98317c..e3e43c4 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java
@@ -32,7 +32,6 @@ import org.apache.qpid.proton.engine.Connection;
 import org.apache.qpid.proton.engine.Sasl;
 import org.apache.qpid.proton.engine.Transport;
 import org.apache.qpid.proton.engine.TransportException;
-import org.apache.qpid.proton.engine.impl.TransportFactory;
 
 class ConnectorImpl<C> implements Connector<C>
 {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverFactoryImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverFactoryImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverFactoryImpl.java
deleted file mode 100644
index 45db9c8..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverFactoryImpl.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.proton.driver.impl;
-
-import java.io.IOException;
-
-import org.apache.qpid.proton.ProtonFactoryImpl;
-import org.apache.qpid.proton.driver.Driver;
-import org.apache.qpid.proton.driver.DriverFactory;
-
-public class DriverFactoryImpl extends ProtonFactoryImpl implements DriverFactory
-{
-    @Override
-    public Driver createDriver() throws IOException
-    {
-        return new DriverImpl();
-    }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
index ade992e..bfdd017 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
@@ -53,7 +53,7 @@ public class DriverImpl implements Driver
     private Queue<ConnectorImpl> _selectedConnectors = new ArrayDeque<ConnectorImpl>();
     private Queue<ListenerImpl> _selectedListeners = new ArrayDeque<ListenerImpl>();
 
-    DriverImpl() throws IOException
+    public DriverImpl() throws IOException
     {
         _selector = Selector.open();
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/Collector.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Collector.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Collector.java
index c2c9765..f9e6fe5 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Collector.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Collector.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.proton.engine;
 
+import org.apache.qpid.proton.engine.impl.CollectorImpl;
 
 /**
  * Collector
@@ -29,6 +30,13 @@ package org.apache.qpid.proton.engine;
 public interface Collector
 {
 
+    public static final class Factory
+    {
+        public static Collector create() {
+            return new CollectorImpl();
+        }
+    }
+
     Event peek();
 
     void pop();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/Connection.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Connection.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Connection.java
index 3df17cf..5fe66d5 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Connection.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Connection.java
@@ -24,6 +24,8 @@ import java.util.EnumSet;
 import java.util.Map;
 import org.apache.qpid.proton.amqp.Symbol;
 
+import org.apache.qpid.proton.engine.impl.ConnectionImpl;
+
 
 /**
  * Maintains lists of sessions, links and deliveries in a state
@@ -36,6 +38,13 @@ import org.apache.qpid.proton.amqp.Symbol;
 public interface Connection extends Endpoint
 {
 
+    public static final class Factory
+    {
+        public static Connection create() {
+            return new ConnectionImpl();
+        }
+    }
+
     /**
      * Returns a newly created session
      *
@@ -81,6 +90,8 @@ public interface Connection extends Endpoint
 
     public void setHostname(String hostname);
 
+    public String getHostname();
+
     public String getRemoteContainer();
 
     public String getRemoteHostname();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/Engine.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Engine.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Engine.java
new file mode 100644
index 0000000..3bd46ce
--- /dev/null
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Engine.java
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.proton.engine;
+
+/**
+ * Engine
+ *
+ */
+
+public final class Engine
+{
+
+    private Engine()
+    {
+    }
+
+    public static Collector collector()
+    {
+        return Collector.Factory.create();
+    }
+
+    public static Connection connection()
+    {
+        return Connection.Factory.create();
+    }
+
+    public static Transport transport()
+    {
+        return Transport.Factory.create();
+    }
+
+    public static SslDomain sslDomain()
+    {
+        return SslDomain.Factory.create();
+    }
+
+    public static SslPeerDetails sslPeerDetails(String hostname, int port)
+    {
+        return SslPeerDetails.Factory.create(hostname, port);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/EngineFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/EngineFactory.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/EngineFactory.java
deleted file mode 100644
index 5cb3ce9..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/EngineFactory.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton.engine;
-
-import org.apache.qpid.proton.ProtonFactory;
-
-public interface EngineFactory extends ProtonFactory
-{
-    Connection createConnection();
-    Transport createTransport();
-    SslDomain createSslDomain();
-    SslPeerDetails createSslPeerDetails(String hostname, int port);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
index 14c0dc7..75ba56c 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
@@ -29,19 +29,38 @@ package org.apache.qpid.proton.engine;
 public interface Event
 {
     public enum Category {
-        PROTOCOL;
+        CONNECTION,
+        SESSION,
+        LINK,
+        DELIVERY,
+        TRANSPORT;
     }
 
     public enum Type {
-        CONNECTION_REMOTE_STATE(Category.PROTOCOL, 1),
-        CONNECTION_LOCAL_STATE(Category.PROTOCOL, 2),
-        SESSION_REMOTE_STATE(Category.PROTOCOL, 3),
-        SESSION_LOCAL_STATE(Category.PROTOCOL, 4),
-        LINK_REMOTE_STATE(Category.PROTOCOL, 5),
-        LINK_LOCAL_STATE(Category.PROTOCOL, 6),
-        LINK_FLOW(Category.PROTOCOL, 7),
-        DELIVERY(Category.PROTOCOL, 8),
-        TRANSPORT(Category.PROTOCOL, 9);
+        CONNECTION_INIT(Category.CONNECTION, 1),
+        CONNECTION_OPEN(Category.CONNECTION, 2),
+        CONNECTION_REMOTE_OPEN(Category.CONNECTION, 3),
+        CONNECTION_CLOSE(Category.CONNECTION, 4),
+        CONNECTION_REMOTE_CLOSE(Category.CONNECTION, 5),
+        CONNECTION_FINAL(Category.CONNECTION, 6),
+
+        SESSION_INIT(Category.SESSION, 1),
+        SESSION_OPEN(Category.SESSION, 2),
+        SESSION_REMOTE_OPEN(Category.SESSION, 3),
+        SESSION_CLOSE(Category.SESSION, 4),
+        SESSION_REMOTE_CLOSE(Category.SESSION, 5),
+        SESSION_FINAL(Category.SESSION, 6),
+
+        LINK_INIT(Category.LINK, 1),
+        LINK_OPEN(Category.LINK, 2),
+        LINK_REMOTE_OPEN(Category.LINK, 3),
+        LINK_CLOSE(Category.LINK, 4),
+        LINK_REMOTE_CLOSE(Category.LINK, 5),
+        LINK_FLOW(Category.LINK, 6),
+        LINK_FINAL(Category.LINK, 7),
+
+        DELIVERY(Category.DELIVERY, 1),
+        TRANSPORT(Category.TRANSPORT, 1);
 
         private int _opcode;
         private Category _category;
@@ -72,4 +91,6 @@ public interface Event
 
     Transport getTransport();
 
+    Event copy();
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/Sasl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Sasl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Sasl.java
index d4b74fc..dd63321 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Sasl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Sasl.java
@@ -49,7 +49,8 @@ public interface Sasl
         PN_SASL_SYS((byte)2),
         /** failed due to unrecoverable error */
         PN_SASL_PERM((byte)3),
-        PN_SASL_TEMP((byte)4);
+        PN_SASL_TEMP((byte)4),
+        PN_SASL_SKIPPED((byte)5);
 
         private final byte _code;
 
@@ -72,6 +73,7 @@ public interface Sasl
     public static SaslOutcome PN_SASL_SYS = SaslOutcome.PN_SASL_SYS;
     public static SaslOutcome PN_SASL_PERM = SaslOutcome.PN_SASL_PERM;
     public static SaslOutcome PN_SASL_TEMP = SaslOutcome.PN_SASL_TEMP;
+    public static SaslOutcome PN_SASL_SKIPPED = SaslOutcome.PN_SASL_SKIPPED;
 
     /**
      * Access the current state of the layer.
@@ -156,4 +158,10 @@ public interface Sasl
 
     void client();
     void server();
+
+    /**
+     * Set whether servers may accept incoming connections
+     * that skip the SASL layer negotiation.
+     */
+    void allowSkip(boolean allowSkip);
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java
index 937d650..a908824 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java
@@ -18,11 +18,21 @@
  */
 package org.apache.qpid.proton.engine;
 
+import org.apache.qpid.proton.engine.impl.ssl.SslDomainImpl;
+
 /**
  * I store the details used to create SSL sessions.
  */
 public interface SslDomain
 {
+
+    public static final class Factory
+    {
+        public static SslDomain create() {
+            return new SslDomainImpl();
+        }
+    }
+
     /**
      * Determines whether the endpoint acts as a client or server.
      */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/SslPeerDetails.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/SslPeerDetails.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/SslPeerDetails.java
index 884fdae..5b318fe 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/SslPeerDetails.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/SslPeerDetails.java
@@ -18,6 +18,8 @@
  */
 package org.apache.qpid.proton.engine;
 
+import org.apache.qpid.proton.engine.impl.ssl.SslPeerDetailsImpl;
+
 /**
  * The details of the remote peer involved in an SSL session.
  *
@@ -28,6 +30,14 @@ package org.apache.qpid.proton.engine;
  */
 public interface SslPeerDetails
 {
+
+    public static final class Factory
+    {
+        public static SslPeerDetails create(String hostname, int port) {
+            return new SslPeerDetailsImpl(hostname, port);
+        }
+    }
+
     String getHostname();
     int getPort();
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java
index 53da131..ba806bd 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java
@@ -22,6 +22,8 @@ package org.apache.qpid.proton.engine;
 
 import java.nio.ByteBuffer;
 
+import org.apache.qpid.proton.engine.impl.TransportImpl;
+
 
 /**
  * <p>
@@ -63,6 +65,19 @@ import java.nio.ByteBuffer;
  */
 public interface Transport extends Endpoint
 {
+
+    public static final class Factory
+    {
+        public static Transport create() {
+            return new TransportImpl();
+        }
+    }
+
+    public static final int TRACE_OFF = 0;
+    public static final int TRACE_RAW = 1;
+    public static final int TRACE_FRM = 2;
+    public static final int TRACE_DRV = 4;
+
     public static final int DEFAULT_MAX_FRAME_SIZE = -1;
 
     /** the lower bound for the agreed maximum frame size (in bytes). */
@@ -70,7 +85,10 @@ public interface Transport extends Endpoint
     public int SESSION_WINDOW = 16*1024;
     public int END_OF_STREAM = -1;
 
+    public void trace(int levels);
+
     public void bind(Connection connection);
+    public void unbind();
 
     public int capacity();
     public ByteBuffer tail();
@@ -83,6 +101,8 @@ public interface Transport extends Endpoint
     public void pop(int bytes);
     public void close_head();
 
+    public boolean isClosed();
+
     /**
      * Processes the provided input.
      *
@@ -156,7 +176,15 @@ public interface Transport extends Endpoint
      */
     void outputConsumed();
 
-    Sasl sasl();
+    /**
+     * Signal the transport to expect SASL frames used to establish a SASL layer prior to
+     * performing the AMQP protocol version negotiation. This must first be performed before
+     * the transport is used for processing. Subsequent invocations will return the same
+     * {@link Sasl} object.
+     *
+     * @throws IllegalStateException if transport processing has already begun prior to initial invocation
+     */
+    Sasl sasl() throws IllegalStateException;
 
     /**
      * Wrap this transport's output and input to apply SSL encryption and decryption respectively.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/CollectorImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/CollectorImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/CollectorImpl.java
index 344597c..e222819 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/CollectorImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/CollectorImpl.java
@@ -35,25 +35,55 @@ import java.util.Queue;
 public class CollectorImpl implements Collector
 {
 
-    private Queue<Event> events = new LinkedList<Event>();
+    private EventImpl head;
+    private EventImpl tail;
+    private EventImpl free;
 
     public CollectorImpl()
     {}
 
     public Event peek()
     {
-        return events.peek();
+        return head;
     }
 
     public void pop()
     {
-        events.poll();
+        if (head != null) {
+            EventImpl next = head.next;
+            head.next = free;
+            free = head;
+            head.clear();
+            head = next;
+        }
     }
 
-    public EventImpl put(Event.Type type)
+    public EventImpl put(Event.Type type, Object context)
     {
-        EventImpl event = new EventImpl(type);
-        events.add(event);
+        if (tail != null && tail.getType() == type &&
+            tail.getContext() == context) {
+            return null;
+        }
+
+        EventImpl event;
+        if (free == null) {
+            event = new EventImpl();
+        } else {
+            event = free;
+            free = free.next;
+            event.next = null;
+        }
+
+        event.init(type, context);
+
+        if (head == null) {
+            head = event;
+            tail = event;
+        } else {
+            tail.next = event;
+            tail = event;
+        }
+
         return event;
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
index 6a27103..736d93c 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
@@ -52,6 +52,7 @@ public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
     private TransportImpl _transport;
     private DeliveryImpl _transportWorkHead;
     private DeliveryImpl _transportWorkTail;
+    private int _transportWorkSize = 0;
     private String _localContainerId = "";
     private String _localHostname = "";
     private String _remoteContainer;
@@ -182,16 +183,30 @@ public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
         return this;
     }
 
-    public void free()
-    {
-        super.free();
-        for(Session session : _sessions)
-        {
+    @Override
+    void postFinal() {
+        put(Event.Type.CONNECTION_FINAL, this);
+    }
+
+    @Override
+    void doFree() {
+        for(Session session : _sessions) {
             session.free();
         }
         _sessions = null;
     }
 
+    void modifyEndpoints() {
+        if (_sessions != null) {
+            for (SessionImpl ssn: _sessions) {
+                ssn.modifyEndpoints();
+            }
+        }
+        if (!freed) {
+            modified();
+        }
+    }
+
     void handleOpen(Open open)
     {
         // TODO - store state
@@ -201,10 +216,7 @@ public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
         setRemoteDesiredCapabilities(open.getDesiredCapabilities());
         setRemoteOfferedCapabilities(open.getOfferedCapabilities());
         setRemoteProperties(open.getProperties());
-        EventImpl ev = put(Event.Type.CONNECTION_REMOTE_STATE);
-        if (ev != null) {
-            ev.init(this);
-        }
+        put(Event.Type.CONNECTION_REMOTE_OPEN, this);
     }
 
 
@@ -489,6 +501,10 @@ public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
         return _transportWorkHead;
     }
 
+    int getTransportWorkSize() {
+        return _transportWorkSize;
+    }
+
     public void removeTransportWork(DeliveryImpl delivery)
     {
         if (!delivery._transportWork) return;
@@ -517,6 +533,7 @@ public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
         }
 
         delivery._transportWork = false;
+        _transportWorkSize--;
     }
 
     void addTransportWork(DeliveryImpl delivery)
@@ -538,6 +555,7 @@ public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
         }
 
         delivery._transportWork = true;
+        _transportWorkSize++;
     }
 
     void workUpdate(DeliveryImpl delivery)
@@ -571,23 +589,40 @@ public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
     public void collect(Collector collector)
     {
         _collector = (CollectorImpl) collector;
+
+        put(Event.Type.CONNECTION_INIT, this);
+
+        LinkNode<SessionImpl> ssn = _sessionHead;
+        while (ssn != null) {
+            put(Event.Type.SESSION_INIT, ssn.getValue());
+            ssn = ssn.getNext();
+        }
+
+        LinkNode<LinkImpl> lnk = _linkHead;
+        while (lnk != null) {
+            put(Event.Type.LINK_INIT, lnk.getValue());
+            lnk = lnk.getNext();
+        }
     }
 
-    EventImpl put(Event.Type type)
+    EventImpl put(Event.Type type, Object context)
     {
         if (_collector != null) {
-            return _collector.put(type);
+            return _collector.put(type, context);
         } else {
             return null;
         }
     }
 
     @Override
-    protected void localStateChanged()
+    void localOpen()
     {
-        EventImpl ev = put(Event.Type.CONNECTION_LOCAL_STATE);
-        if (ev != null) {
-            ev.init(this);
-        }
+        put(Event.Type.CONNECTION_OPEN, this);
+    }
+
+    @Override
+    void localClose()
+    {
+        put(Event.Type.CONNECTION_CLOSE, this);
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
index 72ae1a6..b97793a 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
@@ -37,7 +37,27 @@ public abstract class EndpointImpl implements ProtonJEndpoint
     private EndpointImpl _transportPrev;
     private Object _context;
 
-    protected abstract void localStateChanged();
+    private int refcount = 1;
+    boolean freed = false;
+
+    void incref() {
+        refcount++;
+    }
+
+    void decref() {
+        refcount--;
+        if (refcount == 0) {
+            postFinal();
+        } else if (refcount < 0) {
+            throw new IllegalStateException();
+        }
+    }
+
+    abstract void postFinal();
+
+    abstract void localOpen();
+
+    abstract void localClose();
 
     public void open()
     {
@@ -49,7 +69,7 @@ public abstract class EndpointImpl implements ProtonJEndpoint
                 // TODO
             case UNINITIALIZED:
                 _localState = EndpointState.ACTIVE;
-                localStateChanged();
+                localOpen();
         }
         modified();
     }
@@ -65,7 +85,7 @@ public abstract class EndpointImpl implements ProtonJEndpoint
                 // TODO
             case ACTIVE:
                 _localState = EndpointState.CLOSED;
-                localStateChanged();
+                localClose();
         }
         modified();
     }
@@ -129,9 +149,9 @@ public abstract class EndpointImpl implements ProtonJEndpoint
 
         if (emit) {
             ConnectionImpl conn = getConnectionImpl();
-            EventImpl ev = conn.put(Event.Type.TRANSPORT);
-            if (ev != null) {
-                ev.init(conn);
+            TransportImpl trans = conn.getTransport();
+            if (trans != null) {
+                conn.put(Event.Type.TRANSPORT, trans);
             }
         }
     }
@@ -162,16 +182,15 @@ public abstract class EndpointImpl implements ProtonJEndpoint
         return _transportPrev;
     }
 
-    public void free()
+    abstract void doFree();
+
+    final public void free()
     {
-        if(_transportNext != null)
-        {
-            _transportNext.setTransportPrev(_transportPrev);
-        }
-        if(_transportPrev != null)
-        {
-            _transportPrev.setTransportNext(_transportNext);
-        }
+        if (freed) return;
+        freed = true;
+
+        doFree();
+        decref();
     }
 
     void setTransportNext(EndpointImpl transportNext)
@@ -194,9 +213,4 @@ public abstract class EndpointImpl implements ProtonJEndpoint
         _context = context;
     }
 
-    @Override
-    public String toString()
-    {
-        return "EndpointImpl(" + System.identityHashCode(this) + ") [_localState=" + _localState + ", _remoteState=" + _remoteState + ", _localError=" + _localError + ", _remoteError=" + _remoteError + "]";
-    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EngineFactoryImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EngineFactoryImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EngineFactoryImpl.java
deleted file mode 100644
index 8ce9bba..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EngineFactoryImpl.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton.engine.impl;
-
-import org.apache.qpid.proton.ProtonFactoryImpl;
-import org.apache.qpid.proton.engine.EngineFactory;
-import org.apache.qpid.proton.engine.ProtonJConnection;
-import org.apache.qpid.proton.engine.ProtonJSslDomain;
-import org.apache.qpid.proton.engine.ProtonJSslPeerDetails;
-import org.apache.qpid.proton.engine.ProtonJTransport;
-import org.apache.qpid.proton.engine.impl.ssl.SslDomainImpl;
-import org.apache.qpid.proton.engine.impl.ssl.SslPeerDetailsImpl;
-
-public class EngineFactoryImpl extends ProtonFactoryImpl implements EngineFactory
-{
-    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
-    @Override
-    public ProtonJConnection createConnection()
-    {
-        return new ConnectionImpl();
-    }
-
-    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
-    @Override
-    public ProtonJTransport createTransport()
-    {
-        return new TransportImpl();
-    }
-
-    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
-    @Override
-    public ProtonJSslDomain createSslDomain()
-    {
-        return new SslDomainImpl();
-    }
-
-    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
-    @Override
-    public ProtonJSslPeerDetails createSslPeerDetails(String hostname, int port)
-    {
-        return new SslPeerDetailsImpl(hostname, port);
-    }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
index 7d57909..1dcebe4 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
@@ -36,15 +36,24 @@ class EventImpl implements Event
 {
 
     Type type;
-    Connection connection;
-    Session session;
-    Link link;
-    Delivery delivery;
-    Transport transport;
+    Object context;
+    EventImpl next;
 
-    EventImpl(Type type)
+    EventImpl()
+    {
+        this.type = null;
+    }
+
+    void init(Event.Type type, Object context)
     {
         this.type = type;
+        this.context = context;
+    }
+
+    void clear()
+    {
+        type = null;
+        context = null;
     }
 
     public Category getCategory()
@@ -57,58 +66,88 @@ class EventImpl implements Event
         return type;
     }
 
+    public Object getContext()
+    {
+        return context;
+    }
+
     public Connection getConnection()
     {
-        return connection;
+        switch (type.getCategory()) {
+        case CONNECTION:
+            return (Connection) context;
+        case TRANSPORT:
+            Transport transport = getTransport();
+            if (transport == null) {
+                return null;
+            }
+            return ((TransportImpl) transport).getConnectionImpl();
+        default:
+            Session ssn = getSession();
+            if (ssn == null) {
+                return null;
+            }
+            return ssn.getConnection();
+        }
     }
 
     public Session getSession()
     {
-        return session;
+        switch (type.getCategory()) {
+        case SESSION:
+            return (Session) context;
+        default:
+            Link link = getLink();
+            if (link == null) {
+                return null;
+            }
+            return link.getSession();
+        }
     }
 
     public Link getLink()
     {
-        return link;
+        switch (type.getCategory()) {
+        case LINK:
+            return (Link) context;
+        default:
+            Delivery dlv = getDelivery();
+            if (dlv == null) {
+                return null;
+            }
+            return dlv.getLink();
+        }
     }
 
     public Delivery getDelivery()
     {
-        return delivery;
+        switch (type.getCategory()) {
+        case DELIVERY:
+            return (Delivery) context;
+        default:
+            return null;
+        }
     }
 
     public Transport getTransport()
     {
-        return transport;
-    }
-
-    void init(Transport transport)
-    {
-        this.transport = transport;
-    }
-
-    void init(Connection connection)
-    {
-        this.connection = connection;
-        init(((ConnectionImpl) connection).getTransport());
+        switch (type.getCategory()) {
+        case TRANSPORT:
+            return (Transport) context;
+        default:
+            return null;
+        }
     }
-
-    void init(Session session)
+    public Event copy()
     {
-        this.session = session;
-        init(session.getConnection());
+       EventImpl newEvent = new EventImpl();
+       newEvent.init(type, context);
+       return newEvent;
     }
 
-    void init(Link link)
+    @Override
+    public String toString()
     {
-        this.link = link;
-        init(link.getSession());
+        return "EventImpl{" + "type=" + type + ", context=" + context + '}';
     }
-
-    void init(Delivery delivery)
-    {
-        this.delivery = delivery;
-        init(delivery.getLink());
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameHandler.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameHandler.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameHandler.java
index 9b1413d..542466a 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameHandler.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameHandler.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.proton.engine.impl;
 
+import org.apache.qpid.proton.engine.TransportException;
 import org.apache.qpid.proton.framing.TransportFrame;
 
 public interface FrameHandler
@@ -31,7 +32,7 @@ public interface FrameHandler
      */
     boolean handleFrame(TransportFrame frame);
 
-    void closed();
+    void closed(TransportException error);
 
     /**
      * Returns whether I am currently able to handle frames.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java
index a83f888..849a2e7 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java
@@ -40,6 +40,8 @@ class FrameParser implements TransportInput
 {
     private static final Logger TRACE_LOGGER = Logger.getLogger("proton.trace");
 
+    private static final ByteBuffer _emptyInputBuffer = newWriteableBuffer(0);
+
     private enum State
     {
         HEADER0,
@@ -62,8 +64,9 @@ class FrameParser implements TransportInput
 
     private final FrameHandler _frameHandler;
     private final ByteBufferDecoder _decoder;
+    private final int _maxFrameSize;
 
-    private final ByteBuffer _inputBuffer;
+    private ByteBuffer _inputBuffer = null;
     private boolean _tail_closed = false;
 
     private State _state = State.HEADER0;
@@ -87,11 +90,7 @@ class FrameParser implements TransportInput
     {
         _frameHandler = frameHandler;
         _decoder = decoder;
-        if (maxFrameSize > 0) {
-            _inputBuffer = newWriteableBuffer(maxFrameSize);
-        } else {
-            _inputBuffer = newWriteableBuffer(4*1024);
-        }
+        _maxFrameSize = maxFrameSize > 0 ? maxFrameSize : 4*1024;
     }
 
     private void input(ByteBuffer in) throws TransportException
@@ -372,6 +371,7 @@ class FrameParser implements TransportInput
 
                             _decoder.setByteBuffer(in);
                             Object val = _decoder.readObject();
+                            _decoder.setByteBuffer(null);
 
                             Binary payload;
 
@@ -447,7 +447,7 @@ class FrameParser implements TransportInput
                 state = State.ERROR;
                 frameParsingError = new TransportException("connection aborted");
             } else {
-                _frameHandler.closed();
+                _frameHandler.closed(null);
             }
         }
 
@@ -460,7 +460,7 @@ class FrameParser implements TransportInput
             if(frameParsingError != null)
             {
                 _parsingError = frameParsingError;
-                throw frameParsingError;
+                _frameHandler.closed(frameParsingError);
             }
             else
             {
@@ -475,7 +475,11 @@ class FrameParser implements TransportInput
         if (_tail_closed) {
             return Transport.END_OF_STREAM;
         } else {
-            return _inputBuffer.remaining();
+            if (_inputBuffer != null) {
+                return _inputBuffer.remaining();
+            } else {
+                return _maxFrameSize;
+            }
         }
     }
 
@@ -483,27 +487,41 @@ class FrameParser implements TransportInput
     public ByteBuffer tail()
     {
         if (_tail_closed) {
-            if (_parsingError != null) {
-                throw new TransportException(_parsingError.getMessage());
-            } else {
-                throw new TransportException("tail closed");
-            }
+            throw new TransportException("tail closed");
+        }
+
+        if (_inputBuffer == null) {
+            _inputBuffer = newWriteableBuffer(_maxFrameSize);
         }
+
         return _inputBuffer;
     }
 
     @Override
     public void process() throws TransportException
     {
-        _inputBuffer.flip();
-
-        try
+        if (_inputBuffer != null)
         {
-            input(_inputBuffer);
+            _inputBuffer.flip();
+
+            try
+            {
+                input(_inputBuffer);
+            }
+            finally
+            {
+                if (_inputBuffer.hasRemaining()) {
+                    _inputBuffer.compact();
+                } else if (_inputBuffer.capacity() > TransportImpl.BUFFER_RELEASE_THRESHOLD) {
+                    _inputBuffer = null;
+                } else {
+                    _inputBuffer.clear();
+                }
+            }
         }
-        finally
+        else
         {
-            _inputBuffer.compact();
+            input(_emptyInputBuffer);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameWriter.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameWriter.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameWriter.java
index bacd638..fce5f2d 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameWriter.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameWriter.java
@@ -45,15 +45,15 @@ class FrameWriter
     private WritableBuffer _buffer;
     private int _maxFrameSize;
     private byte _frameType;
-    private ProtocolTracer _protocolTracer;
-    private Object _logCtx;
+    final private Ref<ProtocolTracer> _protocolTracer;
+    private TransportImpl _transport;
 
     private int _frameStart = 0;
     private int _payloadStart;
     private int _performativeSize;
 
     FrameWriter(EncoderImpl encoder, int maxFrameSize, byte frameType,
-                ProtocolTracer protocolTracer, Object logCtx)
+                Ref<ProtocolTracer> protocolTracer, TransportImpl transport)
     {
         _encoder = encoder;
         _bbuf = ByteBuffer.allocate(1024);
@@ -62,7 +62,7 @@ class FrameWriter
         _maxFrameSize = maxFrameSize;
         _frameType = frameType;
         _protocolTracer = protocolTracer;
-        _logCtx = logCtx;
+        _transport = transport;
     }
 
     void setMaxFrameSize(int maxFrameSize)
@@ -155,11 +155,12 @@ class FrameWriter
         // code, further refactor will fix this
         if (_frameType == AMQP_FRAME_TYPE) {
             TransportFrame frame = new TransportFrame(channel, (FrameBody) frameBody, Binary.create(originalPayload));
-            TransportImpl.log(_logCtx, TransportImpl.OUTGOING, frame);
+            _transport.log(TransportImpl.OUTGOING, frame);
 
-            if( _protocolTracer!=null )
+            ProtocolTracer tracer = _protocolTracer.get();
+            if(tracer != null)
             {
-                _protocolTracer.sentFrame(frame);
+                tracer.sentFrame(frame);
             }
         }
 
@@ -191,6 +192,11 @@ class FrameWriter
         writeFrame(0, frameBody, null, null);
     }
 
+    boolean isFull() {
+        // XXX: this should probably be tunable
+        return _bbuf.position() > 64*1024;
+    }
+
     int readBytes(ByteBuffer dst)
     {
         ByteBuffer src = _bbuf.duplicate();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
index dda2171..37433d5 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
@@ -53,14 +53,17 @@ public abstract class LinkImpl extends EndpointImpl implements Link
     private ReceiverSettleMode _remoteReceiverSettleMode;
 
 
-    private final LinkNode<LinkImpl> _node;
+    private LinkNode<LinkImpl> _node;
     private boolean _drain;
 
     LinkImpl(SessionImpl session, String name)
     {
         _session = session;
+        _session.incref();
         _name = name;
-        _node = session.getConnectionImpl().addLinkEndpoint(this);
+        ConnectionImpl conn = session.getConnectionImpl();
+        _node = conn.addLinkEndpoint(this);
+        conn.put(Event.Type.LINK_INIT, this);
     }
 
 
@@ -103,11 +106,21 @@ public abstract class LinkImpl extends EndpointImpl implements Link
         }
     }
 
-    public void free()
+    @Override
+    void postFinal() {
+        _session.getConnectionImpl().put(Event.Type.LINK_FINAL, this);
+        _session.decref();
+    }
+
+    @Override
+    void doFree()
     {
-        super.free();
         _session.getConnectionImpl().removeLinkEndpoint(_node);
-        //TODO.
+        _node = null;
+    }
+
+    void modifyEndpoints() {
+        modified();
     }
 
     public void remove(DeliveryImpl delivery)
@@ -375,11 +388,14 @@ public abstract class LinkImpl extends EndpointImpl implements Link
     }
 
     @Override
-    protected void localStateChanged()
+    void localOpen()
     {
-        EventImpl ev = getConnectionImpl().put(Event.Type.LINK_LOCAL_STATE);
-        if (ev != null) {
-            ev.init(this);
-        }
+        getConnectionImpl().put(Event.Type.LINK_OPEN, this);
+    }
+
+    @Override
+    void localClose()
+    {
+        getConnectionImpl().put(Event.Type.LINK_CLOSE, this);
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ReceiverImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ReceiverImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ReceiverImpl.java
index 89b6a87..defb78b 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ReceiverImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ReceiverImpl.java
@@ -96,12 +96,11 @@ public class ReceiverImpl extends LinkImpl implements Receiver
         return consumed;
     }
 
-    public void free()
+    @Override
+    void doFree()
     {
         getSession().freeReceiver(this);
-
-        super.free();
-        //TODO.
+        super.doFree();
     }
 
     boolean hasIncoming()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/Ref.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/Ref.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/Ref.java
new file mode 100644
index 0000000..01e3a35
--- /dev/null
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/Ref.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.proton.engine.impl;
+
+
+/**
+ * Ref
+ *
+ */
+
+class Ref<T>
+{
+
+    T value;
+
+    public Ref(T initial) {
+        value = initial;
+    }
+
+    public T get() {
+        return value;
+    }
+
+    public void set(T value) {
+        this.value = value;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
index 700bdf6..d587abb 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
@@ -29,6 +29,7 @@ import java.nio.ByteBuffer;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import org.apache.qpid.proton.ProtonUnsupportedOperationException;
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.Symbol;
 import org.apache.qpid.proton.amqp.security.SaslChallenge;
@@ -53,6 +54,8 @@ public class SaslImpl implements Sasl, SaslFrameBody.SaslFrameBodyHandler<Void>,
     private final DecoderImpl _decoder = new DecoderImpl();
     private final EncoderImpl _encoder = new EncoderImpl(_decoder);
 
+    private final TransportImpl _transport;
+
     private boolean _tail_closed = false;
     private final ByteBuffer _inputBuffer;
     private boolean _head_closed = false;
@@ -86,14 +89,15 @@ public class SaslImpl implements Sasl, SaslFrameBody.SaslFrameBodyHandler<Void>,
      * returned by {@link SaslTransportWrapper#getInputBuffer()} and
      * {@link SaslTransportWrapper#getOutputBuffer()}.
      */
-    SaslImpl(int maxFrameSize)
+    SaslImpl(TransportImpl transport, int maxFrameSize)
     {
+        _transport = transport;
         _inputBuffer = newWriteableBuffer(maxFrameSize);
         _outputBuffer = newWriteableBuffer(maxFrameSize);
 
         AMQPDefinedTypes.registerAllTypes(_decoder,_encoder);
         _frameParser = new SaslFrameParser(this, _decoder);
-        _frameWriter = new FrameWriter(_encoder, maxFrameSize, FrameWriter.SASL_FRAME_TYPE, null, this);
+        _frameWriter = new FrameWriter(_encoder, maxFrameSize, FrameWriter.SASL_FRAME_TYPE, null, _transport);
     }
 
     @Override
@@ -460,6 +464,13 @@ public class SaslImpl implements Sasl, SaslFrameBody.SaslFrameBodyHandler<Void>,
         _role = Role.SERVER;
     }
 
+    @Override
+    public void allowSkip(boolean allowSkip)
+    {
+        //TODO: implement
+        throw new ProtonUnsupportedOperationException();
+    }
+
     public TransportWrapper wrap(final TransportInput input, final TransportOutput output)
     {
         return new SaslTransportWrapper(input, output);
@@ -565,6 +576,9 @@ public class SaslImpl implements Sasl, SaslFrameBody.SaslFrameBodyHandler<Void>,
             _tail_closed = true;
             if (isInputInSaslMode()) {
                 _head_closed = true;
+                _underlyingInput.close_tail();
+            } else {
+                _underlyingInput.close_tail();
             }
         }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
index 1ca8b52..38fb5f6 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
@@ -63,11 +63,11 @@ public class SenderImpl  extends LinkImpl implements Sender
         //TODO.
     }
 
-    public void free()
+    @Override
+    void doFree()
     {
         getSession().freeSender(this);
-        super.free();
-
+        super.doFree();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
index f95df27..57010d2 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
@@ -45,7 +45,9 @@ public class SessionImpl extends EndpointImpl implements ProtonJSession
     SessionImpl(ConnectionImpl connection)
     {
         _connection = connection;
+        _connection.incref();
         _node = _connection.addSessionEndpoint(this);
+        _connection.put(Event.Type.SESSION_INIT, this);
     }
 
     public SenderImpl sender(String name)
@@ -90,25 +92,38 @@ public class SessionImpl extends EndpointImpl implements ProtonJSession
         return getConnectionImpl();
     }
 
-    public void free()
-    {
-        super.free();
+    @Override
+    void postFinal() {
+        _connection.put(Event.Type.SESSION_FINAL, this);
+        _connection.decref();
+    }
 
+    @Override
+    void doFree() {
         _connection.removeSessionEndpoint(_node);
         _node = null;
 
-        for(SenderImpl sender : _senders.values())
-        {
+        for(SenderImpl sender : _senders.values()) {
             sender.free();
         }
         _senders.clear();
-        for(ReceiverImpl receiver : _receivers.values())
-        {
+        for(ReceiverImpl receiver : _receivers.values()) {
             receiver.free();
         }
         _receivers.clear();
     }
 
+    void modifyEndpoints() {
+        for (SenderImpl snd : _senders.values()) {
+            snd.modifyEndpoints();
+        }
+
+        for (ReceiverImpl rcv : _receivers.values()) {
+            rcv.modifyEndpoints();
+        }
+        modified();
+    }
+
     TransportSession getTransportSession()
     {
         return _transportSession;
@@ -184,11 +199,14 @@ public class SessionImpl extends EndpointImpl implements ProtonJSession
     }
 
     @Override
-    protected void localStateChanged()
+    void localOpen()
     {
-        EventImpl ev = getConnectionImpl().put(Event.Type.SESSION_LOCAL_STATE);
-        if (ev != null) {
-            ev.init(this);
-        }
+        getConnectionImpl().put(Event.Type.SESSION_OPEN, this);
+    }
+
+    @Override
+    void localClose()
+    {
+        getConnectionImpl().put(Event.Type.SESSION_CLOSE, this);
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactory.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactory.java
deleted file mode 100644
index ddf2170..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.proton.engine.impl;
-
-import org.apache.qpid.proton.engine.Connection;
-import org.apache.qpid.proton.engine.Transport;
-
-public abstract class TransportFactory
-{
-    public abstract Transport transport(Connection conn);
-
-    public static TransportFactory getDefaultTransportFactory()
-    {
-        return new TransportFactoryImpl();
-    }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactoryImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactoryImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactoryImpl.java
deleted file mode 100644
index f685575..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactoryImpl.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.proton.engine.impl;
-
-import org.apache.qpid.proton.engine.Connection;
-import org.apache.qpid.proton.engine.Transport;
-
-class TransportFactoryImpl extends TransportFactory
-{
-    TransportFactoryImpl()
-    {
-    }
-
-    @Override
-    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
-    public Transport transport(Connection c)
-    {
-        TransportImpl t = new TransportImpl();
-        t.bind(c);
-        return t;
-    }
-
-}


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


[37/51] [abbrv] qpid-proton git commit: Improve check for node.js in examples. Add mechanism for clients to increase stack as well as total memory - NB this feature requires emscripten fix only recently applied to incoming so may not be available in SDK

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/tests/javascript/message.js
----------------------------------------------------------------------
diff --git a/tests/javascript/message.js b/tests/javascript/message.js
index 22674c7..dca6f68 100644
--- a/tests/javascript/message.js
+++ b/tests/javascript/message.js
@@ -25,337 +25,335 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("message.js should be run in Node.js");
-    return;
-}
+if (typeof process === 'object' && typeof require === 'function') {
+    var unittest = require("./unittest.js");
+    var assert = require("assert");
+    var proton = require("qpid-proton");
 
-var unittest = require("./unittest.js");
-var assert = require("assert");
-var proton = require("qpid-proton");
+    /**
+     * JavaScript Implementation of Python's range() function taken from:
+     * http://stackoverflow.com/questions/8273047/javascript-function-similar-to-python-range
+     */
+    var range = function(start, stop, step) {
+        if (typeof stop == 'undefined') {
+            // one param defined
+            stop = start;
+            start = 0;
+        };
+        if (typeof step == 'undefined') {
+            step = 1;
+        };
+        if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
+            return [];
+        };
+        var result = [];
+        for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
+            result.push(i);
+        };
+        return result;
+    };
 
-/**
- * JavaScript Implementation of Python's range() function taken from:
- * http://stackoverflow.com/questions/8273047/javascript-function-similar-to-python-range
- */
-var range = function(start, stop, step) {
-    if (typeof stop == 'undefined') {
-        // one param defined
-        stop = start;
-        start = 0;
+
+    // Extend TestCase by creating a new Test class as we're using it in a few places.
+    var Test = function() { // Test constructor.
+        /**
+         * The following call is the equivalent of "super" in Java. It's not necessary
+         * here as the unittest.TestCase constructor doesn't set any state, but it
+         * is the correct thing to do when implementing classical inheritance in
+         * JavaScript so I've kept it here as a useful reminder of the "pattern".
+         */
+        //unittest.TestCase.prototype.constructor.call(this);
+    };  
+
+    Test.prototype = new unittest.TestCase(); // Here's where the inheritance occurs.
+    Test.prototype.constructor = Test; // Otherwise instances of Test would have a constructor of unittest.TestCase.
+
+    Test.prototype.setUp = function() {
+        this.msg = new proton.Message();
     };
-    if (typeof step == 'undefined') {
-        step = 1;
+
+    Test.prototype.tearDown = function() {
+        this.msg.free();
+        this.msg = null;
     };
-    if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
-        return [];
+
+
+    // Extend Test more simply by creating a prototype instance and adding test methods as properties.
+
+    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.
+        // This scenario is what happens in the tests that use the range() function.
+        values = (Object.prototype.toString.call(values[0]) === '[object Array]') ? values[0] : values;
+    
+        // Work out the accessor/mutator names noting that boolean accessors use "is" not "get".
+        var setter = 'set' + name;
+        var getter = (typeof defaultValue === 'boolean') ? 'is' + name : 'get' + name;
+    
+        // 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.
+        assert.deepEqual(d, defaultValue);
+    
+        for (var i = 0; i < values.length; i++) {
+            var v = values[i];
+    
+            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]();
+            gotten = (gotten instanceof proton.Data.Binary) ? gotten.toString() : gotten;
+            gotten = (gotten instanceof Date) ? gotten.valueOf() : v;
+    
+            assert.deepEqual(value, gotten);
+        }
     };
-    var result = [];
-    for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
-        result.push(i);
+
+    AccessorsTest._testString = function(name) {
+        this._test(name, "", "asdf", "fdsa", "");
+    };  
+
+    AccessorsTest._testTime = function(name) {
+        // The ExpiryTime and CreationTime methods can take either a number or a Date Object.
+        this._test(name, new Date(0), new Date(0), 123456789, new Date(987654321));
     };
-    return result;
-};
 
+    AccessorsTest.testID = function() {
+        console.log("testID");
+        this._test("ID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
+        console.log("OK\n");
+    };  
 
-// Extend TestCase by creating a new Test class as we're using it in a few places.
-var Test = function() { // Test constructor.
-    /**
-     * The following call is the equivalent of "super" in Java. It's not necessary
-     * here as the unittest.TestCase constructor doesn't set any state, but it
-     * is the correct thing to do when implementing classical inheritance in
-     * JavaScript so I've kept it here as a useful reminder of the "pattern".
-     */
-    //unittest.TestCase.prototype.constructor.call(this);
-};
+    AccessorsTest.testCorrelationID = function() {
+        console.log("testCorrelationID");
+        this._test("CorrelationID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
+        console.log("OK\n");
+    };
 
-Test.prototype = new unittest.TestCase(); // Here's where the inheritance occurs.
-Test.prototype.constructor = Test; // Otherwise instances of Test would have a constructor of unittest.TestCase.
+    AccessorsTest.testDurable = function() {
+        console.log("testDurable");
+        this._test("Durable", false, true, false);
+        console.log("OK\n");
+    };
 
-Test.prototype.setUp = function() {
-    this.msg = new proton.Message();
-};
+    AccessorsTest.testPriority = function() {
+        console.log("testPriority");
+        this._test("Priority", proton.Message.DEFAULT_PRIORITY, range(0, 256));
+        console.log("OK\n");
+    };
 
-Test.prototype.tearDown = function() {
-    this.msg.free();
-    this.msg = null;
-};
+    AccessorsTest.testTTL = function() {
+        console.log("testTTL");
+        this._test("TTL", 0, range(12345, 54321));
+        console.log("OK\n");
+    };
 
+    AccessorsTest.testFirstAcquirer = function() {
+        console.log("testFirstAcquirer");
+        this._test("FirstAcquirer", false, true, false);
+        console.log("OK\n");
+    };
 
-// Extend Test more simply by creating a prototype instance and adding test methods as properties.
+    AccessorsTest.testDeliveryCount = function() {
+        console.log("testDeliveryCount");
+        this._test("DeliveryCount", 0, range(0, 1024));
+        console.log("OK\n");
+    };
 
-var AccessorsTest = new Test();
+    AccessorsTest.testUserID = function() {
+        console.log("testUserID");
+        this._test("UserID", "", "asdf", "fdsa", 123, new proton.Data.Binary("ВИНАРЫ"), new proton.Data.Uuid(), "");
+        console.log("OK\n");
+    };
 
-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.
-     */
+    AccessorsTest.testAddress = function() {
+        console.log("testAddress");
+        this._testString("Address");
+        console.log("OK\n");
+    };
 
-    // 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.
-    // This scenario is what happens in the tests that use the range() function.
-    values = (Object.prototype.toString.call(values[0]) === '[object Array]') ? values[0] : values;
-
-    // Work out the accessor/mutator names noting that boolean accessors use "is" not "get".
-    var setter = 'set' + name;
-    var getter = (typeof defaultValue === 'boolean') ? 'is' + name : 'get' + name;
-
-    // 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.
-    assert.deepEqual(d, defaultValue);
-
-    for (var i = 0; i < values.length; i++) {
-        var v = values[i];
-
-        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]();
-        gotten = (gotten instanceof proton.Data.Binary) ? gotten.toString() : gotten;
-        gotten = (gotten instanceof Date) ? gotten.valueOf() : v;
-
-        assert.deepEqual(value, gotten);
-    }
-};
-
-AccessorsTest._testString = function(name) {
-    this._test(name, "", "asdf", "fdsa", "");
-};
-
-AccessorsTest._testTime = function(name) {
-    // The ExpiryTime and CreationTime methods can take either a number or a Date Object.
-    this._test(name, new Date(0), new Date(0), 123456789, new Date(987654321));
-};
-
-AccessorsTest.testID = function() {
-    console.log("testID");
-    this._test("ID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
-    console.log("OK\n");
-};
-
-AccessorsTest.testCorrelationID = function() {
-    console.log("testCorrelationID");
-    this._test("CorrelationID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
-    console.log("OK\n");
-};
-
-AccessorsTest.testDurable = function() {
-    console.log("testDurable");
-    this._test("Durable", false, true, false);
-    console.log("OK\n");
-};
-
-AccessorsTest.testPriority = function() {
-    console.log("testPriority");
-    this._test("Priority", proton.Message.DEFAULT_PRIORITY, range(0, 256));
-    console.log("OK\n");
-};
-
-AccessorsTest.testTTL = function() {
-    console.log("testTTL");
-    this._test("TTL", 0, range(12345, 54321));
-    console.log("OK\n");
-};
-
-AccessorsTest.testFirstAcquirer = function() {
-    console.log("testFirstAcquirer");
-    this._test("FirstAcquirer", false, true, false);
-    console.log("OK\n");
-};
-
-AccessorsTest.testDeliveryCount = function() {
-    console.log("testDeliveryCount");
-    this._test("DeliveryCount", 0, range(0, 1024));
-    console.log("OK\n");
-};
-
-AccessorsTest.testUserID = function() {
-    console.log("testUserID");
-    this._test("UserID", "", "asdf", "fdsa", 123, new proton.Data.Binary("ВИНАРЫ"), new proton.Data.Uuid(), "");
-    console.log("OK\n");
-};
-
-AccessorsTest.testAddress = function() {
-    console.log("testAddress");
-    this._testString("Address");
-    console.log("OK\n");
-};
-
-AccessorsTest.testSubject = function() {
-    console.log("testSubject");
-    this._testString("Subject");
-    console.log("OK\n");
-};
-
-AccessorsTest.testReplyTo = function() {
-    console.log("testReplyTo");
-    this._testString("ReplyTo");
-    console.log("OK\n");
-};
-
-AccessorsTest.testContentType = function() {
-    console.log("testContentType");
-    this._testString("ContentType");
-    console.log("OK\n");
-};
-
-AccessorsTest.testContentEncoding = function() {
-    console.log("testContentEncoding");
-    this._testString("ContentEncoding");
-    console.log("OK\n");
-};
-
-AccessorsTest.testExpiryTime = function() {
-    console.log("testExpiryTime");
-    this._testTime("ExpiryTime");
-    console.log("OK\n");
-};
-
-AccessorsTest.testCreationTime = function() {
-    console.log("testCreationTime");
-    this._testTime("CreationTime");
-    console.log("OK\n");
-};
-
-AccessorsTest.testGroupID = function() {
-    console.log("testGroupID");
-    this._testString("GroupID");
-    console.log("OK\n");
-};
-
-AccessorsTest.testGroupSequence = function() {
-    console.log("testGroupSequence");
-    this._test("GroupSequence", 0, 0, -10, 10, 20, -20);
-    console.log("OK\n");
-};
-
-AccessorsTest.testReplyToGroupID = function() {
-    console.log("testReplyToGroupID");
-    this._testString("ReplyToGroupID");
-    console.log("OK\n");
-};
-
-
-var CodecTest = new Test();
-
-CodecTest.testRoundTrip = function() {
-    console.log("testRoundTrip");
-    this.msg.setID("asdf");
-    this.msg.setCorrelationID(new proton.Data.Uuid());
-    this.msg.setTTL(3);
-    this.msg.setPriority(100);
-    this.msg.setAddress("address");
-    this.msg.setSubject("subject");
-    this.msg.body = "Hello World!";
-
-    var data = this.msg.encode();
-    var msg2 = new proton.Message();
-    msg2.decode(data);
-
-    assert(this.msg.getID() === msg2.getID());
-    assert(this.msg.getCorrelationID().toString() === msg2.getCorrelationID().toString());
-    assert(this.msg.getTTL() === msg2.getTTL());
-    assert(this.msg.getPriority() === msg2.getPriority());
-    assert(this.msg.getAddress() === msg2.getAddress());
-    assert(this.msg.getSubject() === msg2.getSubject());
-    assert(this.msg.body === msg2.body);
-
-    msg2.free();
-    console.log("OK\n");
-};
+    AccessorsTest.testSubject = function() {
+        console.log("testSubject");
+        this._testString("Subject");
+        console.log("OK\n");
+    };
 
-/**
- * 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}};
+    AccessorsTest.testReplyTo = function() {
+        console.log("testReplyTo");
+        this._testString("ReplyTo");
+        console.log("OK\n");
+    };
 
-    var data = this.msg.encode();
-    var msg2 = new proton.Message();
-    msg2.decode(data);
+    AccessorsTest.testContentType = function() {
+        console.log("testContentType");
+        this._testString("ContentType");
+        console.log("OK\n");
+    };
 
-    assert(this.msg.getAddress() === msg2.getAddress());
-    assert(this.msg.getContentType() === msg2.getContentType());
-    assert.deepEqual(this.msg.body, msg2.body);
+    AccessorsTest.testContentEncoding = function() {
+        console.log("testContentEncoding");
+        this._testString("ContentEncoding");
+        console.log("OK\n");
+    };
 
-    msg2.free();
-    console.log("OK\n");
-};
+    AccessorsTest.testExpiryTime = function() {
+        console.log("testExpiryTime");
+        this._testTime("ExpiryTime");
+        console.log("OK\n");
+    };
 
-/**
- * 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}};
+    AccessorsTest.testCreationTime = function() {
+        console.log("testCreationTime");
+        this._testTime("CreationTime");
+        console.log("OK\n");
+    };
 
-    var data = this.msg.encode();
-    var msg2 = new proton.Message();
-    msg2.decode(data);
+    AccessorsTest.testGroupID = function() {
+        console.log("testGroupID");
+        this._testString("GroupID");
+        console.log("OK\n");
+    };
 
-    assert(this.msg.getAddress() === msg2.getAddress());
-    assert(this.msg.getContentType() === msg2.getContentType());
-    assert.deepEqual(this.msg.body, msg2.body);
+    AccessorsTest.testGroupSequence = function() {
+        console.log("testGroupSequence");
+        this._test("GroupSequence", 0, 0, -10, 10, 20, -20);
+        console.log("OK\n");
+    };
 
-    msg2.free();
-    console.log("OK\n");
-};
+    AccessorsTest.testReplyToGroupID = function() {
+        console.log("testReplyToGroupID");
+        this._testString("ReplyToGroupID");
+        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);
+    var CodecTest = new Test();
+
+    CodecTest.testRoundTrip = function() {
+        console.log("testRoundTrip");
+        this.msg.setID("asdf");
+        this.msg.setCorrelationID(new proton.Data.Uuid());
+        this.msg.setTTL(3);
+        this.msg.setPriority(100);
+        this.msg.setAddress("address");
+        this.msg.setSubject("subject");
+        this.msg.body = "Hello World!";
+    
+        var data = this.msg.encode();
+        var msg2 = new proton.Message();
+        msg2.decode(data);
+    
+        assert(this.msg.getID() === msg2.getID());
+        assert(this.msg.getCorrelationID().toString() === msg2.getCorrelationID().toString());
+        assert(this.msg.getTTL() === msg2.getTTL());
+        assert(this.msg.getPriority() === msg2.getPriority());
+        assert(this.msg.getAddress() === msg2.getAddress());
+        assert(this.msg.getSubject() === msg2.getSubject());
+        assert(this.msg.body === msg2.body);
+
+        msg2.free();
+        console.log("OK\n");
+    };
 
-    assert(this.msg.getAddress() === msg2.getAddress());
-    assert(this.msg.getContentType() === msg2.getContentType());
-    assert.deepEqual(this.msg.body, msg2.body);
+    /**
+     * 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);
+    
+        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");
+    };
 
-    msg2.free();
-    console.log("OK\n");
-};
+    /**
+     * 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();
+    // load and save are deprecated so not implemented in the JavaScript binding.
 
+    AccessorsTest.run();
+    CodecTest.run();
+} else {
+    console.error("message.js should be run in Node.js");
+}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/tests/javascript/soak.js
----------------------------------------------------------------------
diff --git a/tests/javascript/soak.js b/tests/javascript/soak.js
index c3882ab..8ecce6a 100755
--- a/tests/javascript/soak.js
+++ b/tests/javascript/soak.js
@@ -20,76 +20,74 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("soak.js should be run in Node.js");
-    return;
-}
-
-var proton = require("qpid-proton");
-
-var addr = 'guest:guest@localhost:5673';
-//var addr = 'localhost:5673';
-var address = 'amqp://' + addr;
-console.log(address);
-
-var subscriptionQueue = '';
-var count = 0;
-var start = 0; // Start Time.
-
-var message = new proton.Message();
-var messenger = new proton.Messenger();
-
-var pumpData = function() {
-    while (messenger.incoming()) {
-        // The second parameter forces Binary payloads to be decoded as strings
-        // this is useful because the broker QMF Agent encodes strings as AMQP
-        // binary, which is a right pain from an interoperability perspective.
-        var t = messenger.get(message, true);
-        //console.log("Address: " + message.getAddress());
-        //console.log("Content: " + message.body);
-        messenger.accept(t);
-
-        if (count % 1000 === 0) {
-            var time = +new Date();
-            console.log("count = " + count + ", duration = " + (time - start) + ", rate = " + ((count*1000)/(time - start)));
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
+
+    var addr = 'guest:guest@localhost:5673';
+    //var addr = 'localhost:5673';
+    var address = 'amqp://' + addr;
+    console.log(address);
+
+    var subscriptionQueue = '';
+    var count = 0;
+    var start = 0; // Start Time.
+
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            // The second parameter forces Binary payloads to be decoded as strings
+            // this is useful because the broker QMF Agent encodes strings as AMQP
+            // binary, which is a right pain from an interoperability perspective.
+            var t = messenger.get(message, true);
+            //console.log("Address: " + message.getAddress());
+            //console.log("Content: " + message.body);
+            messenger.accept(t);
+    
+            if (count % 1000 === 0) {
+                var time = +new Date();
+                console.log("count = " + count + ", duration = " + (time - start) + ", rate = " + ((count*1000)/(time - start)));
+            }
+
+            sendMessage();
         }
 
+        if (messenger.isStopped()) {
+            message.free();
+            messenger.free();
+        }
+    };
+
+    var sendMessage = function() {
+        var msgtext = "Message Number " + count;
+        count++;
+
+        message.setAddress(address + '/' + subscriptionQueue);
+        message.body = msgtext;
+        messenger.put(message);
+        //messenger.settle();
+    };
+
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.on('subscription', function(subscription) {
+        var subscriptionAddress = subscription.getAddress();
+        var splitAddress = subscriptionAddress.split('/');
+        subscriptionQueue = splitAddress[splitAddress.length - 1];
+
+        console.log("Subscription Queue: " + subscriptionQueue);
+        start = +new Date();
         sendMessage();
-    }
+    });
 
-    if (messenger.isStopped()) {
-        message.free();
-        messenger.free();
-    }
-};
-
-var sendMessage = function() {
-    var msgtext = "Message Number " + count;
-    count++;
-
-    message.setAddress(address + '/' + subscriptionQueue);
-    message.body = msgtext;
-    messenger.put(message);
-//messenger.settle();
-};
-
-messenger.on('error', function(error) {console.log(error);});
-messenger.on('work', pumpData);
-messenger.on('subscription', function(subscription) {
-    var subscriptionAddress = subscription.getAddress();
-    var splitAddress = subscriptionAddress.split('/');
-    subscriptionQueue = splitAddress[splitAddress.length - 1];
-
-    console.log("Subscription Queue: " + subscriptionQueue);
-    start = +new Date();
-    sendMessage();
-});
-
-//messenger.setOutgoingWindow(1024);
-messenger.setIncomingWindow(1024); // The Java Broker seems to need this.
-messenger.recv(); // Receive as many messages as messenger can buffer.
-messenger.start();
-
-messenger.subscribe('amqp://' + addr + '/#');
+    //messenger.setOutgoingWindow(1024);
+    messenger.setIncomingWindow(1024); // The Java Broker seems to need this.
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
 
+    messenger.subscribe('amqp://' + addr + '/#');
+} else {
+    console.error("soak.js should be run in Node.js");
+}
 


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


[28/51] [abbrv] qpid-proton git commit: 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 tr

Posted by rh...@apache.org.
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

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1624841 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/530d9fd7
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/530d9fd7
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/530d9fd7

Branch: refs/heads/master
Commit: 530d9fd79ecd750750d252f38db101db9164c7c3
Parents: 6343817
Author: fadams <fa...@unknown>
Authored: Sun Sep 14 11:51:15 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sun Sep 14 11:51:15 2014 +0000

----------------------------------------------------------------------
 proton-c/bindings/javascript/binding.js |  28 +++++-
 tests/javascript/codec.js               |  10 ++-
 tests/javascript/message.js             | 123 ++++++++++++++++++++-------
 3 files changed, 123 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/530d9fd7/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index fa53e4c..7e71b88 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -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(decodeBinaryAsString) {
     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

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/530d9fd7/tests/javascript/codec.js
----------------------------------------------------------------------
diff --git a/tests/javascript/codec.js b/tests/javascript/codec.js
index 9decbe7..2ebc390 100644
--- a/tests/javascript/codec.js
+++ b/tests/javascript/codec.js
@@ -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");
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/530d9fd7/tests/javascript/message.js
----------------------------------------------------------------------
diff --git a/tests/javascript/message.js b/tests/javascript/message.js
index ed2d1eb..22674c7 100644
--- a/tests/javascript/message.js
+++ b/tests/javascript/message.js
@@ -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, defaultValue, values) {
 
     // 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 = function() {
 
 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


[25/51] [abbrv] qpid-proton git commit: Update with merge of latest proton codebase and checked against latest emscripten incoming branch

Posted by rh...@apache.org.
Update with merge of latest proton codebase and checked against latest emscripten incoming branch

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1622849 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/1c2f4894
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/1c2f4894
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/1c2f4894

Branch: refs/heads/master
Commit: 1c2f4894270775269abb6e8303e75684331a3212
Parents: 4a78327
Author: fadams <fa...@unknown>
Authored: Sat Sep 6 11:23:10 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sat Sep 6 11:23:10 2014 +0000

----------------------------------------------------------------------
 CMakeLists.txt                                  |   14 +
 DEVELOPERS                                      |   25 +-
 config.bat.in                                   |   66 +
 config.sh                                       |   79 --
 config.sh.in                                    |   61 +
 contrib/proton-hawtdispatch/pom.xml             |   61 +
 .../hawtdispatch/api/AmqpConnectOptions.java    |  228 ++++
 .../proton/hawtdispatch/api/AmqpConnection.java |  201 ++++
 .../hawtdispatch/api/AmqpDeliveryListener.java  |   32 +
 .../hawtdispatch/api/AmqpEndpointBase.java      |  158 +++
 .../qpid/proton/hawtdispatch/api/AmqpLink.java  |   27 +
 .../proton/hawtdispatch/api/AmqpReceiver.java   |  141 +++
 .../proton/hawtdispatch/api/AmqpSender.java     |  227 ++++
 .../proton/hawtdispatch/api/AmqpSession.java    |  141 +++
 .../qpid/proton/hawtdispatch/api/Callback.java  |   29 +
 .../hawtdispatch/api/ChainedCallback.java       |   37 +
 .../hawtdispatch/api/DeliveryAttachment.java    |   27 +
 .../qpid/proton/hawtdispatch/api/Future.java    |   31 +
 .../hawtdispatch/api/MessageDelivery.java       |  226 ++++
 .../qpid/proton/hawtdispatch/api/Promise.java   |  107 ++
 .../qpid/proton/hawtdispatch/api/QoS.java       |   26 +
 .../proton/hawtdispatch/api/TransportState.java |   29 +
 .../proton/hawtdispatch/impl/AmqpHeader.java    |   85 ++
 .../proton/hawtdispatch/impl/AmqpListener.java  |   71 ++
 .../hawtdispatch/impl/AmqpProtocolCodec.java    |  109 ++
 .../proton/hawtdispatch/impl/AmqpTransport.java |  587 +++++++++
 .../qpid/proton/hawtdispatch/impl/Defer.java    |   27 +
 .../hawtdispatch/impl/EndpointContext.java      |   76 ++
 .../qpid/proton/hawtdispatch/impl/Support.java  |   41 +
 .../qpid/proton/hawtdispatch/impl/Watch.java    |   26 +
 .../proton/hawtdispatch/impl/WatchBase.java     |   54 +
 .../proton/hawtdispatch/api/SampleTest.java     |  292 +++++
 .../hawtdispatch/test/MessengerServer.java      |  135 +++
 contrib/proton-jms/pom.xml                      |   50 +
 .../jms/AMQPNativeInboundTransformer.java       |   40 +
 .../jms/AMQPNativeOutboundTransformer.java      |  103 ++
 .../proton/jms/AMQPRawInboundTransformer.java   |   47 +
 .../proton/jms/AutoOutboundTransformer.java     |   46 +
 .../apache/qpid/proton/jms/EncodedMessage.java  |   75 ++
 .../qpid/proton/jms/InboundTransformer.java     |  314 +++++
 .../jms/JMSMappingInboundTransformer.java       |  102 ++
 .../jms/JMSMappingOutboundTransformer.java      |  246 ++++
 .../org/apache/qpid/proton/jms/JMSVendor.java   |   45 +
 .../qpid/proton/jms/OutboundTransformer.java    |   52 +
 examples/CMakeLists.txt                         |    1 +
 examples/messenger/java/recv                    |    2 +-
 examples/messenger/java/send                    |    2 +-
 .../org/apache/qpid/proton/example/Send.java    |   10 +-
 examples/messenger/javascript/send.html         |   12 +-
 examples/messenger/perl/recv.pl                 |   34 +-
 examples/messenger/perl/send.pl                 |   16 +-
 examples/messenger/perl/server.pl               |    6 +-
 proton-c/CMakeLists.txt                         |   49 +-
 proton-c/bindings/CMakeLists.txt                |    2 +
 proton-c/bindings/javascript/CMakeLists.txt     |   10 +-
 proton-c/bindings/perl/CMakeLists.txt           |    4 +-
 .../bindings/perl/lib/qpid/proton/Constants.pm  |    7 +-
 proton-c/bindings/perl/lib/qpid/proton/Data.pm  |   93 +-
 .../bindings/perl/lib/qpid/proton/Message.pm    |   28 +-
 proton-c/bindings/perl/lib/qpid/proton/utils.pm |   31 +
 proton-c/bindings/perl/lib/qpid_proton.pm       |    1 +
 proton-c/bindings/perl/perl.i                   |    7 -
 proton-c/bindings/php/CMakeLists.txt            |    3 +
 proton-c/bindings/php/proton.php                |    2 +-
 proton-c/bindings/python/CMakeLists.txt         |   90 +-
 proton-c/bindings/python/cproton.i              |  379 ++++++
 proton-c/bindings/python/proton.py              |  242 ++--
 proton-c/bindings/python/python.i               |  378 ------
 proton-c/bindings/python/setup.py.in            |  107 ++
 proton-c/bindings/ruby/CMakeLists.txt           |    4 +-
 proton-c/bindings/ruby/lib/qpid_proton.rb       |    1 +
 .../bindings/ruby/lib/qpid_proton/version.rb    |   29 +
 proton-c/bindings/ruby/qpid_proton.gemspec      |    1 +
 proton-c/bindings/ruby/ruby.i                   |    1 -
 proton-c/docs/man/CMakeLists.txt                |    2 +-
 proton-c/docs/man/proton-dump.1                 |   19 +
 proton-c/include/proton/buffer.h                |    6 +
 proton-c/include/proton/cproton.i               |   28 +-
 proton-c/include/proton/event.h                 |  153 ++-
 proton-c/include/proton/io.h                    |    2 +
 proton-c/include/proton/object.h                |   11 +-
 proton-c/include/proton/sasl.h                  |   15 +-
 proton-c/include/proton/selector.h              |    4 +-
 proton-c/include/proton/terminus.h              |    8 +-
 proton-c/include/proton/transport.h             |   13 +-
 proton-c/include/proton/types.h                 |    6 +-
 proton-c/src/buffer.c                           |   12 +
 proton-c/src/codec/codec.c                      |   48 +-
 proton-c/src/codec/data.h                       |   34 +-
 proton-c/src/codec/decoder.c                    |    2 +-
 proton-c/src/codec/encoder.c                    |    2 +-
 proton-c/src/dispatch_actions.h                 |   45 +
 proton-c/src/dispatcher/dispatcher.c            |   63 +-
 proton-c/src/dispatcher/dispatcher.h            |   21 +-
 proton-c/src/engine/engine-internal.h           |   77 +-
 proton-c/src/engine/engine.c                    |  186 +--
 proton-c/src/engine/event.c                     |  249 ++--
 proton-c/src/engine/event.h                     |    9 +-
 proton-c/src/error.c                            |    2 +-
 proton-c/src/message/message.c                  |   25 +-
 proton-c/src/messenger/messenger.c              |  137 ++-
 proton-c/src/messenger/store.c                  |   22 +-
 proton-c/src/messenger/subscription.c           |    2 +-
 proton-c/src/messenger/transform.c              |    4 +-
 proton-c/src/object/object.c                    |  104 +-
 proton-c/src/parser.c                           |    2 +-
 proton-c/src/platform.h                         |    2 +
 proton-c/src/posix/driver.c                     |   24 +-
 proton-c/src/posix/io.c                         |   12 +-
 proton-c/src/posix/selector.c                   |    4 +-
 proton-c/src/protocol.h.py                      |   98 +-
 proton-c/src/proton-dump.c                      |   28 +
 proton-c/src/proton.c                           |    4 +-
 proton-c/src/sasl/sasl.c                        |   91 +-
 proton-c/src/selectable.c                       |    2 +-
 proton-c/src/ssl/openssl.c                      |   57 +-
 proton-c/src/tests/object.c                     |   53 +-
 proton-c/src/tests/parse-url.c                  |    7 +
 proton-c/src/transport/transport.c              |  366 +++---
 proton-c/src/types.c                            |   14 +-
 proton-c/src/util.c                             |   22 +-
 proton-c/src/windows/io.c                       |  226 ++--
 proton-c/src/windows/iocp.c                     | 1138 ++++++++++++++++++
 proton-c/src/windows/iocp.h                     |  141 +++
 proton-c/src/windows/selector.c                 |  325 +++--
 proton-c/src/windows/write_pipeline.c           |  312 +++++
 .../java/org/apache/qpid/proton/Proton.java     |  168 +--
 .../org/apache/qpid/proton/ProtonFactory.java   |   31 -
 .../apache/qpid/proton/ProtonFactoryImpl.java   |   28 -
 .../apache/qpid/proton/ProtonFactoryLoader.java |  111 --
 .../amqp/messaging/DeliveryAnnotations.java     |   11 +-
 .../amqp/messaging/MessageAnnotations.java      |    8 +-
 .../org/apache/qpid/proton/codec/Codec.java     |   40 +
 .../java/org/apache/qpid/proton/codec/Data.java |   10 +
 .../apache/qpid/proton/codec/DataFactory.java   |   28 -
 .../qpid/proton/codec/impl/DataFactoryImpl.java |   35 -
 .../org/apache/qpid/proton/driver/Driver.java   |   10 +
 .../qpid/proton/driver/DriverFactory.java       |   29 -
 .../qpid/proton/driver/impl/ConnectorImpl.java  |    1 -
 .../proton/driver/impl/DriverFactoryImpl.java   |   35 -
 .../qpid/proton/driver/impl/DriverImpl.java     |    2 +-
 .../apache/qpid/proton/engine/Collector.java    |    8 +
 .../apache/qpid/proton/engine/Connection.java   |   11 +
 .../org/apache/qpid/proton/engine/Engine.java   |   60 +
 .../qpid/proton/engine/EngineFactory.java       |   29 -
 .../org/apache/qpid/proton/engine/Event.java    |   41 +-
 .../org/apache/qpid/proton/engine/Sasl.java     |   10 +-
 .../apache/qpid/proton/engine/SslDomain.java    |   10 +
 .../qpid/proton/engine/SslPeerDetails.java      |   12 +-
 .../apache/qpid/proton/engine/Transport.java    |   30 +-
 .../qpid/proton/engine/impl/CollectorImpl.java  |   42 +-
 .../qpid/proton/engine/impl/ConnectionImpl.java |   67 +-
 .../qpid/proton/engine/impl/EndpointImpl.java   |   54 +-
 .../proton/engine/impl/EngineFactoryImpl.java   |   59 -
 .../qpid/proton/engine/impl/EventImpl.java      |  111 +-
 .../qpid/proton/engine/impl/FrameHandler.java   |    3 +-
 .../qpid/proton/engine/impl/FrameParser.java    |   58 +-
 .../qpid/proton/engine/impl/FrameWriter.java    |   20 +-
 .../qpid/proton/engine/impl/LinkImpl.java       |   36 +-
 .../qpid/proton/engine/impl/ReceiverImpl.java   |    7 +-
 .../org/apache/qpid/proton/engine/impl/Ref.java |   46 +
 .../qpid/proton/engine/impl/SaslImpl.java       |   18 +-
 .../qpid/proton/engine/impl/SenderImpl.java     |    6 +-
 .../qpid/proton/engine/impl/SessionImpl.java    |   42 +-
 .../proton/engine/impl/TransportFactory.java    |   34 -
 .../engine/impl/TransportFactoryImpl.java       |   41 -
 .../qpid/proton/engine/impl/TransportImpl.java  |  298 +++--
 .../qpid/proton/engine/impl/TransportLink.java  |   28 +-
 .../engine/impl/TransportOutputAdaptor.java     |   66 +-
 .../engine/impl/TransportOutputWriter.java      |    4 +-
 .../proton/engine/impl/TransportSession.java    |   32 +-
 .../impl/ssl/SimpleSslTransportWrapper.java     |   33 +-
 .../proton/engine/impl/ssl/SslDomainImpl.java   |    1 -
 .../engine/impl/ssl/SslPeerDetailsImpl.java     |    1 -
 .../org/apache/qpid/proton/message/Message.java |   23 +
 .../qpid/proton/message/MessageFactory.java     |   37 -
 .../proton/message/impl/MessageFactoryImpl.java |   54 -
 .../qpid/proton/message/impl/MessageImpl.java   |   12 +-
 .../apache/qpid/proton/messenger/Messenger.java |   14 +
 .../qpid/proton/messenger/MessengerFactory.java |   28 -
 .../messenger/impl/MessengerFactoryImpl.java    |   42 -
 .../proton/messenger/impl/MessengerImpl.java    |    9 +-
 proton-j/src/main/resources/cengine.py          |  140 ++-
 proton-j/src/main/resources/csasl.py            |   10 +-
 .../qpid/proton/ProtonFactoryLoaderTest.java    |  129 --
 .../proton/engine/impl/FrameParserTest.java     |   16 +-
 .../proton/engine/impl/TransportImplTest.java   |   15 +
 .../engine/impl/TransportOutputAdaptorTest.java |    4 +-
 .../impl/ssl/SimpleSslTransportWrapperTest.java |   13 +-
 .../DummyProtonCFactory.java                    |   29 -
 .../DummyProtonFactory.java                     |   25 -
 .../DummyProtonJFactory.java                    |   29 -
 .../systemtests/ProtonEngineExampleTest.java    |   34 +-
 .../proton/systemtests/ProtonFactoryTest.java   |   60 -
 .../qpid/proton/systemtests/SimpleTest.java     |   13 +-
 .../systemtests/engine/ConnectionTest.java      |   31 +-
 .../engine/ProtonFactoryTestFixture.java        |   54 -
 .../systemtests/engine/TransportTest.java       |    6 +-
 .../org/apache/qpid/proton/InteropTest.java     |    5 +-
 tests/python/proton_tests/common.py             |   81 +-
 tests/python/proton_tests/engine.py             |  242 +++-
 tests/python/proton_tests/messenger.py          |   98 +-
 tests/python/proton_tests/sasl.py               |   77 +-
 tests/python/proton_tests/ssl.py                |   72 +-
 tests/python/proton_tests/transport.py          |  117 +-
 tests/tools/apps/c/CMakeLists.txt               |    2 +
 tests/tools/apps/c/msgr-common.h                |    4 +
 version.txt                                     |    2 +-
 208 files changed, 10388 insertions(+), 3391 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a503467..7917258 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,6 +18,14 @@
 #
 cmake_minimum_required (VERSION 2.6)
 
+# Set default build type. Must come before project() which sets default to ""
+set (CMAKE_BUILD_TYPE RelWithDebInfo CACHE string
+  "Build type: Debug, Release, RelWithDebInfo or MinSizeRel (default RelWithDebInfo)")
+if (CMAKE_BUILD_TYPE MATCHES "Deb")
+  set (has_debug_symbols " (has debug symbols)")
+endif (CMAKE_BUILD_TYPE MATCHES "Deb")
+message("Build type is \"${CMAKE_BUILD_TYPE}\"${has_debug_symbols}")
+
 option(BUILD_WITH_CXX "Compile Proton using C++" OFF)
 if ("${CMAKE_GENERATOR}" MATCHES "^Visual Studio")
   # No C99 capability, use C++
@@ -152,3 +160,9 @@ if (JAVA_FOUND AND MAVEN_EXE)
 else (JAVA_FOUND AND MAVEN_EXE)
   message (STATUS "Cannot find both Java and Maven: testing disabled for Proton-J")
 endif (JAVA_FOUND AND MAVEN_EXE)
+
+# Generate test environment settings
+configure_file(${CMAKE_SOURCE_DIR}/config.sh.in
+               ${CMAKE_BINARY_DIR}/config.sh @ONLY)
+configure_file(${CMAKE_SOURCE_DIR}/config.bat.in
+               ${CMAKE_BINARY_DIR}/config.bat @ONLY)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/DEVELOPERS
----------------------------------------------------------------------
diff --git a/DEVELOPERS b/DEVELOPERS
index 97cfdaf..b0e0015 100644
--- a/DEVELOPERS
+++ b/DEVELOPERS
@@ -5,32 +5,15 @@ DEVELOPMENT ENVIRONMENT
 =======================
 
 To setup the variables for your development environment, simply source
-the file $REPO/config.sh:
+the file $BLDDIR/config.sh [$BLDDIR points to the proton build directory]:
 
   $ source config.sh
 
 This file sets the needed environment variables for all supported dynamic
-languages (Python, Perl, Ruby, PHP) as well as for Java and for testing. It,
-by default, assumes that you're building Proton in the directory:
-
-  $REPO/build
-
-where $REPO points the location where the Proton Subversion or Git repo has
-been checked out.
-
-If, however, you use a different location for your build files, then you'll want
-to set the environment variable CPROTON_BUILD to point to it first. So, for
-example, if you're building in:
-
-  /home/yourname/devel/proton/cmake
-
-then you would have the following environment variable set:
-
-  $ export CPROTON_BUILD=/hojme/yourname/devel/proton/cmake/proton-c
-
-NOTE: You need to point the environment variable to the proton-c directory under
-where your build is done.
+languages (Python, Perl, Ruby, PHP) as well as for Java and for testing.
 
+You will need to have set up the build directory first with cmake before the file
+will exist (see the instructions in README).
 
 
 MAILING LIST

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/config.bat.in
----------------------------------------------------------------------
diff --git a/config.bat.in b/config.bat.in
new file mode 100644
index 0000000..a73a88e
--- /dev/null
+++ b/config.bat.in
@@ -0,0 +1,66 @@
+REM
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements.  See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership.  The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License.  You may obtain a copy of the License at
+REM
+REM   http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied.  See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+REM
+
+REM This is a generated file and will be overwritten the next
+REM time that cmake is run.
+
+REM This build may be one of @CMAKE_CONFIGURATION_TYPES@
+REM Choose the configuration this script should reference:
+SET PROTON_BUILD_CONFIGURATION=relwithdebinfo
+
+REM PROTON_HOME  is the root of the proton checkout
+REM PROTON_BUILD is where cmake was run
+
+set PROTON_HOME=@CMAKE_SOURCE_DIR@
+set PROTON_BUILD=@CMAKE_BINARY_DIR@
+
+set PROTON_HOME=%PROTON_HOME:/=\%
+set PROTON_BUILD=%PROTON_BUILD:/=\%
+
+set PROTON_BINDINGS=%PROTON_BUILD%\proton-c\bindings
+set PROTON_JARS=%PROTON_BUILD%\proton-j\proton-j.jar
+
+REM Python & Jython
+set PYTHON_BINDINGS=%PROTON_BINDINGS%\python
+set COMMON_PYPATH=%PROTON_HOME%\tests\python;%PROTON_HOME%\proton-c\bindings\python
+set PYTHONPATH=%COMMON_PYPATH%;%PYTHON_BINDINGS%
+set JYTHONPATH=%COMMON_PYPATH%;%PROTON_HOME%\proton-j\src\main\resources;%PROTON_JARS%
+set CLASSPATH=%PROTON_JARS%
+
+REM PHP
+set PHP_BINDINGS=%PROTON_BINDINGS%\php
+if EXIST %PHP_BINDINGS% (
+    echo include_path="%PHP_BINDINGS%;%PROTON_HOME%\proton-c\bindings\php" >  %PHP_BINDINGS%\php.ini
+    echo extension="%PHP_BINDINGS%\cproton.so"                             >> %PHP_BINDINGS%\php.ini
+    set PHPRC=%PHP_BINDINGS%\php.ini
+)
+
+REM Ruby
+set RUBY_BINDINGS=%PROTON_BINDINGS%\ruby
+set RUBYLIB=%RUBY_BINDINGS%;%PROTON_HOME%\proton-c\bindings\ruby\lib;%PROTON_HOME%\tests\ruby
+
+REM Perl
+set PERL_BINDINGS=%PROTON_BINDINGS%\perl
+set PERL5LIB=%PERL5LIB%;%PERL_BINDINGS%;%PROTON_HOME%\proton-c\bindings\perl\lib
+
+REM test applications
+set PATH=%PATH%;%PROTON_BUILD%\tests\tools\apps\c
+set PATH=%PATH%;%PROTON_HOME%\tests\tools\apps\python
+set PATH=%PATH%;%PROTON_HOME%\tests\python
+set PATH=%PATH%;%PROTON_BUILD%\proton-c\%PROTON_BUILD_CONFIGURATION%

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/config.sh
----------------------------------------------------------------------
diff --git a/config.sh b/config.sh
deleted file mode 100755
index 90ad707..0000000
--- a/config.sh
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-# 
-#   http://www.apache.org/licenses/LICENSE-2.0
-# 
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-cd $(dirname ${BASH_SOURCE[0]}) > /dev/null
-export PROTON_HOME=$(pwd)
-cd - > /dev/null
-
-if [ -z "$CPROTON_BUILD" ]; then
-    if [ -d $PROTON_HOME/build/proton-c ]; then
-        PROTON_BINDINGS=$PROTON_HOME/build/proton-c/bindings
-    else
-        PROTON_BINDINGS=$PROTON_HOME/proton-c/bindings
-    fi
-    if [ -d $PROTON_HOME/build/proton-j ]; then
-        PROTON_JARS=$PROTON_HOME/build/proton-j/proton-api/proton-api.jar:$PROTON_HOME/build/proton-j/proton/proton-j-impl.jar
-    else
-        PROTON_JARS=$PROTON_HOME/proton-j/proton-api/proton-api.jar:$PROTON_HOME/proton-j/proton/proton-j-impl.jar
-    fi
-else
-    PROTON_BINDINGS=$CPROTON_BUILD/bindings
-fi
-
-# Python & Jython
-export PYTHON_BINDINGS=$PROTON_BINDINGS/python
-export COMMON_PYPATH=$PROTON_HOME/tests/python
-export PYTHONPATH=$COMMON_PYPATH:$PROTON_HOME/proton-c/bindings/python:$PYTHON_BINDINGS
-export JYTHONPATH=$COMMON_PYPATH:$PROTON_HOME/proton-j/proton-api/src/main/resources:$PROTON_JARS
-export CLASSPATH=$PROTON_JARS
-
-# PHP
-export PHP_BINDINGS=$PROTON_BINDINGS/php
-if [ -d $PHP_BINDINGS ]; then
-    cat <<EOF > $PHP_BINDINGS/php.ini
-include_path="$PHP_BINDINGS:$PROTON_HOME/proton-c/bindings/php"
-extension="$PHP_BINDINGS/cproton.so"
-EOF
-    export PHPRC=$PHP_BINDINGS/php.ini
-fi
-
-# Ruby
-export RUBY_BINDINGS=$PROTON_BINDINGS/ruby
-export RUBYLIB=$RUBY_BINDINGS:$PROTON_HOME/proton-c/bindings/ruby/lib:$PROTON_HOME/tests/ruby
-
-# Perl
-export PERL_BINDINGS=$PROTON_BINDINGS/perl
-export PERL5LIB=$PERL5LIB:$PERL_BINDINGS:$PROTON_HOME/proton-c/bindings/perl/lib
-
-# test applications
-if [ -d $PROTON_HOME/build/tests/tools/apps/c ]; then
-    export PATH="$PATH:$PROTON_HOME/build/tests/tools/apps/c"
-fi
-if [ -d $PROTON_HOME/tests/tools/apps/python ]; then
-    export PATH="$PATH:$PROTON_HOME/tests/tools/apps/python"
-fi
-
-# test applications
-export PATH="$PATH:$PROTON_HOME/tests/python"
-
-# can the test harness use valgrind?
-if [[ -x "$(type -p valgrind)" ]] ; then
-    export VALGRIND=1
-fi

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/config.sh.in
----------------------------------------------------------------------
diff --git a/config.sh.in b/config.sh.in
new file mode 100755
index 0000000..4b60b2f
--- /dev/null
+++ b/config.sh.in
@@ -0,0 +1,61 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+PROTON_HOME=@CMAKE_SOURCE_DIR@
+PROTON_BUILD=@CMAKE_BINARY_DIR@
+
+PROTON_BINDINGS=$PROTON_BUILD/proton-c/bindings
+PROTON_JARS=$PROTON_BUILD/proton-j/proton-j.jar
+
+PYTHON_BINDINGS=$PROTON_BINDINGS/python
+PHP_BINDINGS=$PROTON_BINDINGS/php
+RUBY_BINDINGS=$PROTON_BINDINGS/ruby
+PERL_BINDINGS=$PROTON_BINDINGS/perl
+
+# Python & Jython
+COMMON_PYPATH=$PROTON_HOME/tests/python:$PROTON_HOME/proton-c/bindings/python
+export PYTHONPATH=$COMMON_PYPATH:$PYTHON_BINDINGS
+export JYTHONPATH=$COMMON_PYPATH:$PROTON_HOME/proton-j/src/main/resources:$PROTON_JARS
+export CLASSPATH=$PROTON_JARS
+
+# PHP
+if [ -d $PHP_BINDINGS ]; then
+    cat <<EOF > $PHP_BINDINGS/php.ini
+include_path="$PHP_BINDINGS:$PROTON_HOME/proton-c/bindings/php"
+extension="$PHP_BINDINGS/cproton.so"
+EOF
+    export PHPRC=$PHP_BINDINGS/php.ini
+fi
+
+# Ruby
+export RUBYLIB=$RUBY_BINDINGS:$PROTON_HOME/proton-c/bindings/ruby/lib:$PROTON_HOME/tests/ruby
+
+# Perl
+export PERL5LIB=$PERL5LIB:$PERL_BINDINGS:$PROTON_HOME/proton-c/bindings/perl/lib
+
+# test applications
+export PATH="$PATH:$PROTON_BUILD/tests/tools/apps/c"
+export PATH="$PATH:$PROTON_HOME/tests/tools/apps/python"
+export PATH="$PATH:$PROTON_HOME/tests/python"
+
+# can the test harness use valgrind?
+if [[ -x "$(type -p valgrind)" ]] ; then
+    export VALGRIND=$(type -p valgrind)
+fi

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/pom.xml b/contrib/proton-hawtdispatch/pom.xml
new file mode 100644
index 0000000..0eaa171
--- /dev/null
+++ b/contrib/proton-hawtdispatch/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>proton-project</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <relativePath>../..</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>proton-hawtdispatch</artifactId>
+  <name>proton-hawtdispatch</name>
+
+  <properties>
+    <hawtbuf-version>1.9</hawtbuf-version>
+    <hawtdispatch-version>1.18</hawtdispatch-version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>proton-j</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.fusesource.hawtdispatch</groupId>
+      <artifactId>hawtdispatch-transport</artifactId>
+      <version>${hawtdispatch-version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.fusesource.hawtbuf</groupId>
+      <artifactId>hawtbuf</artifactId>
+      <version>${hawtbuf-version}</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+  </build>
+  <scm>
+    <url>http://svn.apache.org/viewvc/qpid/proton/</url>
+  </scm>
+
+</project>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnectOptions.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnectOptions.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnectOptions.java
new file mode 100644
index 0000000..3c3543d
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnectOptions.java
@@ -0,0 +1,228 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import org.fusesource.hawtdispatch.DispatchQueue;
+import org.fusesource.hawtdispatch.transport.TcpTransport;
+
+import javax.net.ssl.SSLContext;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class AmqpConnectOptions implements Cloneable {
+
+    private static final long KEEP_ALIVE = Long.parseLong(System.getProperty("amqp.thread.keep_alive", ""+1000));
+    private static final long STACK_SIZE = Long.parseLong(System.getProperty("amqp.thread.stack_size", ""+1024*512));
+    private static ThreadPoolExecutor blockingThreadPool;
+
+    public synchronized static ThreadPoolExecutor getBlockingThreadPool() {
+        if( blockingThreadPool == null ) {
+            blockingThreadPool = new ThreadPoolExecutor(0, Integer.MAX_VALUE, KEEP_ALIVE, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() {
+                    public Thread newThread(Runnable r) {
+                        Thread rc = new Thread(null, r, "AMQP Task", STACK_SIZE);
+                        rc.setDaemon(true);
+                        return rc;
+                    }
+                }) {
+
+                    @Override
+                    public void shutdown() {
+                        // we don't ever shutdown since we are shared..
+                    }
+
+                    @Override
+                    public List<Runnable> shutdownNow() {
+                        // we don't ever shutdown since we are shared..
+                        return Collections.emptyList();
+                    }
+                };
+        }
+        return blockingThreadPool;
+    }
+    public synchronized static void setBlockingThreadPool(ThreadPoolExecutor pool) {
+        blockingThreadPool = pool;
+    }
+
+    private static final URI DEFAULT_HOST;
+    static {
+        try {
+            DEFAULT_HOST = new URI("tcp://localhost");
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    URI host = DEFAULT_HOST;
+    URI localAddress;
+    SSLContext sslContext;
+    DispatchQueue dispatchQueue;
+    Executor blockingExecutor;
+    int maxReadRate;
+    int maxWriteRate;
+    int trafficClass = TcpTransport.IPTOS_THROUGHPUT;
+    boolean useLocalHost;
+    int receiveBufferSize = 1024*64;
+    int sendBufferSize = 1024*64;
+    String localContainerId;
+    String remoteContainerId;
+    String user;
+    String password;
+
+
+    @Override
+    public AmqpConnectOptions clone() {
+        try {
+            return (AmqpConnectOptions) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public String getLocalContainerId() {
+        return localContainerId;
+    }
+
+    public void setLocalContainerId(String localContainerId) {
+        this.localContainerId = localContainerId;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getRemoteContainerId() {
+        return remoteContainerId;
+    }
+
+    public void setRemoteContainerId(String remoteContainerId) {
+        this.remoteContainerId = remoteContainerId;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public Executor getBlockingExecutor() {
+        return blockingExecutor;
+    }
+
+    public void setBlockingExecutor(Executor blockingExecutor) {
+        this.blockingExecutor = blockingExecutor;
+    }
+
+    public DispatchQueue getDispatchQueue() {
+        return dispatchQueue;
+    }
+
+    public void setDispatchQueue(DispatchQueue dispatchQueue) {
+        this.dispatchQueue = dispatchQueue;
+    }
+
+    public URI getLocalAddress() {
+        return localAddress;
+    }
+
+    public void setLocalAddress(String localAddress) throws URISyntaxException {
+        this.setLocalAddress(new URI(localAddress));
+    }
+    public void setLocalAddress(URI localAddress) {
+        this.localAddress = localAddress;
+    }
+
+    public int getMaxReadRate() {
+        return maxReadRate;
+    }
+
+    public void setMaxReadRate(int maxReadRate) {
+        this.maxReadRate = maxReadRate;
+    }
+
+    public int getMaxWriteRate() {
+        return maxWriteRate;
+    }
+
+    public void setMaxWriteRate(int maxWriteRate) {
+        this.maxWriteRate = maxWriteRate;
+    }
+
+    public int getReceiveBufferSize() {
+        return receiveBufferSize;
+    }
+
+    public void setReceiveBufferSize(int receiveBufferSize) {
+        this.receiveBufferSize = receiveBufferSize;
+    }
+
+    public URI getHost() {
+        return host;
+    }
+    public void setHost(String host, int port) throws URISyntaxException {
+        this.setHost(new URI("tcp://"+host+":"+port));
+    }
+    public void setHost(String host) throws URISyntaxException {
+        this.setHost(new URI(host));
+    }
+    public void setHost(URI host) {
+        this.host = host;
+    }
+
+    public int getSendBufferSize() {
+        return sendBufferSize;
+    }
+
+    public void setSendBufferSize(int sendBufferSize) {
+        this.sendBufferSize = sendBufferSize;
+    }
+
+    public SSLContext getSslContext() {
+        return sslContext;
+    }
+
+    public void setSslContext(SSLContext sslContext) {
+        this.sslContext = sslContext;
+    }
+
+    public int getTrafficClass() {
+        return trafficClass;
+    }
+
+    public void setTrafficClass(int trafficClass) {
+        this.trafficClass = trafficClass;
+    }
+
+    public boolean isUseLocalHost() {
+        return useLocalHost;
+    }
+
+    public void setUseLocalHost(boolean useLocalHost) {
+        this.useLocalHost = useLocalHost;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnection.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnection.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnection.java
new file mode 100644
index 0000000..b308209
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnection.java
@@ -0,0 +1,201 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import org.apache.qpid.proton.amqp.transport.ErrorCondition;
+import org.apache.qpid.proton.hawtdispatch.impl.AmqpListener;
+import org.apache.qpid.proton.hawtdispatch.impl.AmqpTransport;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.Endpoint;
+import org.apache.qpid.proton.engine.ProtonJConnection;
+import org.apache.qpid.proton.engine.ProtonJSession;
+import org.apache.qpid.proton.engine.impl.ProtocolTracer;
+import org.fusesource.hawtdispatch.DispatchQueue;
+import org.fusesource.hawtdispatch.Task;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class AmqpConnection extends AmqpEndpointBase  {
+
+    AmqpTransport transport;
+    ProtonJConnection connection;
+    HashSet<AmqpSender> senders = new HashSet<AmqpSender>();
+    boolean closing = false;
+
+    public static AmqpConnection connect(AmqpConnectOptions options) {
+        return new AmqpConnection(options);
+    }
+
+    private AmqpConnection(AmqpConnectOptions options) {
+        transport = AmqpTransport.connect(options);
+        transport.setListener(new AmqpListener() {
+            @Override
+            public void processDelivery(Delivery delivery) {
+                Attachment attachment = (Attachment) getTransport().context(delivery.getLink()).getAttachment();
+                AmqpLink link = (AmqpLink) attachment.endpoint();
+                link.processDelivery(delivery);
+            }
+
+            @Override
+            public void processRefill() {
+                for(AmqpSender sender: new ArrayList<AmqpSender>(senders)) {
+                    sender.pumpDeliveries();
+                }
+                pumpOut();
+            }
+
+            public void processTransportFailure(final IOException e) {
+            }
+        });
+        connection = transport.connection();
+        connection.open();
+        attach();
+    }
+
+    public void waitForConnected() throws Exception {
+        assertNotOnDispatchQueue();
+        getConnectedFuture().await();
+    }
+
+    public Future<Void> getConnectedFuture() {
+        final Promise<Void> rc = new Promise<Void>();
+        queue().execute(new Task() {
+            @Override
+            public void run() {
+                onConnected(rc);
+            }
+        });
+        return rc;
+    }
+
+    public void onConnected(Callback<Void> cb) {
+        transport.onTransportConnected(cb);
+    }
+
+    @Override
+    protected Endpoint getEndpoint() {
+        return connection;
+    }
+
+    @Override
+    protected AmqpConnection getConnection() {
+        return this;
+    }
+
+    @Override
+    protected AmqpEndpointBase getParent() {
+        return null;
+    }
+
+    public AmqpSession createSession() {
+        assertExecuting();
+        ProtonJSession session = connection.session();
+        session.open();
+        pumpOut();
+        return new AmqpSession(this, session);
+    }
+
+    public int getMaxSessions() {
+        return connection.getMaxChannels();
+    }
+
+    public void disconnect() {
+        closing = true;
+        transport.disconnect();
+    }
+
+    public void waitForDisconnected() throws Exception {
+        assertNotOnDispatchQueue();
+        getDisconnectedFuture().await();
+    }
+
+    public Future<Void> getDisconnectedFuture() {
+        final Promise<Void> rc = new Promise<Void>();
+        queue().execute(new Task() {
+            @Override
+            public void run() {
+                onDisconnected(rc);
+            }
+        });
+        return rc;
+    }
+
+    public void onDisconnected(Callback<Void> cb) {
+        transport.onTransportDisconnected(cb);
+    }
+
+    public TransportState getTransportState() {
+        return transport.getState();
+    }
+
+    public Throwable getTransportFailure() {
+        return transport.getFailure();
+    }
+
+    public Future<Throwable> getTransportFailureFuture() {
+        final Promise<Throwable> rc = new Promise<Throwable>();
+        queue().execute(new Task() {
+            @Override
+            public void run() {
+                onTransportFailure(rc);
+            }
+        });
+        return rc;
+    }
+
+    public void onTransportFailure(Callback<Throwable> cb) {
+        transport.onTransportFailure(cb);
+    }
+
+    @Override
+    public DispatchQueue queue() {
+        return super.queue();
+    }
+
+    public void setProtocolTracer(ProtocolTracer protocolTracer) {
+        transport.setProtocolTracer(protocolTracer);
+    }
+
+    public ProtocolTracer getProtocolTracer() {
+        return transport.getProtocolTracer();
+    }
+
+    /**
+     * Once the remote end, closes the transport is disconnected.
+     */
+    @Override
+    public void close() {
+        super.close();
+        onRemoteClose(new Callback<ErrorCondition>() {
+            @Override
+            public void onSuccess(ErrorCondition value) {
+                disconnect();
+            }
+
+            @Override
+            public void onFailure(Throwable value) {
+                disconnect();
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpDeliveryListener.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpDeliveryListener.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpDeliveryListener.java
new file mode 100644
index 0000000..1e9f4e2
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpDeliveryListener.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public interface AmqpDeliveryListener {
+
+    /**
+     * Caller should suspend/resume the AmqpReceiver to
+     * flow control the delivery of messages.
+     *
+     * @param delivery
+     */
+    void onMessageDelivery(MessageDelivery delivery);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpEndpointBase.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpEndpointBase.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpEndpointBase.java
new file mode 100644
index 0000000..4ebd8e2
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpEndpointBase.java
@@ -0,0 +1,158 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.transport.ErrorCondition;
+import org.apache.qpid.proton.hawtdispatch.impl.*;
+import org.apache.qpid.proton.engine.Endpoint;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.fusesource.hawtdispatch.Dispatch;
+import org.fusesource.hawtdispatch.DispatchQueue;
+import org.fusesource.hawtdispatch.Task;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+abstract class AmqpEndpointBase extends WatchBase {
+    abstract protected Endpoint getEndpoint();
+    abstract protected AmqpEndpointBase getParent();
+
+    protected AmqpConnection getConnection() {
+        return getParent().getConnection();
+    }
+
+    protected AmqpTransport getTransport() {
+        return getConnection().transport;
+    }
+
+    protected DispatchQueue queue() {
+        return getTransport().queue();
+    }
+
+    protected void assertExecuting() {
+        getTransport().assertExecuting();
+    }
+
+    public void waitForRemoteOpen() throws Exception {
+        assertNotOnDispatchQueue();
+        getRemoteOpenFuture().await();
+    }
+
+    public Future<Void> getRemoteOpenFuture() {
+        final Promise<Void> rc = new Promise<Void>();
+        queue().execute(new Task() {
+            @Override
+            public void run() {
+                onRemoteOpen(rc);
+            }
+        });
+        return rc;
+    }
+
+    public void onRemoteOpen(final Callback<Void> cb) {
+        addWatch(new Watch() {
+            @Override
+            public boolean execute() {
+                switch (getEndpoint().getRemoteState()) {
+                    case ACTIVE:
+                        cb.onSuccess(null);
+                        return true;
+                    case CLOSED:
+                        cb.onFailure(Support.illegalState("closed"));
+                        return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    public ErrorCondition waitForRemoteClose() throws Exception {
+        assertNotOnDispatchQueue();
+        return getRemoteCloseFuture().await();
+    }
+
+    public Future<ErrorCondition> getRemoteCloseFuture() {
+        final Promise<ErrorCondition> rc = new Promise<ErrorCondition>();
+        queue().execute(new Task() {
+            @Override
+            public void run() {
+                onRemoteClose(rc);
+            }
+        });
+        return rc;
+    }
+
+    public void onRemoteClose(final Callback<ErrorCondition> cb) {
+        addWatch(new Watch() {
+            @Override
+            public boolean execute() {
+                if (getEndpoint().getRemoteState() == EndpointState.CLOSED) {
+                    cb.onSuccess(getEndpoint().getRemoteCondition());
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    public void close() {
+        getEndpoint().close();
+        pumpOut();
+    }
+
+    public EndpointState getRemoteState() {
+        return getEndpoint().getRemoteState();
+    }
+
+    public ErrorCondition getRemoteError() {
+        return getEndpoint().getRemoteCondition();
+    }
+
+    static protected ErrorCondition toError(Throwable value) {
+        return new ErrorCondition(Symbol.valueOf("error"), value.toString());
+    }
+
+    class Attachment extends Task {
+        AmqpEndpointBase endpoint() {
+            return AmqpEndpointBase.this;
+        }
+
+        @Override
+        public void run() {
+            fireWatches();
+        }
+    }
+
+    protected void attach() {
+        getTransport().context(getEndpoint()).setAttachment(new Attachment());
+    }
+
+    protected void defer(Defer defer) {
+        getTransport().defer(defer);
+    }
+
+    protected void pumpOut() {
+        getTransport().pumpOut();
+    }
+
+    static protected void assertNotOnDispatchQueue() {
+        assert Dispatch.getCurrentQueue()==null : "Not allowed to be called when executing on a dispatch queue";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpLink.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpLink.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpLink.java
new file mode 100644
index 0000000..dd6f32e
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpLink.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import org.apache.qpid.proton.engine.Delivery;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+abstract public class AmqpLink extends AmqpEndpointBase {
+    abstract protected void processDelivery(Delivery delivery);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpReceiver.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpReceiver.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpReceiver.java
new file mode 100644
index 0000000..644f72a
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpReceiver.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import org.apache.qpid.proton.hawtdispatch.impl.Defer;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.amqp.messaging.Accepted;
+import org.fusesource.hawtbuf.Buffer;
+import org.fusesource.hawtbuf.ByteArrayOutputStream;
+
+import java.util.LinkedList;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class AmqpReceiver extends AmqpLink {
+
+    final AmqpSession parent;
+    final Receiver receiver;
+
+    public AmqpReceiver(AmqpSession parent, Receiver receiver2, QoS qos) {
+        this.parent = parent;
+        this.receiver = receiver2;
+        attach();
+    }
+
+    @Override
+    protected Receiver getEndpoint() {
+        return receiver;
+    }
+    @Override
+    protected AmqpSession getParent() {
+        return parent;
+    }
+
+    ByteArrayOutputStream current = new ByteArrayOutputStream();
+
+    @Override
+    protected void processDelivery(Delivery delivery) {
+        if( !delivery.isReadable() ) {
+            System.out.println("it was not readable!");
+            return;
+        }
+
+        if( current==null ) {
+            current = new ByteArrayOutputStream();
+        }
+
+        int count;
+        byte data[] = new byte[1024*4];
+        while( (count = receiver.recv(data, 0, data.length)) > 0 ) {
+            current.write(data, 0, count);
+        }
+
+        // Expecting more deliveries..
+        if( count == 0 ) {
+            return;
+        }
+
+        receiver.advance();
+        Buffer buffer = current.toBuffer();
+        current = null;
+        onMessage(delivery, buffer);
+
+    }
+
+    LinkedList<MessageDelivery> inbound = new LinkedList<MessageDelivery>();
+
+    protected void onMessage(Delivery delivery, Buffer buffer) {
+        MessageDelivery md = new MessageDelivery(buffer) {
+            @Override
+            AmqpLink link() {
+                return AmqpReceiver.this;
+            }
+
+            @Override
+            public void settle() {
+                if( !delivery.isSettled() ) {
+                    delivery.disposition(new Accepted());
+                    delivery.settle();
+                }
+                drain();
+            }
+        };
+        md.delivery = delivery;
+        delivery.setContext(md);
+        inbound.add(md);
+        drainInbound();
+    }
+
+    public void drain() {
+        defer(deferedDrain);
+    }
+
+    Defer deferedDrain = new Defer(){
+        public void run() {
+            drainInbound();
+        }
+    };
+    int resumed = 0;
+
+    public void resume() {
+        resumed++;
+    }
+    public void suspend() {
+        resumed--;
+    }
+
+    AmqpDeliveryListener deliveryListener;
+    private void drainInbound() {
+        while( deliveryListener!=null && !inbound.isEmpty() && resumed>0) {
+            deliveryListener.onMessageDelivery(inbound.removeFirst());
+            receiver.flow(1);
+        }
+    }
+
+    public AmqpDeliveryListener getDeliveryListener() {
+        return deliveryListener;
+    }
+
+    public void setDeliveryListener(AmqpDeliveryListener deliveryListener) {
+        this.deliveryListener = deliveryListener;
+        drainInbound();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java
new file mode 100644
index 0000000..9a672d5
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java
@@ -0,0 +1,227 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import org.apache.qpid.proton.hawtdispatch.impl.Defer;
+import org.apache.qpid.proton.hawtdispatch.impl.Watch;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.amqp.messaging.Accepted;
+import org.apache.qpid.proton.amqp.messaging.Modified;
+import org.apache.qpid.proton.amqp.messaging.Rejected;
+import org.apache.qpid.proton.amqp.messaging.Released;
+import org.apache.qpid.proton.amqp.transport.DeliveryState;
+import org.fusesource.hawtbuf.Buffer;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class AmqpSender extends AmqpLink {
+
+    private  byte[] EMPTY_BYTE_ARRAY = new byte[]{};
+    long nextTagId = 0;
+    HashSet<byte[]> tagCache = new HashSet<byte[]>();
+
+    final AmqpSession parent;
+    private final QoS qos;
+    final Sender sender;
+
+    public AmqpSender(AmqpSession parent, Sender sender2, QoS qos) {
+        this.parent = parent;
+        this.sender = sender2;
+        this.qos = qos;
+        attach();
+        getConnection().senders.add(this);
+    }
+
+    @Override
+    public void close() {
+        super.close();
+        getConnection().senders.remove(this);
+    }
+
+    @Override
+    protected Sender getEndpoint() {
+        return sender;
+    }
+
+    @Override
+    protected AmqpSession getParent() {
+        return parent;
+    }
+
+    final LinkedList<MessageDelivery> outbound = new LinkedList<MessageDelivery>();
+    long outboundBufferSize;
+
+    public MessageDelivery send(Message message) {
+        assertExecuting();
+        MessageDelivery rc = new MessageDelivery(message) {
+            @Override
+            AmqpLink link() {
+                return AmqpSender.this;
+            }
+
+            @Override
+            public void redeliver(boolean incrementDeliveryCounter) {
+                super.redeliver(incrementDeliveryCounter);
+                outbound.add(this);
+                outboundBufferSize += initialSize;
+                defer(deferedPumpDeliveries);
+            }
+        };
+        outbound.add(rc);
+        outboundBufferSize += rc.initialSize;
+        pumpDeliveries();
+        pumpOut();
+        return rc;
+    }
+
+    Buffer currentBuffer;
+    Delivery currentDelivery;
+
+    Defer deferedPumpDeliveries = new Defer() {
+        public void run() {
+            pumpDeliveries();
+        }
+    };
+
+    public long getOverflowBufferSize() {
+        return outboundBufferSize;
+    }
+
+    protected void pumpDeliveries() {
+        assertExecuting();
+        try {
+            while(true) {
+                while( currentBuffer !=null ) {
+                    if( sender.getCredit() > 0 ) {
+                        int sent = sender.send(currentBuffer.data, currentBuffer.offset, currentBuffer.length);
+                        currentBuffer.moveHead(sent);
+                        if( currentBuffer.length == 0 ) {
+                            Delivery current = currentDelivery;
+                            MessageDelivery md = (MessageDelivery) current.getContext();
+                            currentBuffer = null;
+                            currentDelivery = null;
+                            if( qos == QoS.AT_MOST_ONCE ) {
+                                current.settle();
+                            } else {
+                                sender.advance();
+                            }
+                            md.fireWatches();
+                        }
+                    } else {
+                        return;
+                    }
+                }
+
+                if( outbound.isEmpty() ) {
+                    return;
+                }
+
+                final MessageDelivery md = outbound.removeFirst();
+                outboundBufferSize -= md.initialSize;
+                currentBuffer = md.encoded();
+                if( qos == QoS.AT_MOST_ONCE ) {
+                    currentDelivery = sender.delivery(EMPTY_BYTE_ARRAY, 0, 0);
+                } else {
+                    final byte[] tag = nextTag();
+                    currentDelivery = sender.delivery(tag, 0, tag.length);
+                }
+                md.delivery = currentDelivery;
+                currentDelivery.setContext(md);
+            }
+        } finally {
+            fireWatches();
+        }
+    }
+
+    @Override
+    protected void processDelivery(Delivery delivery) {
+        final MessageDelivery md  = (MessageDelivery) delivery.getContext();
+        if( delivery.remotelySettled() ) {
+            if( delivery.getTag().length > 0 ) {
+                checkinTag(delivery.getTag());
+            }
+
+            final DeliveryState state = delivery.getRemoteState();
+            if( state==null || state instanceof Accepted) {
+                if( !delivery.remotelySettled() ) {
+                    delivery.disposition(new Accepted());
+                }
+            } else if( state instanceof Rejected) {
+                // re-deliver /w incremented delivery counter.
+                md.delivery = null;
+                md.incrementDeliveryCount();
+                outbound.addLast(md);
+            } else if( state instanceof Released) {
+                // re-deliver && don't increment the counter.
+                md.delivery = null;
+                outbound.addLast(md);
+            } else if( state instanceof Modified) {
+                Modified modified = (Modified) state;
+                if ( modified.getDeliveryFailed() ) {
+                  // increment delivery counter..
+                  md.incrementDeliveryCount();
+                }
+            }
+            delivery.settle();
+        }
+        md.fireWatches();
+    }
+
+    byte[] nextTag() {
+        byte[] rc;
+        if (tagCache != null && !tagCache.isEmpty()) {
+            final Iterator<byte[]> iterator = tagCache.iterator();
+            rc = iterator.next();
+            iterator.remove();
+        } else {
+            try {
+                rc = Long.toHexString(nextTagId++).getBytes("UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return rc;
+    }
+
+    void checkinTag(byte[] data) {
+        if( tagCache.size() < 1024 ) {
+            tagCache.add(data);
+        }
+    }
+
+    public void onOverflowBufferDrained(final Callback<Void> cb) {
+        addWatch(new Watch() {
+            @Override
+            public boolean execute() {
+                if (outboundBufferSize==0) {
+                    cb.onSuccess(null);
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSession.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSession.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSession.java
new file mode 100644
index 0000000..b25a1b7
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSession.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
+import org.apache.qpid.proton.engine.Endpoint;
+import org.apache.qpid.proton.engine.Link;
+import org.apache.qpid.proton.engine.ProtonJSession;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.*;
+import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
+
+import java.util.UUID;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class AmqpSession extends AmqpEndpointBase {
+
+    final AmqpConnection parent;
+    final ProtonJSession session;
+
+
+    public AmqpSession(AmqpConnection parent, ProtonJSession session) {
+        this.parent = parent;
+        this.session = session;
+        attach();
+    }
+
+    @Override
+    protected Endpoint getEndpoint() {
+        return session;
+    }
+
+    @Override
+    protected AmqpConnection getParent() {
+        return parent;
+    }
+
+    public AmqpSender createSender(Target target) {
+        return createSender(target, QoS.AT_LEAST_ONCE);
+    }
+
+    public AmqpSender createSender(Target target, QoS qos) {
+        return createSender(target, qos, UUID.randomUUID().toString());
+    }
+
+    public AmqpSender createSender(Target target, QoS qos, String name) {
+        assertExecuting();
+        Sender sender = session.sender(name);
+        attach();
+//        Source source = new Source();
+//        source.setAddress(UUID.randomUUID().toString());
+//        sender.setSource(source);
+        sender.setTarget(target);
+        configureQos(sender, qos);
+        sender.open();
+        pumpOut();
+        return new AmqpSender(this, sender, qos);
+    }
+
+    public AmqpReceiver createReceiver(Source source) {
+        return createReceiver(source, QoS.AT_LEAST_ONCE);
+    }
+
+    public AmqpReceiver createReceiver(Source source, QoS qos) {
+        return createReceiver(source, qos, 100);
+    }
+
+    public AmqpReceiver createReceiver(Source source, QoS qos, int prefetch) {
+        return createReceiver(source, qos, prefetch,  UUID.randomUUID().toString());
+    }
+
+    public AmqpReceiver createReceiver(Source source, QoS qos, int prefetch, String name) {
+        assertExecuting();
+        Receiver receiver = session.receiver(name);
+        receiver.setSource(source);
+//        Target target = new Target();
+//        target.setAddress(UUID.randomUUID().toString());
+//        receiver.setTarget(target);
+        receiver.flow(prefetch);
+        configureQos(receiver, qos);
+        receiver.open();
+        pumpOut();
+        return new AmqpReceiver(this, receiver, qos);
+    }
+
+    private void configureQos(Link link, QoS qos) {
+        switch (qos) {
+            case AT_MOST_ONCE:
+                link.setSenderSettleMode(SenderSettleMode.SETTLED);
+                link.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+                break;
+            case AT_LEAST_ONCE:
+                link.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+                link.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+                break;
+            case EXACTLY_ONCE:
+                link.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+                link.setReceiverSettleMode(ReceiverSettleMode.SECOND);
+                break;
+        }
+    }
+
+    public Message createTextMessage(String value) {
+        Message msg = Message.Factory.create();
+        Section body = new AmqpValue(value);
+        msg.setBody(body);
+        return msg;
+    }
+
+    public Message createBinaryMessage(byte value[]) {
+        return createBinaryMessage(value, 0, value.length);
+    }
+
+    public Message createBinaryMessage(byte value[], int offset, int len) {
+        Message msg = Message.Factory.create();
+        Data body = new Data(new Binary(value, offset,len));
+        msg.setBody(body);
+        return msg;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Callback.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Callback.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Callback.java
new file mode 100644
index 0000000..89fbdd1
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Callback.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.hawtdispatch.api;
+
+/**
+ * <p>
+ * Function Result that carries one value.
+ * </p>
+ *
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public interface Callback<T> {
+    public void onSuccess(T value);
+    public void onFailure(Throwable value);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/ChainedCallback.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/ChainedCallback.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/ChainedCallback.java
new file mode 100644
index 0000000..e53f512
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/ChainedCallback.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.hawtdispatch.api;
+
+/**
+ * <p>
+ * Function Result that carries one value.
+ * </p>
+ *
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+abstract public class ChainedCallback<In,Out> implements Callback<In> {
+
+    public final Callback<Out> next;
+
+    public ChainedCallback(Callback<Out> next) {
+        this.next = next;
+    }
+
+    public void onFailure(Throwable value) {
+        next.onFailure(value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/DeliveryAttachment.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/DeliveryAttachment.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/DeliveryAttachment.java
new file mode 100644
index 0000000..290076f
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/DeliveryAttachment.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import org.apache.qpid.proton.engine.Delivery;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+abstract public class DeliveryAttachment {
+    abstract void processDelivery(Delivery delivery);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Future.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Future.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Future.java
new file mode 100644
index 0000000..4a9eb5e
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Future.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * <p>A simplified Future function results interface.</p>
+ *
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public interface Future<T> {
+    T await() throws Exception;
+    T await(long amount, TimeUnit unit) throws Exception;
+    void then(Callback<T> callback);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java
new file mode 100644
index 0000000..b115557
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java
@@ -0,0 +1,226 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import org.apache.qpid.proton.amqp.transport.DeliveryState;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.hawtdispatch.impl.Watch;
+import org.apache.qpid.proton.hawtdispatch.impl.WatchBase;
+import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.message.ProtonJMessage;
+import org.fusesource.hawtbuf.Buffer;
+import org.fusesource.hawtdispatch.Task;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public abstract class MessageDelivery extends WatchBase {
+
+    final int initialSize;
+    private Message message;
+    private Buffer encoded;
+    public Delivery delivery;
+    private int sizeHint = 32;
+
+    static Buffer encode(Message message, int sizeHint) {
+        byte[] buffer = new byte[sizeHint];
+        int size = ((ProtonJMessage)message).encode2(buffer, 0, sizeHint);
+        if( size > sizeHint ) {
+            buffer = new byte[size];
+            size = message.encode(buffer, 0, size);
+        }
+        return new Buffer(buffer, 0, size);
+    }
+
+    static Message decode(Buffer buffer) {
+        Message msg = Message.Factory.create();
+        int offset = buffer.offset;
+        int len = buffer.length;
+        while( len > 0 ) {
+            int decoded = msg.decode(buffer.data, offset, len);
+            assert decoded > 0: "Make progress decoding the message";
+            offset += decoded;
+            len -= decoded;
+        }
+        return msg;
+    }
+
+    public MessageDelivery(Message message) {
+        this(message, encode(message, 32));
+    }
+
+    public MessageDelivery(Buffer encoded) {
+        this(null, encoded);
+    }
+
+    public MessageDelivery(Message message, Buffer encoded) {
+        this.message = message;
+        this.encoded = encoded;
+        sizeHint = this.encoded.length;
+        initialSize = sizeHint;
+    }
+
+    public Message getMessage() {
+        if( message == null ) {
+            message = decode(encoded);
+        }
+        return message;
+    }
+
+    public Buffer encoded() {
+        if( encoded == null ) {
+            encoded = encode(message, sizeHint);
+            sizeHint = encoded.length;
+        }
+        return encoded;
+    }
+
+    public boolean isSettled() {
+        return delivery!=null && delivery.isSettled();
+    }
+
+    public DeliveryState getRemoteState() {
+        return delivery==null ? null : delivery.getRemoteState();
+    }
+
+    public DeliveryState getLocalState() {
+        return delivery==null ? null : delivery.getLocalState();
+    }
+
+    public void onEncoded(final Callback<Void> cb) {
+        addWatch(new Watch() {
+            @Override
+            public boolean execute() {
+                if( delivery!=null ) {
+                    cb.onSuccess(null);
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    /**
+     * @return the remote delivery state when it changes.
+     * @throws Exception
+     */
+    public DeliveryState getRemoteStateChange() throws Exception {
+        AmqpEndpointBase.assertNotOnDispatchQueue();
+        return getRemoteStateChangeFuture().await();
+    }
+
+    /**
+     * @return the future remote delivery state when it changes.
+     */
+    public Future<DeliveryState> getRemoteStateChangeFuture() {
+        final Promise<DeliveryState> rc = new Promise<DeliveryState>();
+        link().queue().execute(new Task() {
+            @Override
+            public void run() {
+                onRemoteStateChange(rc);
+            }
+        });
+        return rc;
+    }
+
+    abstract AmqpLink link();
+
+    boolean watchingRemoteStateChange;
+    public void onRemoteStateChange(final Callback<DeliveryState> cb) {
+        watchingRemoteStateChange = true;
+        final DeliveryState original = delivery.getRemoteState();
+        addWatch(new Watch() {
+            @Override
+            public boolean execute() {
+                if (original == null) {
+                    if( delivery.getRemoteState()!=null ) {
+                        cb.onSuccess(delivery.getRemoteState());
+                        watchingRemoteStateChange = false;
+                        return true;
+                    }
+                } else {
+                    if( !original.equals(delivery.getRemoteState()) ) {
+                        cb.onSuccess(delivery.getRemoteState());
+                        watchingRemoteStateChange = false;
+                        return true;
+                    }
+                }
+                return false;
+            }
+        });
+    }
+
+    /**
+     * @return the remote delivery state once settled.
+     * @throws Exception
+     */
+    public DeliveryState getSettle() throws Exception {
+        AmqpEndpointBase.assertNotOnDispatchQueue();
+        return getSettleFuture().await();
+    }
+
+    /**
+     * @return the future remote delivery state once the delivery is settled.
+     */
+    public Future<DeliveryState> getSettleFuture() {
+        final Promise<DeliveryState> rc = new Promise<DeliveryState>();
+        link().queue().execute(new Task() {
+            @Override
+            public void run() {
+                onSettle(rc);
+            }
+        });
+        return rc;
+    }
+
+    public void onSettle(final Callback<DeliveryState> cb) {
+        addWatch(new Watch() {
+            @Override
+            public boolean execute() {
+                if( delivery!=null && delivery.isSettled() ) {
+                    cb.onSuccess(delivery.getRemoteState());
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    @Override
+    protected void fireWatches() {
+        super.fireWatches();
+    }
+
+    void incrementDeliveryCount() {
+        Message msg = getMessage();
+        msg.setDeliveryCount(msg.getDeliveryCount()+1);
+        encoded = null;
+    }
+
+    public void redeliver(boolean incrementDeliveryCounter) {
+        if( incrementDeliveryCounter ) {
+            incrementDeliveryCount();
+        }
+    }
+
+    public void settle() {
+        if( !delivery.isSettled() ) {
+            delivery.settle();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Promise.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Promise.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Promise.java
new file mode 100644
index 0000000..b914b44
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/Promise.java
@@ -0,0 +1,107 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * <p>
+ * </p>
+ *
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class Promise<T> implements Callback<T>, Future<T> {
+
+    private final CountDownLatch latch = new CountDownLatch(1);
+    Callback<T> next;
+    Throwable error;
+    T value;
+
+    public void onFailure(Throwable value) {
+        Callback<T> callback = null;
+        synchronized(this)  {
+            error = value;
+            latch.countDown();
+            callback = next;
+        }
+        if( callback!=null ) {
+            callback.onFailure(value);
+        }
+    }
+
+    public void onSuccess(T value) {
+        Callback<T> callback = null;
+        synchronized(this)  {
+            this.value = value;
+            latch.countDown();
+            callback = next;
+        }
+        if( callback!=null ) {
+            callback.onSuccess(value);
+        }
+    }
+
+    public void then(Callback<T> callback) {
+        boolean fire = false;
+        synchronized(this)  {
+            next = callback;
+            if( latch.getCount() == 0 ) {
+                fire = true;
+            }
+        }
+        if( fire ) {
+            if( error!=null ) {
+                callback.onFailure(error);
+            } else {
+                callback.onSuccess(value);
+            }
+        }
+    }
+
+    public T await(long amount, TimeUnit unit) throws Exception {
+        if( latch.await(amount, unit) ) {
+            return get();
+        } else {
+            throw new TimeoutException();
+        }
+    }
+
+    public T await() throws Exception {
+        latch.await();
+        return get();
+    }
+
+    private T get() throws Exception {
+        Throwable e = error;
+        if( e !=null ) {
+            if( e instanceof RuntimeException ) {
+                throw (RuntimeException) e;
+            } else if( e instanceof Exception) {
+                throw (Exception) e;
+            } else if( e instanceof Error) {
+                throw (Error) e;
+            } else {
+                // don't expect to hit this case.
+                throw new RuntimeException(e);
+            }
+        }
+        return value;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/QoS.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/QoS.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/QoS.java
new file mode 100644
index 0000000..5b4a8dc
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/QoS.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.hawtdispatch.api;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public enum QoS {
+    AT_MOST_ONCE,
+    AT_LEAST_ONCE,
+    EXACTLY_ONCE
+}


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


[43/51] [abbrv] qpid-proton git commit: Sync with proton trunk revision 1627945 and update CMakeLists.txt

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/windows/driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/driver.c b/proton-c/src/windows/driver.c
index 3dadadb..ddccd82 100644
--- a/proton-c/src/windows/driver.c
+++ b/proton-c/src/windows/driver.c
@@ -19,59 +19,37 @@
  *
  */
 
-/*
- * Copy of posix poll-based driver with minimal changes to use
- * select().  TODO: fully native implementaton with I/O completion
- * ports.
- *
- * This implementation comments out the posix max_fds arg to select
- * which has no meaning on windows.  The number of fd_set slots are
- * configured at compile time via FD_SETSIZE, chosen "large enough"
- * for the limited scalability of select() at the expense of
- * 2*N*sizeof(unsigned int) bytes per driver instance.  select (and
- * associated macros like FD_ZERO) are otherwise unaffected
- * performance-wise by increasing FD_SETSIZE.
- */
-
-#define FD_SETSIZE 2048
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#if _WIN32_WINNT < 0x0501
-#error "Proton requires Windows API support for XP or later."
-#endif
-#include <winsock2.h>
-#include <Ws2tcpip.h>
-#define PN_WINAPI
-
 #include <assert.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <fcntl.h>
 
-#include "../platform.h"
-#include <proton/io.h>
 #include <proton/driver.h>
 #include <proton/driver_extras.h>
 #include <proton/error.h>
+#include <proton/io.h>
 #include <proton/sasl.h>
 #include <proton/ssl.h>
-#include <proton/util.h>
-#include "../util.h"
-#include "../ssl/ssl-internal.h"
-
+#include <proton/object.h>
+#include <proton/selector.h>
 #include <proton/types.h>
+#include "selectable.h"
+#include "util.h"
+#include "platform.h"
 
-/* Posix compatibility helpers */
-
-static int pn_socket_pair(SOCKET sv[2]);
-#define close(sock) closesocket(sock)
-static int pn_i_error_from_errno_wrap(pn_error_t *error, const char *msg) {
-  errno = WSAGetLastError();
-  return pn_i_error_from_errno(error, msg);
-}
-#define pn_i_error_from_errno(e,m) pn_i_error_from_errno_wrap(e,m)
+/*
+ * This driver provides limited thread safety for some operations on pn_connector_t objects.
+ *
+ * These calls are: pn_connector_process(), pn_connector_activate(), pn_connector_activated(),
+ * pn_connector_close(), and others that only touch the connection object, i.e.
+ * pn_connector_context().  These calls provide limited safety in that simultaneous calls are
+ * not allowed to the same pn_connector_t object.
+ *
+ * The application must call pn_driver_wakeup() and resume its wait loop logic if a call to
+ * pn_wait() may have overlapped with any of the above calls that could affect a pn_wait()
+ * outcome.
+ */
 
 /* Decls */
 
@@ -81,82 +59,137 @@ static int pn_i_error_from_errno_wrap(pn_error_t *error, const char *msg) {
 struct pn_driver_t {
   pn_error_t *error;
   pn_io_t *io;
+  pn_selector_t *selector;
   pn_listener_t *listener_head;
   pn_listener_t *listener_tail;
   pn_listener_t *listener_next;
   pn_connector_t *connector_head;
   pn_connector_t *connector_tail;
-  pn_connector_t *connector_next;
+  pn_listener_t *ready_listener_head;
+  pn_listener_t *ready_listener_tail;
+  pn_connector_t *ready_connector_head;
+  pn_connector_t *ready_connector_tail;
+  pn_selectable_t *ctrl_selectable;
   size_t listener_count;
   size_t connector_count;
-  size_t closed_count;
-  fd_set readfds;
-  fd_set writefds;
-  fd_set exceptfds;
-  // int max_fds;
-  bool overflow;
   pn_socket_t ctrl[2]; //pipe for updating selectable status
-
   pn_trace_t trace;
-  pn_timestamp_t wakeup;
 };
 
+typedef enum {LISTENER, CONNECTOR} sel_type_t;
+
 struct pn_listener_t {
+  sel_type_t type;
   pn_driver_t *driver;
   pn_listener_t *listener_next;
   pn_listener_t *listener_prev;
-  int idx;
+  pn_listener_t *ready_listener_next;
+  pn_listener_t *ready_listener_prev;
+  void *context;
+  pn_selectable_t *selectable;
   bool pending;
-  pn_socket_t fd;
   bool closed;
-  void *context;
 };
 
 #define PN_NAME_MAX (256)
 
 struct pn_connector_t {
+  sel_type_t type;
   pn_driver_t *driver;
   pn_connector_t *connector_next;
   pn_connector_t *connector_prev;
+  pn_connector_t *ready_connector_next;
+  pn_connector_t *ready_connector_prev;
   char name[PN_NAME_MAX];
+  pn_timestamp_t wakeup;
+  pn_timestamp_t posted_wakeup;
+  pn_connection_t *connection;
+  pn_transport_t *transport;
+  pn_sasl_t *sasl;
+  pn_listener_t *listener;
+  void *context;
+  pn_selectable_t *selectable;
   int idx;
+  int status;
+  int posted_status;
+  pn_trace_t trace;
   bool pending_tick;
   bool pending_read;
   bool pending_write;
-  pn_socket_t fd;
-  int status;
-  pn_trace_t trace;
   bool closed;
-  pn_timestamp_t wakeup;
-  pn_connection_t *connection;
-  pn_transport_t *transport;
-  pn_sasl_t *sasl;
   bool input_done;
   bool output_done;
-  pn_listener_t *listener;
-  void *context;
 };
 
+static void get_new_events(pn_driver_t *);
+
 /* Impls */
 
 // listener
 
+static void driver_listener_readable(pn_selectable_t *sel)
+{
+  // do nothing
+}
+
+static void driver_listener_writable(pn_selectable_t *sel)
+{
+  // do nothing
+}
+
+static void driver_listener_expired(pn_selectable_t *sel)
+{
+  // do nothing
+}
+
+static ssize_t driver_listener_capacity(pn_selectable_t *sel)
+{
+  return 1;
+}
+
+static ssize_t driver_listener_pending(pn_selectable_t *sel)
+{
+  return 0;
+}
+
+static pn_timestamp_t driver_listener_deadline(pn_selectable_t *sel)
+{
+  return 0;
+}
+
+static void driver_listener_finalize(pn_selectable_t *sel)
+{
+  // do nothing
+}
+
+
 static void pn_driver_add_listener(pn_driver_t *d, pn_listener_t *l)
 {
   if (!l->driver) return;
   LL_ADD(d, listener, l);
   l->driver = d;
   d->listener_count++;
+  pn_selector_add(d->selector, l->selectable);
+}
+
+static void ready_listener_list_remove(pn_driver_t *d, pn_listener_t *l)
+{
+  LL_REMOVE(d, ready_listener, l);
+  l->ready_listener_next = NULL;
+  l->ready_listener_prev = NULL;
 }
 
 static void pn_driver_remove_listener(pn_driver_t *d, pn_listener_t *l)
 {
   if (!l->driver) return;
 
+  pn_selector_remove(d->selector, l->selectable);
+  if (l == d->ready_listener_head || l->ready_listener_prev)
+    ready_listener_list_remove(d, l);
+
   if (l == d->listener_next) {
     d->listener_next = l->listener_next;
   }
-
   LL_REMOVE(d, listener, l);
   l->driver = NULL;
   d->listener_count--;
@@ -169,7 +202,7 @@ pn_listener_t *pn_listener(pn_driver_t *driver, const char *host,
 
   pn_socket_t sock = pn_listen(driver->io, host, port);
 
-  if (sock == INVALID_SOCKET) {
+  if (sock == PN_INVALID_SOCKET) {
     return NULL;
   } else {
     pn_listener_t *l = pn_listener_fd(driver, sock, context);
@@ -186,15 +219,24 @@ pn_listener_t *pn_listener_fd(pn_driver_t *driver, pn_socket_t fd, void *context
 
   pn_listener_t *l = (pn_listener_t *) malloc(sizeof(pn_listener_t));
   if (!l) return NULL;
+  l->type = LISTENER;
   l->driver = driver;
   l->listener_next = NULL;
   l->listener_prev = NULL;
-  l->idx = 0;
+  l->ready_listener_next = NULL;
+  l->ready_listener_prev = NULL;
   l->pending = false;
-  l->fd = fd;
   l->closed = false;
   l->context = context;
-
+  l->selectable = pni_selectable(driver_listener_capacity,
+                                 driver_listener_pending,
+                                 driver_listener_deadline,
+                                 driver_listener_readable,
+                                 driver_listener_writable,
+                                 driver_listener_expired,
+                                 driver_listener_finalize);
+  pni_selectable_set_fd(l->selectable, fd);
+  pni_selectable_set_context(l->selectable, l);
   pn_driver_add_listener(driver, l);
   return l;
 }
@@ -202,7 +244,7 @@ pn_listener_t *pn_listener_fd(pn_driver_t *driver, pn_socket_t fd, void *context
 pn_socket_t pn_listener_get_fd(pn_listener_t *listener)
 {
   assert(listener);
-  return listener->fd;
+  return pn_selectable_fd(listener->selectable);
 }
 
 pn_listener_t *pn_listener_head(pn_driver_t *driver)
@@ -234,8 +276,8 @@ pn_connector_t *pn_listener_accept(pn_listener_t *l)
   if (!l || !l->pending) return NULL;
   char name[PN_NAME_MAX];
 
-  pn_socket_t sock = pn_accept(l->driver->io, l->fd, name, PN_NAME_MAX);
-  if (sock == INVALID_SOCKET) {
+  pn_socket_t sock = pn_accept(l->driver->io, pn_selectable_fd(l->selectable), name, PN_NAME_MAX);
+  if (sock == PN_INVALID_SOCKET) {
     return NULL;
   } else {
     if (l->driver->trace & (PN_TRACE_FRM | PN_TRACE_RAW | PN_TRACE_DRV))
@@ -252,8 +294,7 @@ void pn_listener_close(pn_listener_t *l)
   if (!l) return;
   if (l->closed) return;
 
-  if (close(l->fd) == -1)
-    perror("close");
+  pn_close(l->driver->io, pn_selectable_fd(l->selectable));
   l->closed = true;
 }
 
@@ -262,45 +303,85 @@ void pn_listener_free(pn_listener_t *l)
   if (!l) return;
 
   if (l->driver) pn_driver_remove_listener(l->driver, l);
+  pn_selectable_free(l->selectable);
   free(l);
 }
 
 // connector
 
+static ssize_t driver_connection_capacity(pn_selectable_t *sel)
+{
+  pn_connector_t *c = (pn_connector_t *) pni_selectable_get_context(sel);
+  return c->posted_status & PN_SEL_RD ? 1 : 0;
+}
+
+static ssize_t driver_connection_pending(pn_selectable_t *sel)
+{
+  pn_connector_t *c = (pn_connector_t *) pni_selectable_get_context(sel);
+  return c->posted_status & PN_SEL_WR ? 1 : 0;
+}
+
+static pn_timestamp_t driver_connection_deadline(pn_selectable_t *sel)
+{
+  pn_connector_t *c = (pn_connector_t *) pni_selectable_get_context(sel);
+  return c->posted_wakeup;
+}
+
+static void driver_connection_readable(pn_selectable_t *sel)
+{
+  // do nothing
+}
+
+static void driver_connection_writable(pn_selectable_t *sel)
+{
+  // do nothing
+}
+
+static void driver_connection_expired(pn_selectable_t *sel)
+{
+  // do nothing
+}
+
+static void driver_connection_finalize(pn_selectable_t *sel)
+{
+  // do nothing
+}
+
 static void pn_driver_add_connector(pn_driver_t *d, pn_connector_t *c)
 {
   if (!c->driver) return;
   LL_ADD(d, connector, c);
   c->driver = d;
   d->connector_count++;
+  pn_selector_add(d->selector, c->selectable);
+}
+
+static void ready_connector_list_remove(pn_driver_t *d, pn_connector_t *c)
+{
+  LL_REMOVE(d, ready_connector, c);
+  c->ready_connector_next = NULL;
+  c->ready_connector_prev = NULL;
 }
 
 static void pn_driver_remove_connector(pn_driver_t *d, pn_connector_t *c)
 {
   if (!c->driver) return;
 
-  if (c == d->connector_next) {
-    d->connector_next = c->connector_next;
-  }
+  pn_selector_remove(d->selector, c->selectable);
+  if (c == d->ready_connector_head || c->ready_connector_prev)
+    ready_connector_list_remove(d, c);
 
   LL_REMOVE(d, connector, c);
   c->driver = NULL;
   d->connector_count--;
-  if (c->closed) {
-    d->closed_count--;
-  }
 }
 
-pn_connector_t *pn_connector(pn_driver_t *driver, const char *hostarg,
+pn_connector_t *pn_connector(pn_driver_t *driver, const char *host,
                              const char *port, void *context)
 {
   if (!driver) return NULL;
 
-  // convert "0.0.0.0" to "127.0.0.1" on Windows for outgoing sockets
-  const char *host = strcmp("0.0.0.0", hostarg) ? hostarg : "127.0.0.1";
-
   pn_socket_t sock = pn_connect(driver->io, host, port);
-
   pn_connector_t *c = pn_connector_fd(driver, sock, context);
   snprintf(c->name, PN_NAME_MAX, "%s:%s", host, port);
   if (driver->trace & (PN_TRACE_FRM | PN_TRACE_RAW | PN_TRACE_DRV))
@@ -308,28 +389,28 @@ pn_connector_t *pn_connector(pn_driver_t *driver, const char *hostarg,
   return c;
 }
 
-static void pn_connector_read(pn_connector_t *ctor);
-static void pn_connector_write(pn_connector_t *ctor);
-
 pn_connector_t *pn_connector_fd(pn_driver_t *driver, pn_socket_t fd, void *context)
 {
   if (!driver) return NULL;
 
   pn_connector_t *c = (pn_connector_t *) malloc(sizeof(pn_connector_t));
   if (!c) return NULL;
+  c->type = CONNECTOR;
   c->driver = driver;
   c->connector_next = NULL;
   c->connector_prev = NULL;
+  c->ready_connector_next = NULL;
+  c->ready_connector_prev = NULL;
   c->pending_tick = false;
   c->pending_read = false;
   c->pending_write = false;
   c->name[0] = '\0';
-  c->idx = 0;
-  c->fd = fd;
   c->status = PN_SEL_RD | PN_SEL_WR;
+  c->posted_status = -1;
   c->trace = driver->trace;
   c->closed = false;
   c->wakeup = 0;
+  c->posted_wakeup = 0;
   c->connection = NULL;
   c->transport = pn_transport();
   c->sasl = pn_sasl(c->transport);
@@ -337,7 +418,15 @@ pn_connector_t *pn_connector_fd(pn_driver_t *driver, pn_socket_t fd, void *conte
   c->output_done = false;
   c->context = context;
   c->listener = NULL;
-
+  c->selectable = pni_selectable(driver_connection_capacity,
+                                 driver_connection_pending,
+                                 driver_connection_deadline,
+                                 driver_connection_readable,
+                                 driver_connection_writable,
+                                 driver_connection_expired,
+                                 driver_connection_finalize);
+  pni_selectable_set_fd(c->selectable, fd);
+  pni_selectable_set_context(c->selectable, c);
   pn_connector_trace(c, driver->trace);
 
   pn_driver_add_connector(driver, c);
@@ -347,7 +436,7 @@ pn_connector_t *pn_connector_fd(pn_driver_t *driver, pn_socket_t fd, void *conte
 pn_socket_t pn_connector_get_fd(pn_connector_t *connector)
 {
   assert(connector);
-  return connector->fd;
+  return pn_selectable_fd(connector->selectable);
 }
 
 pn_connector_t *pn_connector_head(pn_driver_t *driver)
@@ -380,8 +469,15 @@ pn_transport_t *pn_connector_transport(pn_connector_t *ctor)
 void pn_connector_set_connection(pn_connector_t *ctor, pn_connection_t *connection)
 {
   if (!ctor) return;
+  if (ctor->connection) {
+    pn_decref(ctor->connection);
+    pn_transport_unbind(ctor->transport);
+  }
   ctor->connection = connection;
-  pn_transport_bind(ctor->transport, connection);
+  if (ctor->connection) {
+    pn_incref(ctor->connection);
+    pn_transport_bind(ctor->transport, connection);
+  }
   if (ctor->transport) pn_transport_trace(ctor->transport, ctor->trace);
 }
 
@@ -418,10 +514,8 @@ void pn_connector_close(pn_connector_t *ctor)
   if (!ctor) return;
 
   ctor->status = 0;
-  if (close(ctor->fd) == -1)
-    perror("close");
+  pn_close(ctor->driver->io, pn_selectable_fd(ctor->selectable));
   ctor->closed = true;
-  ctor->driver->closed_count++;
 }
 
 bool pn_connector_closed(pn_connector_t *ctor)
@@ -434,9 +528,11 @@ void pn_connector_free(pn_connector_t *ctor)
   if (!ctor) return;
 
   if (ctor->driver) pn_driver_remove_connector(ctor->driver, ctor);
-  ctor->connection = NULL;
   pn_transport_free(ctor->transport);
   ctor->transport = NULL;
+  if (ctor->connection) pn_decref(ctor->connection);
+  ctor->connection = NULL;
+  pn_selectable_free(ctor->selectable);
   free(ctor);
 }
 
@@ -487,6 +583,7 @@ void pn_connector_process(pn_connector_t *c)
     if (c->closed) return;
 
     pn_transport_t *transport = c->transport;
+    pn_socket_t sock = pn_selectable_fd(c->selectable);
 
     ///
     /// Socket read
@@ -497,7 +594,7 @@ void pn_connector_process(pn_connector_t *c)
         c->status |= PN_SEL_RD;
         if (c->pending_read) {
           c->pending_read = false;
-          ssize_t n =  pn_recv(c->driver->io, c->fd, pn_transport_tail(transport), capacity);
+          ssize_t n =  pn_recv(c->driver->io, sock, pn_transport_tail(transport), capacity);
           if (n < 0) {
             if (errno != EAGAIN) {
               perror("read");
@@ -540,7 +637,7 @@ void pn_connector_process(pn_connector_t *c)
         c->status |= PN_SEL_WR;
         if (c->pending_write) {
           c->pending_write = false;
-          ssize_t n = pn_send(c->driver->io, c->fd, pn_transport_head(transport), pending);
+          ssize_t n = pn_send(c->driver->io, sock, pn_transport_head(transport), pending);
           if (n < 0) {
             // XXX
             if (errno != EAGAIN) {
@@ -574,35 +671,41 @@ void pn_connector_process(pn_connector_t *c)
 
 // driver
 
+static pn_selectable_t *create_ctrl_selectable(pn_socket_t fd);
+
 pn_driver_t *pn_driver()
 {
   pn_driver_t *d = (pn_driver_t *) malloc(sizeof(pn_driver_t));
   if (!d) return NULL;
+
   d->error = pn_error();
   d->io = pn_io();
+  d->selector = pn_io_selector(d->io);
   d->listener_head = NULL;
   d->listener_tail = NULL;
   d->listener_next = NULL;
+  d->ready_listener_head = NULL;
+  d->ready_listener_tail = NULL;
   d->connector_head = NULL;
   d->connector_tail = NULL;
-  d->connector_next = NULL;
+  d->ready_connector_head = NULL;
+  d->ready_connector_tail = NULL;
   d->listener_count = 0;
   d->connector_count = 0;
-  d->closed_count = 0;
-  // d->max_fds = 0;
   d->ctrl[0] = 0;
   d->ctrl[1] = 0;
   d->trace = ((pn_env_bool("PN_TRACE_RAW") ? PN_TRACE_RAW : PN_TRACE_OFF) |
               (pn_env_bool("PN_TRACE_FRM") ? PN_TRACE_FRM : PN_TRACE_OFF) |
               (pn_env_bool("PN_TRACE_DRV") ? PN_TRACE_DRV : PN_TRACE_OFF));
-  d->wakeup = 0;
 
   // XXX
-  if (pn_socket_pair(d->ctrl)) {
+  if (pn_pipe(d->io, d->ctrl)) {
     perror("Can't create control pipe");
     free(d);
     return NULL;
   }
+  d->ctrl_selectable = create_ctrl_selectable(d->ctrl[0]);
+  pn_selector_add(d->selector, d->ctrl_selectable);
 
   return d;
 }
@@ -626,8 +729,9 @@ void pn_driver_free(pn_driver_t *d)
 {
   if (!d) return;
 
-  close(d->ctrl[0]);
-  close(d->ctrl[1]);
+  pn_selectable_free(d->ctrl_selectable);
+  pn_close(d->io, d->ctrl[0]);
+  pn_close(d->io, d->ctrl[1]);
   while (d->connector_head)
     pn_connector_free(d->connector_head);
   while (d->listener_head)
@@ -640,7 +744,7 @@ void pn_driver_free(pn_driver_t *d)
 int pn_driver_wakeup(pn_driver_t *d)
 {
   if (d) {
-      ssize_t count = send(d->ctrl[1], "x", 1, 0);
+    ssize_t count = pn_write(d->io, d->ctrl[1], "x", 1);
     if (count <= 0) {
       return count;
     } else {
@@ -651,158 +755,57 @@ int pn_driver_wakeup(pn_driver_t *d)
   }
 }
 
-static void pn_driver_rebuild(pn_driver_t *d)
+void pn_driver_wait_1(pn_driver_t *d)
 {
-  d->wakeup = 0;
-  d->overflow = false;
-  int r_avail = FD_SETSIZE;
-  int w_avail = FD_SETSIZE;
-  // d->max_fds = -1;
-  FD_ZERO(&d->readfds);
-  FD_ZERO(&d->writefds);
-  FD_ZERO(&d->exceptfds);
-
-  FD_SET(d->ctrl[0], &d->readfds);
-  // if (d->ctrl[0] > d->max_fds) d->max_fds = d->ctrl[0];
-
-  pn_listener_t *l = d->listener_head;
-  for (unsigned i = 0; i < d->listener_count; i++) {
-    if (r_avail) {
-      FD_SET(l->fd, &d->readfds);
-      // if (l->fd > d->max_fds) d->max_fds = l->fd;
-      r_avail--;
-      l = l->listener_next;
-    }
-    else {
-      d->overflow = true;
-      break;
-    }
-  }
+}
 
+int pn_driver_wait_2(pn_driver_t *d, int timeout)
+{
+  // These lists will normally be empty
+  while (d->ready_listener_head)
+    ready_listener_list_remove(d, d->ready_listener_head);
+  while (d->ready_connector_head)
+    ready_connector_list_remove(d, d->ready_connector_head);
   pn_connector_t *c = d->connector_head;
   for (unsigned i = 0; i < d->connector_count; i++)
   {
-    if (!c->closed) {
-      FD_SET(c->fd, &d->exceptfds);
-      d->wakeup = pn_timestamp_min(d->wakeup, c->wakeup);
-      if (c->status & PN_SEL_RD) {
-        if (r_avail) {
-          FD_SET(c->fd, &d->readfds);
-          r_avail--;
-        }
-        else {
-          d->overflow = true;
-          break;
-        }
-      }
-      if (c->status & PN_SEL_WR) {
-        if (w_avail) {
-          FD_SET(c->fd, &d->writefds);
-          w_avail--;
-        }
-        else {
-          d->overflow = true;
-          break;
-        }
-      }
-      // if (c->fd > d->max_fds) d->max_fds = c->fd;
+    // Optimistically use a snapshot of the non-threadsafe vars.
+    // If they are in flux, the app will guarantee progress with a pn_driver_wakeup().
+    int current_status = c->status;
+    pn_timestamp_t current_wakeup = c->wakeup;
+    if (c->posted_status != current_status || c->posted_wakeup != current_wakeup) {
+      c->posted_status = current_status;
+      c->posted_wakeup = current_wakeup;
+      pn_selector_update(c->driver->selector, c->selectable);
+    }
+    if (c->closed) {
+      c->pending_read = false;
+      c->pending_write = false;
+      c->pending_tick = false;
+      LL_ADD(d, ready_connector, c);
     }
     c = c->connector_next;
   }
-}
 
-void pn_driver_wait_1(pn_driver_t *d)
-{
-  pn_driver_rebuild(d);
-}
-
-int pn_driver_wait_2(pn_driver_t *d, int timeout)
-{
-  if (d->overflow)
-      return pn_error_set(d->error, PN_ERR, "maximum driver sockets exceeded");
-  if (d->wakeup) {
-    pn_timestamp_t now = pn_i_now();
-    if (now >= d->wakeup)
-      timeout = 0;
-    else
-      timeout = (timeout < 0) ? d->wakeup-now : pn_min(timeout, d->wakeup - now);
-  }
+  if (d->ready_connector_head)
+    timeout = 0;   // We found closed connections
 
-  struct timeval to = {0};
-  struct timeval *to_arg = &to;
-  // block only if (timeout == 0) and (closed_count == 0)
-  if (d->closed_count == 0) {
-    if (timeout > 0) {
-      // convert millisecs to sec and usec:
-      to.tv_sec = timeout/1000;
-      to.tv_usec = (timeout - (to.tv_sec * 1000)) * 1000;
-    }
-    else if (timeout < 0) {
-        to_arg = NULL;
-    }
-  }
-  int nfds = select(/* d->max_fds */ 0, &d->readfds, &d->writefds, &d->exceptfds, to_arg);
-  if (nfds == SOCKET_ERROR) {
-    errno = WSAGetLastError();
-    pn_i_error_from_errno(d->error, "select");
+  int code = pn_selector_select(d->selector, timeout);
+  if (code) {
+    pn_error_set(d->error, code, "select");
     return -1;
   }
+  get_new_events(d);
   return 0;
 }
 
 int pn_driver_wait_3(pn_driver_t *d)
 {
-  bool woken = false;
-  if (FD_ISSET(d->ctrl[0], &d->readfds)) {
-    woken = true;
-    //clear the pipe
-    char buffer[512];
-    while (recv(d->ctrl[0], buffer, 512, 0) == 512);
-  }
-
-  pn_listener_t *l = d->listener_head;
-  while (l) {
-    l->pending = (FD_ISSET(l->fd, &d->readfds));
-    l = l->listener_next;
-  }
-
-  pn_timestamp_t now = pn_i_now();
-  pn_connector_t *c = d->connector_head;
-  while (c) {
-    if (c->closed) {
-      c->pending_read = false;
-      c->pending_write = false;
-      c->pending_tick = false;
-    } else {
-      c->pending_read = FD_ISSET(c->fd, &d->readfds);
-      c->pending_write = FD_ISSET(c->fd, &d->writefds);
-      c->pending_tick = (c->wakeup &&  c->wakeup <= now);
-// Unlike Posix no distinction of POLLERR and POLLHUP
-//      if (idx && d->fds[idx].revents & POLLERR)
-//          pn_connector_close(c);
-//      else if (idx && (d->fds[idx].revents & POLLHUP)) {
-//          [...]
-// Strategy, defer error to a recv or send if read or write pending.
-// Otherwise proclaim the connection dead.
-      if (!c->pending_read && !c->pending_write) {
-        if (FD_ISSET(c->fd, &d->exceptfds)) {
-          // can't defer error to a read or write, close now.
-          // How to get WSAlastError() equivalent info?
-          fprintf(stderr, "connector cleanup on unknown error %s\n", c->name);
-          pn_connector_close(c);
-        }
-      }
-    }
-    c = c->connector_next;
-  }
-
-  d->listener_next = d->listener_head;
-  d->connector_next = d->connector_head;
-
-  return woken ? PN_INTR : 0;
+  //  no-op with new selector/selectables
+  return 0;
 }
 
-//
+
 // XXX - pn_driver_wait has been divided into three internal functions as a
 //       temporary workaround for a multi-threading problem.  A multi-threaded
 //       application must hold a lock on parts 1 and 3, but not on part 2.
@@ -821,103 +824,75 @@ int pn_driver_wait(pn_driver_t *d, int timeout)
     return pn_driver_wait_3(d);
 }
 
+static void get_new_events(pn_driver_t *d)
+{
+  bool woken = false;
+  int events;
+  pn_selectable_t *sel;
+  while ((sel = pn_selector_next(d->selector, &events)) != NULL) {
+    if (sel == d->ctrl_selectable) {
+      woken = true;
+      //clear the pipe
+      char buffer[512];
+      while (pn_read(d->io, d->ctrl[0], buffer, 512) == 512);
+      continue;
+    }
+
+    void *ctx = pni_selectable_get_context(sel);
+    sel_type_t *type = (sel_type_t *) ctx;
+    if (*type == CONNECTOR) {
+      pn_connector_t *c = (pn_connector_t *) ctx;
+      if (!c->closed) {
+        LL_ADD(d, ready_connector, c);
+        c->pending_read = events & PN_READABLE;
+        c->pending_write = events & PN_WRITABLE;
+        c->pending_tick = events & PN_EXPIRED;
+      }
+    } else {
+      pn_listener_t *l = (pn_listener_t *) ctx;
+      LL_ADD(d, ready_listener, l);
+      l->pending = events & PN_READABLE;
+    }
+  }
+}
+
 pn_listener_t *pn_driver_listener(pn_driver_t *d) {
   if (!d) return NULL;
 
-  while (d->listener_next) {
-    pn_listener_t *l = d->listener_next;
-    d->listener_next = l->listener_next;
-
-    if (l->pending) {
+  pn_listener_t *l = d->ready_listener_head;
+  while (l) {
+    ready_listener_list_remove(d, l);
+    if (l->pending)
       return l;
-    }
+    l = d->ready_listener_head;
   }
-
   return NULL;
 }
 
 pn_connector_t *pn_driver_connector(pn_driver_t *d) {
   if (!d) return NULL;
 
-  while (d->connector_next) {
-    pn_connector_t *c = d->connector_next;
-    d->connector_next = c->connector_next;
-
+  pn_connector_t *c = d->ready_connector_head;
+  while (c) {
+    ready_connector_list_remove(d, c);
     if (c->closed || c->pending_read || c->pending_write || c->pending_tick) {
       return c;
     }
+    c = d->ready_connector_head;
   }
-
   return NULL;
 }
 
-static int pn_socket_pair (SOCKET sv[2]) {
-  // no socketpair on windows.  provide pipe() semantics using sockets
-
-  SOCKET sock = socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
-  if (sock == INVALID_SOCKET) {
-    perror("socket");
-    return -1;
-  }
-
-  BOOL b = 1;
-  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &b, sizeof(b)) == -1) {
-    perror("setsockopt");
-    closesocket(sock);
-    return -1;
-  }
-  else {
-    struct sockaddr_in addr = {0};
-    addr.sin_family = AF_INET;
-    addr.sin_port = 0;
-    addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-
-    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-      perror("bind");
-      closesocket(sock);
-      return -1;
-    }
-  }
-
-  if (listen(sock, 50) == -1) {
-    perror("listen");
-    closesocket(sock);
-    return -1;
-  }
-
-  if ((sv[1] = socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto)) == INVALID_SOCKET) {
-    perror("sock1");
-    closesocket(sock);
-    return -1;
-  }
-  else {
-    struct sockaddr addr = {0};
-    int l = sizeof(addr);
-    if (getsockname(sock, &addr, &l) == -1) {
-      perror("getsockname");
-      closesocket(sock);
-      return -1;
-    }
-
-    if (connect(sv[1], &addr, sizeof(addr)) == -1) {
-      int err = WSAGetLastError();
-      fprintf(stderr, "connect wsaerrr %d\n", err);
-      closesocket(sock);
-      closesocket(sv[1]);
-      return -1;
-    }
-
-    if ((sv[0] = accept(sock, &addr, &l)) == INVALID_SOCKET) {
-      perror("accept");
-      closesocket(sock);
-      closesocket(sv[1]);
-      return -1;
-    }
-  }
-
-  u_long v = 1;
-  ioctlsocket (sv[0], FIONBIO, &v);
-  ioctlsocket (sv[1], FIONBIO, &v);
-  closesocket(sock);
-  return 0;
+static pn_selectable_t *create_ctrl_selectable(pn_socket_t fd)
+{
+  // ctrl input only needs to know about read events, just like a listener.
+  pn_selectable_t *sel = pni_selectable(driver_listener_capacity,
+                                        driver_listener_pending,
+                                        driver_listener_deadline,
+                                        driver_listener_readable,
+                                        driver_listener_writable,
+                                        driver_listener_expired,
+                                        driver_listener_finalize);
+  pni_selectable_set_fd(sel, fd);
+  return sel;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/windows/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/io.c b/proton-c/src/windows/io.c
index b5660be..b2d528a 100644
--- a/proton-c/src/windows/io.c
+++ b/proton-c/src/windows/io.c
@@ -103,7 +103,7 @@ void pn_io_finalize(void *obj)
 pn_io_t *pn_io(void)
 {
   static const pn_class_t clazz = PN_CLASS(pn_io);
-  pn_io_t *io = (pn_io_t *) pn_new(sizeof(pn_io_t), &clazz);
+  pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
   return io;
 }
 
@@ -210,14 +210,16 @@ pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
     return INVALID_SOCKET;
   }
 
-  iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
-  if (!iocpd) {
-    pn_i_error_from_errno(io->error, "register");
-    closesocket(sock);
-    return INVALID_SOCKET;
+  if (io->iocp->selector) {
+    iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
+    if (!iocpd) {
+      pn_i_error_from_errno(io->error, "register");
+      closesocket(sock);
+      return INVALID_SOCKET;
+    }
+    pni_iocpdesc_start(iocpd);
   }
 
-  pni_iocpdesc_start(iocpd);
   return sock;
 }
 
@@ -242,7 +244,22 @@ pn_socket_t pn_connect(pn_io_t *io, const char *hostarg, const char *port)
 
   ensure_unique(io, sock);
   pn_configure_sock(io, sock);
-  return pni_iocp_begin_connect(io->iocp, sock, addr, io->error);
+
+  if (io->iocp->selector) {
+    return pni_iocp_begin_connect(io->iocp, sock, addr, io->error);
+  } else {
+    if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
+      if (WSAGetLastError() != WSAEWOULDBLOCK) {
+	pni_win32_error(io->error, "connect", WSAGetLastError());
+	freeaddrinfo(addr);
+	closesocket(sock);
+	return INVALID_SOCKET;
+      }
+    }
+
+    freeaddrinfo(addr);
+    return sock;
+  }
 }
 
 pn_socket_t pn_accept(pn_io_t *io, pn_socket_t listen_sock, char *name, size_t size)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/windows/iocp.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/iocp.c b/proton-c/src/windows/iocp.c
index 614b130..3c0451a 100644
--- a/proton-c/src/windows/iocp.c
+++ b/proton-c/src/windows/iocp.c
@@ -30,7 +30,7 @@
 #include <Ws2tcpip.h>
 #define PN_WINAPI
 
-#include "../platform.h"
+#include "platform.h"
 #include <proton/object.h>
 #include <proton/io.h>
 #include <proton/selector.h>
@@ -162,8 +162,7 @@ typedef struct {
 } accept_result_t;
 
 static accept_result_t *accept_result(iocpdesc_t *listen_sock) {
-  accept_result_t *result = (accept_result_t *) pn_new(sizeof(accept_result_t), 0);
-  memset(result, 0, sizeof(accept_result_t));
+  accept_result_t *result = (accept_result_t *)calloc(1, sizeof(accept_result_t));
   if (result) {
     result->base.type = IOCP_ACCEPT;
     result->base.iocpd = listen_sock;
@@ -192,7 +191,7 @@ struct pni_acceptor_t {
 static void pni_acceptor_initialize(void *object)
 {
   pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
-  acceptor->accepts = pn_list(IOCP_MAX_ACCEPTS, 0);
+  acceptor->accepts = pn_list(PN_VOID, IOCP_MAX_ACCEPTS);
 }
 
 static void pni_acceptor_finalize(void *object)
@@ -200,14 +199,15 @@ static void pni_acceptor_finalize(void *object)
   pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
   size_t len = pn_list_size(acceptor->accepts);
   for (size_t i = 0; i < len; i++)
-    pn_free(pn_list_get(acceptor->accepts, i));
+    free(pn_list_get(acceptor->accepts, i));
   pn_free(acceptor->accepts);
 }
 
 static pni_acceptor_t *pni_acceptor(iocpdesc_t *iocpd)
 {
+  static const pn_cid_t CID_pni_acceptor = CID_pn_void;
   static const pn_class_t clazz = PN_CLASS(pni_acceptor);
-  pni_acceptor_t *acceptor = (pni_acceptor_t *) pn_new(sizeof(pni_acceptor_t), &clazz);
+  pni_acceptor_t *acceptor = (pni_acceptor_t *) pn_class_new(&clazz, sizeof(pni_acceptor_t));
   acceptor->listen_sock = iocpd;
   acceptor->accept_queue_size = 0;
   acceptor->signalled = false;
@@ -221,7 +221,7 @@ static void begin_accept(pni_acceptor_t *acceptor, accept_result_t *result)
 {
   if (acceptor->listen_sock->closing) {
     if (result) {
-      pn_free(result);
+      free(result);
       acceptor->accept_queue_size--;
     }
     if (acceptor->accept_queue_size == 0)
@@ -272,7 +272,7 @@ static void complete_accept(accept_result_t *result, HRESULT status)
   if (ld->read_closed) {
     if (!result->new_sock->closing)
       pni_iocp_begin_close(result->new_sock);
-    pn_free(result);    // discard
+    free(result);    // discard
     reap_check(ld);
   } else {
     result->base.status = status;
@@ -364,8 +364,9 @@ static void connect_result_finalize(void *object)
 }
 
 static connect_result_t *connect_result(iocpdesc_t *iocpd, struct addrinfo *addr) {
+  static const pn_cid_t CID_connect_result = CID_pn_void;
   static const pn_class_t clazz = PN_CLASS(connect_result);
-  connect_result_t *result = (connect_result_t *) pn_new(sizeof(connect_result_t), &clazz);
+  connect_result_t *result = (connect_result_t *) pn_class_new(&clazz, sizeof(connect_result_t));
   if (result) {
     memset(result, 0, sizeof(connect_result_t));
     result->base.type = IOCP_CONNECT;
@@ -599,7 +600,7 @@ static void begin_zero_byte_read(iocpdesc_t *iocpd)
 }
 
 static void drain_until_closed(iocpdesc_t *iocpd) {
-  int max_drain = 16 * 1024;
+  size_t max_drain = 16 * 1024;
   char buf[512];
   read_result_t *result = iocpd->read_result;
   while (result->drain_count < max_drain) {
@@ -730,9 +731,10 @@ static uintptr_t pni_iocpdesc_hashcode(void *object)
 // Reference counted in the iocpdesc map, zombie_list, selector.
 static iocpdesc_t *pni_iocpdesc(pn_socket_t s)
 {
+  static const pn_cid_t CID_pni_iocpdesc = CID_pn_void;
   static pn_class_t clazz = PN_CLASS(pni_iocpdesc);
   assert (s != INVALID_SOCKET);
-  iocpdesc_t *iocpd = (iocpdesc_t *) pn_new(sizeof(iocpdesc_t), &clazz);
+  iocpdesc_t *iocpd = (iocpdesc_t *) pn_class_new(&clazz, sizeof(iocpdesc_t));
   assert(iocpd);
   iocpd->socket = s;
   return iocpd;
@@ -983,7 +985,7 @@ static void drain_zombie_completions(iocp_t *iocp)
 static pn_list_t *iocp_map_close_all(iocp_t *iocp)
 {
   // Zombify stragglers, i.e. no pn_close() from the application.
-  pn_list_t *externals = pn_list(0, PN_REFCOUNT);
+  pn_list_t *externals = pn_list(PN_OBJECT, 0);
   for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
        entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
     iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
@@ -1101,8 +1103,8 @@ void pni_iocp_initialize(void *obj)
   pni_shared_pool_create(iocp);
   iocp->completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
   assert(iocp->completion_port != NULL);
-  iocp->iocpdesc_map = pn_hash(0, 0.75, PN_REFCOUNT);
-  iocp->zombie_list = pn_list(0, PN_REFCOUNT);
+  iocp->iocpdesc_map = pn_hash(PN_OBJECT, 0, 0.75);
+  iocp->zombie_list = pn_list(PN_OBJECT, 0);
   iocp->iocp_trace = pn_env_bool("PN_TRACE_DRV");
   iocp->selector = NULL;
 }
@@ -1132,7 +1134,8 @@ void pni_iocp_finalize(void *obj)
 
 iocp_t *pni_iocp()
 {
+  static const pn_cid_t CID_pni_iocp = CID_pn_void;
   static const pn_class_t clazz = PN_CLASS(pni_iocp);
-  iocp_t *iocp = (iocp_t *) pn_new(sizeof(iocp_t), &clazz);
+  iocp_t *iocp = (iocp_t *) pn_class_new(&clazz, sizeof(iocp_t));
   return iocp;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/windows/iocp.h
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/iocp.h b/proton-c/src/windows/iocp.h
index bc64dd0..91ded50 100644
--- a/proton-c/src/windows/iocp.h
+++ b/proton-c/src/windows/iocp.h
@@ -47,7 +47,7 @@ struct iocp_t {
   char *shared_pool_memory;
   write_result_t **shared_results;
   write_result_t **available_results;
-  int shared_available_count;
+  size_t shared_available_count;
   size_t writer_count;
   int loopback_bufsize;
   bool iocp_trace;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/windows/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/schannel.c b/proton-c/src/windows/schannel.c
new file mode 100644
index 0000000..7aaf464
--- /dev/null
+++ b/proton-c/src/windows/schannel.c
@@ -0,0 +1,1320 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * SChannel is designed to encrypt and decrypt data in place.  So a
+ * given buffer is expected to sometimes contain encrypted data,
+ * sometimes decrypted data, and occasionally both.  Outgoing buffers
+ * need to reserve space for the TLS header and trailer.  Read
+ * operations need to ignore the same headers and trailers from
+ * incoming buffers.  Outgoing is simple because we choose record
+ * boundaries.  Incoming is complicated by handling incomplete TLS
+ * records, and buffering contiguous data for the app layer that may
+ * span many records.  A lazy double buffering system is used for
+ * the latter.
+ */
+
+#include <proton/ssl.h>
+#include <proton/engine.h>
+#include "engine/engine-internal.h"
+#include "platform.h"
+#include "util.h"
+
+#include <assert.h>
+
+// security.h needs to see this to distinguish from kernel use.
+#include <windows.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <Schnlsp.h>
+#undef SECURITY_WIN32
+
+
+/** @file
+ * SSL/TLS support API.
+ *
+ * This file contains an SChannel-based implemention of the SSL/TLS API for Windows platforms.
+ */
+
+#define SSL_DATA_SIZE 16384
+#define SSL_BUF_SIZE (SSL_DATA_SIZE + 5 + 2048 + 32)
+
+typedef enum { UNKNOWN_CONNECTION, SSL_CONNECTION, CLEAR_CONNECTION } connection_mode_t;
+typedef struct pn_ssl_session_t pn_ssl_session_t;
+
+struct pn_ssl_domain_t {
+  int ref_count;
+  pn_ssl_mode_t mode;
+  bool has_ca_db;       // true when CA database configured
+  bool has_certificate; // true when certificate configured
+  char *keyfile_pw;
+
+  // settings used for all connections
+  pn_ssl_verify_mode_t verify_mode;
+  bool allow_unsecured;
+
+  // SChannel
+  HCERTSTORE cert_store;
+  PCCERT_CONTEXT cert_context;
+  SCHANNEL_CRED credential;
+};
+
+typedef enum { CREATED, CLIENT_HELLO, NEGOTIATING,
+               RUNNING, SHUTTING_DOWN, SSL_CLOSED } ssl_state_t;
+
+struct pn_ssl_t {
+  pn_transport_t   *transport;
+  pn_io_layer_t    *io_layer;
+  pn_ssl_domain_t  *domain;
+  const char    *session_id;
+  const char *peer_hostname;
+  ssl_state_t state;
+
+  bool queued_shutdown;
+  bool ssl_closed;            // shutdown complete, or SSL error
+  ssize_t app_input_closed;   // error code returned by upper layer process input
+  ssize_t app_output_closed;  // error code returned by upper layer process output
+
+  // OpenSSL hides the protocol envelope bytes, SChannel has them in-line.
+  char *sc_outbuf;     // SChannel output buffer
+  size_t sc_out_size;
+  size_t sc_out_count;
+  char *network_outp;   // network ready bytes within sc_outbuf
+  size_t network_out_pending;
+
+  char *sc_inbuf;      // SChannel input buffer
+  size_t sc_in_size;
+  size_t sc_in_count;
+  bool sc_in_incomplete;
+
+  char *inbuf_extra;    // Still encrypted data from following Record(s)
+  size_t extra_count;
+
+  char *in_data;          // Just the plaintext data part of sc_inbuf, decrypted in place
+  size_t in_data_size;
+  size_t in_data_count;
+  bool decrypting;
+  size_t max_data_size;  // computed in the handshake
+
+  pn_bytes_t app_inbytes; // Virtual decrypted datastream, presented to app layer
+
+  pn_buffer_t *inbuf2;    // Second input buf if longer contiguous bytes needed
+  bool double_buffered;
+
+  bool sc_input_shutdown;
+
+  pn_trace_t trace;
+
+  CredHandle cred_handle;
+  CtxtHandle ctxt_handle;
+  SecPkgContext_StreamSizes sc_sizes;
+};
+
+struct pn_ssl_session_t {
+  const char       *id;
+// TODO
+  pn_ssl_session_t *ssn_cache_next;
+  pn_ssl_session_t *ssn_cache_prev;
+};
+
+
+static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_data, size_t len);
+static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *input_data, size_t len);
+static ssize_t process_input_unknown( pn_io_layer_t *io_layer, const char *input_data, size_t len);
+static ssize_t process_output_unknown( pn_io_layer_t *io_layer, char *input_data, size_t len);
+static ssize_t process_input_done(pn_io_layer_t *io_layer, const char *input_data, size_t len);
+static ssize_t process_output_done(pn_io_layer_t *io_layer, char *input_data, size_t len);
+static connection_mode_t check_for_ssl_connection( const char *data, size_t len );
+static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
+static void ssl_session_free( pn_ssl_session_t *);
+static size_t buffered_output( pn_io_layer_t *io_layer );
+static size_t buffered_input( pn_io_layer_t *io_layer );
+static void start_ssl_shutdown(pn_ssl_t *ssl);
+static void rewind_sc_inbuf(pn_ssl_t *ssl);
+static bool grow_inbuf2(pn_ssl_t *ssl, size_t minimum_size);
+
+
+// @todo: used to avoid littering the code with calls to printf...
+static void ssl_log_error(const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fflush(stderr);
+}
+
+// @todo: used to avoid littering the code with calls to printf...
+static void ssl_log(pn_ssl_t *ssl, const char *fmt, ...)
+{
+  if (PN_TRACE_DRV & ssl->trace) {
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fflush(stderr);
+  }
+}
+
+static void ssl_log_error_status(HRESULT status, const char *fmt, ...)
+{
+  char buf[512];
+  va_list ap;
+
+  if (fmt) {
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+  }
+
+  if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
+                    0, status, 0, buf, sizeof(buf), 0))
+    ssl_log_error("%s\n", buf);
+  else
+    fprintf(stderr, "pn internal Windows error: %lu\n", GetLastError());
+
+  fflush(stderr);
+}
+
+static void ssl_log_clear_data(pn_ssl_t *ssl, const char *data, size_t len)
+{
+  if (PN_TRACE_RAW & ssl->trace) {
+    fprintf(stderr, "SSL decrypted data: \"");
+    pn_fprint_data( stderr, data, len );
+    fprintf(stderr, "\"\n");
+  }
+}
+
+static size_t _pni_min(size_t a, size_t b)
+{
+  return (a < b) ? a : b;
+}
+
+// unrecoverable SSL failure occured, notify transport and generate error code.
+static int ssl_failed(pn_ssl_t *ssl, char *reason)
+{
+  char buf[512] = "Unknown error.";
+  if (!reason) {
+    HRESULT status = GetLastError();
+
+    FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
+                  0, status, 0, buf, sizeof(buf), 0);
+    reason = buf;
+  }
+  ssl->ssl_closed = true;
+  ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
+  ssl->transport->tail_closed = true;
+  ssl->state = SSL_CLOSED;
+  pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: %s", reason);
+  return PN_EOS;
+}
+
+/* match the DNS name pattern from the peer certificate against our configured peer
+   hostname */
+static bool match_dns_pattern( const char *hostname,
+                               const char *pattern, int plen )
+{
+  return false; // TODO
+}
+
+
+static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *domain, const char *id )
+{
+// TODO:
+  return NULL;
+}
+
+static void ssl_session_free( pn_ssl_session_t *ssn)
+{
+  if (ssn) {
+    if (ssn->id) free( (void *)ssn->id );
+    free( ssn );
+  }
+}
+
+
+/** Public API - visible to application code */
+
+pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
+{
+  pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t));
+  if (!domain) return NULL;
+
+  memset(domain, 0, sizeof(domain));
+  domain->credential.dwVersion = SCHANNEL_CRED_VERSION;
+  domain->credential.dwFlags = SCH_CRED_NO_DEFAULT_CREDS;
+
+  domain->ref_count = 1;
+  domain->mode = mode;
+  switch(mode) {
+  case PN_SSL_MODE_CLIENT:
+    // TODO
+    break;
+
+  case PN_SSL_MODE_SERVER:
+    // TODO
+    break;
+
+  default:
+    ssl_log_error("Invalid mode for pn_ssl_mode_t: %d\n", mode);
+    free(domain);
+    return NULL;
+  }
+
+  return domain;
+}
+
+void pn_ssl_domain_free( pn_ssl_domain_t *domain )
+{
+  if (--domain->ref_count == 0) {
+
+    if (domain->cert_context)
+      CertFreeCertificateContext(domain->cert_context);
+    if (domain->cert_store)
+      CertCloseStore(domain->cert_store, CERT_CLOSE_STORE_FORCE_FLAG);
+
+    if (domain->keyfile_pw) free(domain->keyfile_pw);
+    free(domain);
+  }
+}
+
+
+int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
+                               const char *certificate_file,
+                               const char *private_key_file,
+                               const char *password)
+{
+  if (!domain) return -1;
+
+  // TODO:
+
+  return 0;
+}
+
+
+int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
+                                    const char *certificate_db)
+{
+  if (!domain) return -1;
+  // TODO: support for alternate ca db? or just return -1
+  domain->has_ca_db = true;
+  return 0;
+}
+
+
+int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
+                                          const pn_ssl_verify_mode_t mode,
+                                          const char *trusted_CAs)
+{
+  if (!domain) return -1;
+
+  switch (mode) {
+  case PN_SSL_VERIFY_PEER:
+  case PN_SSL_VERIFY_PEER_NAME:
+    // TODO
+    break;
+
+  case PN_SSL_ANONYMOUS_PEER:   // hippie free love mode... :)
+    // TODO
+    break;
+
+  default:
+    ssl_log_error( "Invalid peer authentication mode given.\n" );
+    return -1;
+  }
+
+  domain->verify_mode = mode;
+  return 0;
+}
+
+int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_domain_t *domain, const char *session_id)
+{
+  if (!ssl || !domain || ssl->domain) return -1;
+  if (ssl->state != CREATED) return -1;
+
+  ssl->domain = domain;
+  domain->ref_count++;
+  if (domain->allow_unsecured) {
+    ssl->io_layer->process_input = process_input_unknown;
+    ssl->io_layer->process_output = process_output_unknown;
+  } else {
+    ssl->io_layer->process_input = process_input_ssl;
+    ssl->io_layer->process_output = process_output_ssl;
+  }
+
+  if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
+    ssl->session_id = pn_strdup(session_id);
+
+  TimeStamp cred_expiry;
+  SECURITY_STATUS status = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND,
+                               NULL, &domain->credential, NULL, NULL, &ssl->cred_handle,
+                               &cred_expiry);
+  if (status != SEC_E_OK) {
+    ssl_log_error_status(status, "AcquireCredentialsHandle");
+    return -1;
+  }
+
+  ssl->state = (domain->mode == PN_SSL_MODE_CLIENT) ? CLIENT_HELLO : NEGOTIATING;
+  return 0;
+}
+
+
+int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
+{
+  if (!domain) return -1;
+  if (domain->mode != PN_SSL_MODE_SERVER) {
+    ssl_log_error("Cannot permit unsecured clients - not a server.\n");
+    return -1;
+  }
+  domain->allow_unsecured = true;
+  return 0;
+}
+
+
+bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *buffer, size_t size )
+{
+  *buffer = '\0';
+  snprintf( buffer, size, "%s", "TODO: cipher_name" );
+  return true;
+}
+
+bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *buffer, size_t size )
+{
+  *buffer = '\0';
+  snprintf( buffer, size, "%s", "TODO: protocol name" );
+  return true;
+}
+
+
+void pn_ssl_free( pn_ssl_t *ssl)
+{
+  if (!ssl) return;
+  ssl_log( ssl, "SSL socket freed.\n" );
+  // clean up Windows per TLS session data before releasing the domain count
+  if (SecIsValidHandle(&ssl->ctxt_handle))
+    DeleteSecurityContext(&ssl->ctxt_handle);
+  if (SecIsValidHandle(&ssl->cred_handle))
+    FreeCredentialsHandle(&ssl->cred_handle);
+
+  if (ssl->domain) pn_ssl_domain_free(ssl->domain);
+  if (ssl->session_id) free((void *)ssl->session_id);
+  if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
+  if (ssl->sc_inbuf) free((void *)ssl->sc_inbuf);
+  if (ssl->sc_outbuf) free((void *)ssl->sc_outbuf);
+  if (ssl->inbuf2) pn_buffer_free(ssl->inbuf2);
+  free(ssl);
+}
+
+pn_ssl_t *pn_ssl(pn_transport_t *transport)
+{
+  if (!transport) return NULL;
+  if (transport->ssl) return transport->ssl;
+
+  pn_ssl_t *ssl = (pn_ssl_t *) calloc(1, sizeof(pn_ssl_t));
+  if (!ssl) return NULL;
+  ssl->sc_out_size = ssl->sc_in_size = SSL_BUF_SIZE;
+
+  ssl->sc_outbuf = (char *)malloc(ssl->sc_out_size);
+  if (!ssl->sc_outbuf) {
+    free(ssl);
+    return NULL;
+  }
+  ssl->sc_inbuf = (char *)malloc(ssl->sc_in_size);
+  if (!ssl->sc_inbuf) {
+    free(ssl->sc_outbuf);
+    free(ssl);
+    return NULL;
+  }
+
+  ssl->inbuf2 = pn_buffer(0);
+  if (!ssl->inbuf2) {
+    free(ssl->sc_inbuf);
+    free(ssl->sc_outbuf);
+    free(ssl);
+    return NULL;
+  }
+
+  ssl->transport = transport;
+  transport->ssl = ssl;
+
+  ssl->io_layer = &transport->io_layers[PN_IO_SSL];
+  ssl->io_layer->context = ssl;
+  ssl->io_layer->process_input = pn_io_layer_input_passthru;
+  ssl->io_layer->process_output = pn_io_layer_output_passthru;
+  ssl->io_layer->process_tick = pn_io_layer_tick_passthru;
+  ssl->io_layer->buffered_output = buffered_output;
+  ssl->io_layer->buffered_input = buffered_input;
+
+  ssl->trace = (transport->disp) ? transport->disp->trace : PN_TRACE_OFF;
+  SecInvalidateHandle(&ssl->cred_handle);
+  SecInvalidateHandle(&ssl->ctxt_handle);
+  ssl->state = CREATED;
+  ssl->decrypting = true;
+
+  return ssl;
+}
+
+void pn_ssl_trace(pn_ssl_t *ssl, pn_trace_t trace)
+{
+  ssl->trace = trace;
+}
+
+
+pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
+{
+  // TODO
+  return PN_SSL_RESUME_UNKNOWN;
+}
+
+
+int pn_ssl_set_peer_hostname( pn_ssl_t *ssl, const char *hostname )
+{
+  if (!ssl) return -1;
+
+  if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
+  ssl->peer_hostname = NULL;
+  if (hostname) {
+    ssl->peer_hostname = pn_strdup(hostname);
+    if (!ssl->peer_hostname) return -2;
+  }
+  return 0;
+}
+
+int pn_ssl_get_peer_hostname( pn_ssl_t *ssl, char *hostname, size_t *bufsize )
+{
+  if (!ssl) return -1;
+  if (!ssl->peer_hostname) {
+    *bufsize = 0;
+    if (hostname) *hostname = '\0';
+    return 0;
+  }
+  unsigned len = strlen(ssl->peer_hostname);
+  if (hostname) {
+    if (len >= *bufsize) return -1;
+    strcpy( hostname, ssl->peer_hostname );
+  }
+  *bufsize = len;
+  return 0;
+}
+
+
+/** SChannel specific: */
+
+static void ssl_encrypt(pn_ssl_t *ssl, char *app_data, size_t count)
+{
+  // Get SChannel to encrypt exactly one Record.
+  SecBuffer buffs[4];
+  buffs[0].cbBuffer = ssl->sc_sizes.cbHeader;
+  buffs[0].BufferType = SECBUFFER_STREAM_HEADER;
+  buffs[0].pvBuffer = ssl->sc_outbuf;
+  buffs[1].cbBuffer = count;
+  buffs[1].BufferType = SECBUFFER_DATA;
+  buffs[1].pvBuffer = app_data;
+  buffs[2].cbBuffer = ssl->sc_sizes.cbTrailer;
+  buffs[2].BufferType = SECBUFFER_STREAM_TRAILER;
+  buffs[2].pvBuffer = &app_data[count];
+  buffs[3].cbBuffer = 0;
+  buffs[3].BufferType = SECBUFFER_EMPTY;
+  buffs[3].pvBuffer = 0;
+  SecBufferDesc buff_desc;
+  buff_desc.ulVersion = SECBUFFER_VERSION;
+  buff_desc.cBuffers = 4;
+  buff_desc.pBuffers = buffs;
+  SECURITY_STATUS status = EncryptMessage(&ssl->ctxt_handle, 0, &buff_desc, 0);
+  assert(status == SEC_E_OK);
+
+  // EncryptMessage encrypts the data in place. The header and trailer
+  // areas were reserved previously and must now be included in the updated
+  // count of bytes to write to the peer.
+  ssl->sc_out_count = buffs[0].cbBuffer + buffs[1].cbBuffer + buffs[2].cbBuffer;
+  ssl->network_outp = ssl->sc_outbuf;
+  ssl->network_out_pending = ssl->sc_out_count;
+  ssl_log(ssl, "ssl_encrypt %d network bytes\n", ssl->network_out_pending);
+}
+
+// Returns true if decryption succeeded (even for empty content)
+static bool ssl_decrypt(pn_ssl_t *ssl)
+{
+  // Get SChannel to decrypt input.  May have an incomplete Record,
+  // exactly one, or more than one.  Check also for session ending,
+  // session renegotiation.
+
+  SecBuffer recv_buffs[4];
+  recv_buffs[0].cbBuffer = ssl->sc_in_count;
+  recv_buffs[0].BufferType = SECBUFFER_DATA;
+  recv_buffs[0].pvBuffer = ssl->sc_inbuf;
+  recv_buffs[1].BufferType = SECBUFFER_EMPTY;
+  recv_buffs[2].BufferType = SECBUFFER_EMPTY;
+  recv_buffs[3].BufferType = SECBUFFER_EMPTY;
+  SecBufferDesc buff_desc;
+  buff_desc.ulVersion = SECBUFFER_VERSION;
+  buff_desc.cBuffers = 4;
+  buff_desc.pBuffers = recv_buffs;
+  SECURITY_STATUS status = ::DecryptMessage(&ssl->ctxt_handle, &buff_desc, 0, NULL);
+
+  if (status == SEC_E_INCOMPLETE_MESSAGE) {
+    // Less than a full Record, come back later with more network data
+    ssl->sc_in_incomplete = true;
+    return false;
+  }
+
+  ssl->decrypting = false;
+
+  if (status != SEC_E_OK) {
+    rewind_sc_inbuf(ssl);
+    switch (status) {
+    case SEC_I_CONTEXT_EXPIRED:
+      // TLS shutdown alert record.  Ignore all subsequent input.
+      ssl->state = SHUTTING_DOWN;
+      ssl->sc_input_shutdown = true;
+      return false;
+
+    case SEC_I_RENEGOTIATE:
+      // TODO.  Fall through for now.
+    default:
+      ssl_failed(ssl, 0);
+      return false;
+    }
+  }
+
+  ssl->decrypting = false;
+  // have a decrypted Record and possible (still-encrypted) data of
+  // one (or more) later Recordss.  Adjust pointers accordingly.
+  for (int i = 0; i < 4; i++) {
+    switch (recv_buffs[i].BufferType) {
+    case SECBUFFER_DATA:
+      ssl->in_data = (char *) recv_buffs[i].pvBuffer;
+      ssl->in_data_size = ssl->in_data_count = recv_buffs[i].cbBuffer;
+      break;
+    case SECBUFFER_EXTRA:
+      ssl->inbuf_extra = (char *)recv_buffs[i].pvBuffer;
+      ssl->extra_count = recv_buffs[i].cbBuffer;
+      break;
+    default:
+      // SECBUFFER_STREAM_HEADER:
+      // SECBUFFER_STREAM_TRAILER:
+      break;
+    }
+  }
+  return true;
+}
+
+static void client_handshake_init(pn_ssl_t *ssl)
+{
+  // Tell SChannel to create the first handshake token (ClientHello)
+  // and place it in sc_outbuf
+  SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
+  ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS;
+  ULONG ctxt_attrs;
+
+  SecBuffer send_buffs[2];
+  send_buffs[0].cbBuffer = ssl->sc_out_size;
+  send_buffs[0].BufferType = SECBUFFER_TOKEN;
+  send_buffs[0].pvBuffer = ssl->sc_outbuf;
+  send_buffs[1].cbBuffer = 0;
+  send_buffs[1].BufferType = SECBUFFER_EMPTY;
+  send_buffs[1].pvBuffer = 0;
+  SecBufferDesc send_buff_desc;
+  send_buff_desc.ulVersion = SECBUFFER_VERSION;
+  send_buff_desc.cBuffers = 2;
+  send_buff_desc.pBuffers = send_buffs;
+  SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
+                               NULL, host, ctxt_requested, 0, 0, NULL, 0,
+                               &ssl->ctxt_handle, &send_buff_desc,
+                               &ctxt_attrs, NULL);
+
+  if (status == SEC_I_CONTINUE_NEEDED) {
+    ssl->sc_out_count = send_buffs[0].cbBuffer;
+    ssl->network_out_pending = ssl->sc_out_count;
+    // the token is the whole quantity to send
+    ssl->network_outp = ssl->sc_outbuf;
+    ssl_log(ssl, "Sending client hello %d bytes\n", ssl->network_out_pending);
+  } else {
+    ssl_log_error_status(status, "InitializeSecurityContext failed");
+    ssl_failed(ssl, 0);
+  }
+}
+
+static void client_handshake( pn_ssl_t* ssl) {
+  // Feed SChannel ongoing responses from the server until the handshake is complete.
+  SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
+  ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS;
+  ULONG ctxt_attrs;
+  size_t max = 0;
+
+  // token_buffs describe the buffer that's coming in. It should have
+  // a token from the SSL server, or empty if sending final shutdown alert.
+  bool shutdown = ssl->state == SHUTTING_DOWN;
+  SecBuffer token_buffs[2];
+  token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
+  token_buffs[0].BufferType = SECBUFFER_TOKEN;
+  token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
+  token_buffs[1].cbBuffer = 0;
+  token_buffs[1].BufferType = SECBUFFER_EMPTY;
+  token_buffs[1].pvBuffer = 0;
+  SecBufferDesc token_buff_desc;
+  token_buff_desc.ulVersion = SECBUFFER_VERSION;
+  token_buff_desc.cBuffers = 2;
+  token_buff_desc.pBuffers = token_buffs;
+
+  // send_buffs will hold information to forward to the peer.
+  SecBuffer send_buffs[2];
+  send_buffs[0].cbBuffer = ssl->sc_out_size;
+  send_buffs[0].BufferType = SECBUFFER_TOKEN;
+  send_buffs[0].pvBuffer = ssl->sc_outbuf;
+  send_buffs[1].cbBuffer = 0;
+  send_buffs[1].BufferType = SECBUFFER_EMPTY;
+  send_buffs[1].pvBuffer = 0;
+  SecBufferDesc send_buff_desc;
+  send_buff_desc.ulVersion = SECBUFFER_VERSION;
+  send_buff_desc.cBuffers = 2;
+  send_buff_desc.pBuffers = send_buffs;
+
+  SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
+                               &ssl->ctxt_handle, host, ctxt_requested, 0, 0,
+                               &token_buff_desc, 0, NULL, &send_buff_desc,
+                               &ctxt_attrs, NULL);
+  switch (status) {
+  case SEC_E_INCOMPLETE_MESSAGE:
+    // Not enough - get more data from the server then try again.
+    // Leave input buffers untouched.
+    ssl_log(ssl, "client handshake: incomplete record\n");
+    ssl->sc_in_incomplete = true;
+    return;
+
+  case SEC_I_CONTINUE_NEEDED:
+    // Successful handshake step, requiring data to be sent to peer.
+    // TODO: check if server has requested a client certificate
+    ssl->sc_out_count = send_buffs[0].cbBuffer;
+    // the token is the whole quantity to send
+    ssl->network_out_pending = ssl->sc_out_count;
+    ssl->network_outp = ssl->sc_outbuf;
+    ssl_log(ssl, "client handshake token %d bytes\n", ssl->network_out_pending);
+    break;
+
+  case SEC_E_OK:
+    // Handshake complete.
+    if (shutdown) {
+      if (send_buffs[0].cbBuffer > 0) {
+        ssl->sc_out_count = send_buffs[0].cbBuffer;
+        // the token is the whole quantity to send
+        ssl->network_out_pending = ssl->sc_out_count;
+        ssl->network_outp = ssl->sc_outbuf;
+        ssl_log(ssl, "client shutdown token %d bytes\n", ssl->network_out_pending);
+      } else {
+        ssl->state = SSL_CLOSED;
+      }
+      // we didn't touch sc_inbuf, no need to reset
+      return;
+    }
+    if (send_buffs[0].cbBuffer != 0) {
+      ssl_failed(ssl, "unexpected final server token");
+      break;
+    }
+    if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0) {
+      // This seems to work but not documented, plus logic differs from decrypt message
+      // since the pvBuffer value is not set.  Grrr.
+      ssl->extra_count = token_buffs[1].cbBuffer;
+      ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
+    }
+
+    QueryContextAttributes(&ssl->ctxt_handle,
+                             SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
+    max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
+    if (max > ssl->sc_out_size) {
+      ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
+      ssl->state = SHUTTING_DOWN;
+      ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
+      start_ssl_shutdown(ssl);
+      pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
+      break;
+    }
+
+    ssl->state = RUNNING;
+    ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
+    ssl_log(ssl, "client handshake successful %d max record size\n", max);
+    break;
+
+  case SEC_I_CONTEXT_EXPIRED:
+    // ended before we got going
+  default:
+    ssl_log(ssl, "client handshake failed %d\n", (int) status);
+    ssl_failed(ssl, 0);
+    break;
+  }
+  ssl->decrypting = false;
+  rewind_sc_inbuf(ssl);
+}
+
+
+static void ssl_handshake(pn_ssl_t* ssl) {
+  if (ssl->domain->mode == PN_SSL_MODE_CLIENT)
+    client_handshake(ssl);
+  else {
+    ssl_log( ssl, "TODO: server handshake.\n" );
+    ssl_failed(ssl, "internal runtime error, not yet implemented");
+  }
+}
+
+static bool grow_inbuf2(pn_ssl_t *ssl, size_t minimum_size) {
+  size_t old_capacity = pn_buffer_capacity(ssl->inbuf2);
+  size_t new_capacity = old_capacity ? old_capacity * 2 : 1024;
+
+  while (new_capacity < minimum_size)
+    new_capacity *= 2;
+
+  uint32_t max_frame = pn_transport_get_max_frame(ssl->transport);
+  if (max_frame != 0) {
+    if (old_capacity >= max_frame) {
+      //  already big enough
+      ssl_log(ssl, "Application expecting %d bytes (> negotiated maximum frame)\n", new_capacity);
+      ssl_failed(ssl, "TLS: transport maximimum frame size error");
+      return false;
+    }
+  }
+
+  size_t extra_bytes = new_capacity - pn_buffer_size(ssl->inbuf2);
+  int err = pn_buffer_ensure(ssl->inbuf2, extra_bytes);
+  if (err) {
+    ssl_log(ssl, "TLS memory allocation failed for %d bytes\n", max_frame);
+    ssl_failed(ssl, "TLS memory allocation failed");
+    return false;
+  }
+  return true;
+}
+
+
+// Peer initiated a session end by sending us a shutdown alert (and we should politely
+// reciprocate), or else we are initiating the session end (and will not bother to wait
+// for the peer shutdown alert). Stop processing input immediately, and stop processing
+// output once this is sent.
+
+static void start_ssl_shutdown(pn_ssl_t *ssl)
+{
+  assert(ssl->network_out_pending == 0);
+  if (ssl->queued_shutdown)
+    return;
+  ssl->queued_shutdown = true;
+  ssl_log(ssl, "Shutting down SSL connection...\n");
+
+  DWORD shutdown = SCHANNEL_SHUTDOWN;
+  SecBuffer shutBuff;
+  shutBuff.cbBuffer = sizeof(DWORD);
+  shutBuff.BufferType = SECBUFFER_TOKEN;
+  shutBuff.pvBuffer = &shutdown;
+  SecBufferDesc desc;
+  desc.ulVersion = SECBUFFER_VERSION;
+  desc.cBuffers = 1;
+  desc.pBuffers = &shutBuff;
+  ::ApplyControlToken(&ssl->ctxt_handle, &desc);
+
+  // Next handshake will generate the shudown alert token
+  ssl_handshake(ssl);
+}
+
+static int setup_ssl_connection(pn_ssl_t *ssl)
+{
+  ssl_log( ssl, "SSL connection detected.\n");
+  ssl->io_layer->process_input = process_input_ssl;
+  ssl->io_layer->process_output = process_output_ssl;
+  return 0;
+}
+
+static void rewind_sc_inbuf(pn_ssl_t *ssl)
+{
+  // Decrypted bytes have been drained or double buffered.  Prepare for the next SSL Record.
+  assert(ssl->in_data_count == 0);
+  if (ssl->decrypting)
+    return;
+  ssl->decrypting = true;
+  if (ssl->inbuf_extra) {
+    // A previous read picked up more than one Record.  Move it to the beginning.
+    memmove(ssl->sc_inbuf, ssl->inbuf_extra, ssl->extra_count);
+    ssl->sc_in_count = ssl->extra_count;
+    ssl->inbuf_extra = 0;
+    ssl->extra_count = 0;
+  } else {
+    ssl->sc_in_count = 0;
+  }
+}
+
+static void app_inbytes_add(pn_ssl_t *ssl)
+{
+  if (!ssl->app_inbytes.start) {
+    ssl->app_inbytes.start = ssl->in_data;
+    ssl->app_inbytes.size = ssl->in_data_count;
+    return;
+  }
+
+  if (ssl->double_buffered) {
+    if (pn_buffer_available(ssl->inbuf2) == 0) {
+      if (!grow_inbuf2(ssl, 1024))
+        // could not add room
+        return;
+    }
+    size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
+    pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
+    ssl->in_data += count;
+    ssl->in_data_count -= count;
+    ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
+  } else {
+    assert(ssl->app_inbytes.size == 0);
+    ssl->app_inbytes.start = ssl->in_data;
+    ssl->app_inbytes.size = ssl->in_data_count;
+  }
+}
+
+
+static void app_inbytes_progress(pn_ssl_t *ssl, size_t minimum)
+{
+  // Make more decrypted data available, if possible.  Otherwise, move
+  // unread bytes to front of inbuf2 to make room for next bulk decryption.
+  // SSL may have chopped up data that app layer expects to be
+  // contiguous.  Start, continue or stop double buffering here.
+  if (ssl->double_buffered) {
+    if (ssl->app_inbytes.size == 0) {
+      // no straggler bytes, optimistically stop for now
+      ssl->double_buffered = false;
+      pn_buffer_clear(ssl->inbuf2);
+      ssl->app_inbytes.start = ssl->in_data;
+      ssl->app_inbytes.size = ssl->in_data_count;
+    } else {
+      pn_bytes_t ib2 = pn_buffer_bytes(ssl->inbuf2);
+      assert(ssl->app_inbytes.size <= ib2.size);
+      size_t consumed = ib2.size - ssl->app_inbytes.size;
+      if (consumed > 0) {
+          memmove((void *)ib2.start, ib2.start + consumed, consumed);
+        pn_buffer_trim(ssl->inbuf2, 0, consumed);
+      }
+      if (!pn_buffer_available(ssl->inbuf2)) {
+        if (!grow_inbuf2(ssl, minimum))
+          // could not add room
+          return;
+      }
+      size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
+      pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
+      ssl->in_data += count;
+      ssl->in_data_count -= count;
+      ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
+    }
+  } else {
+    if (ssl->app_inbytes.size) {
+      // start double buffering the left over bytes
+      ssl->double_buffered = true;
+      pn_buffer_clear(ssl->inbuf2);
+      if (!pn_buffer_available(ssl->inbuf2)) {
+        if (!grow_inbuf2(ssl, minimum))
+          // could not add room
+          return;
+      }
+      size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
+      pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
+      ssl->in_data += count;
+      ssl->in_data_count -= count;
+      ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
+    } else {
+      // already pointing at all available bytes until next decrypt
+    }
+  }
+  if (ssl->in_data_count == 0)
+    rewind_sc_inbuf(ssl);
+}
+
+
+static void app_inbytes_advance(pn_ssl_t *ssl, size_t consumed)
+{
+  if (consumed == 0) {
+    // more contiguous bytes required
+    app_inbytes_progress(ssl, ssl->app_inbytes.size + 1);
+    return;
+  }
+  assert(consumed <= ssl->app_inbytes.size);
+  ssl->app_inbytes.start += consumed;
+  ssl->app_inbytes.size -= consumed;
+  if (!ssl->double_buffered) {
+    ssl->in_data += consumed;
+    ssl->in_data_count -= consumed;
+  }
+  if (ssl->app_inbytes.size == 0)
+    app_inbytes_progress(ssl, 0);
+}
+
+static void read_closed(pn_ssl_t *ssl, ssize_t error)
+{
+  if (ssl->app_input_closed)
+    return;
+  if (ssl->state == RUNNING && !error) {
+    pn_io_layer_t *io_next = ssl->io_layer->next;
+    // Signal end of stream
+    ssl->app_input_closed = io_next->process_input(io_next, ssl->app_inbytes.start, 0);
+  }
+  if (!ssl->app_input_closed)
+    ssl->app_input_closed = error ? error : PN_ERR;
+
+  if (ssl->app_output_closed) {
+    // both sides of app closed, and no more app output pending:
+    ssl->state = SHUTTING_DOWN;
+    if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
+      start_ssl_shutdown(ssl);
+    }
+  }
+}
+
+
+// Read up to "available" bytes from the network, decrypt it and pass plaintext to application.
+
+static ssize_t process_input_ssl(pn_io_layer_t *io_layer, const char *input_data, size_t available)
+{
+  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+  ssl_log( ssl, "process_input_ssl( data size=%d )\n",available );
+  ssize_t consumed = 0;
+  ssize_t forwarded = 0;
+  bool new_app_input;
+
+  if (available == 0) {
+    // No more inbound network data
+    read_closed(ssl,0);
+    return 0;
+  }
+
+  do {
+    if (ssl->sc_input_shutdown) {
+      // TLS protocol shutdown detected on input
+      read_closed(ssl,0);
+      return consumed;
+    }
+
+    // sc_inbuf should be ready for new or additional network encrypted bytes.
+    // i.e. no straggling decrypted bytes pending.
+    assert(ssl->in_data_count == 0 && ssl->decrypting);
+    new_app_input = false;
+    size_t count;
+
+    if (ssl->state != RUNNING) {
+      count = _pni_min(ssl->sc_in_size - ssl->sc_in_count, available);
+    } else {
+      // look for TLS record boundaries
+      if (ssl->sc_in_count < 5) {
+        ssl->sc_in_incomplete = true;
+        size_t hc = _pni_min(available, 5 - ssl->sc_in_count);
+        memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, hc);
+        ssl->sc_in_count += hc;
+        input_data += hc;
+        available -= hc;
+        consumed += hc;
+        if (ssl->sc_in_count < 5 || available == 0)
+          break;
+      }
+
+      // Top up sc_inbuf from network input_data hoping for a complete TLS Record
+      // We try to guess the length as an optimization, but let SChannel
+      // ultimately decide if there is spoofing going on.
+      unsigned char low = (unsigned char) ssl->sc_inbuf[4];
+      unsigned char high = (unsigned char) ssl->sc_inbuf[3];
+      size_t rec_len = high * 256 + low + 5;
+      if (rec_len < 5 || rec_len == ssl->sc_in_count || rec_len > ssl->sc_in_size)
+        rec_len = ssl->sc_in_size;
+
+      count = _pni_min(rec_len - ssl->sc_in_count, available);
+    }
+
+    if (count > 0) {
+      memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, count);
+      ssl->sc_in_count += count;
+      input_data += count;
+      available -= count;
+      consumed += count;
+      ssl->sc_in_incomplete = false;
+    }
+
+    // Try to decrypt another TLS Record.
+
+    if (ssl->sc_in_count > 0 && ssl->state <= SHUTTING_DOWN) {
+      if (ssl->state == NEGOTIATING) {
+        ssl_handshake(ssl);
+      } else {
+        if (ssl_decrypt(ssl)) {
+          // Ignore TLS Record with 0 length data (does not mean EOS)
+          if (ssl->in_data_size > 0) {
+            new_app_input = true;
+            app_inbytes_add(ssl);
+          } else {
+            assert(ssl->decrypting == false);
+            rewind_sc_inbuf(ssl);
+          }
+        }
+        ssl_log(ssl, "Next decryption, %d left over\n", available);
+      }
+    }
+
+    if (ssl->state == SHUTTING_DOWN) {
+      if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
+        start_ssl_shutdown(ssl);
+      }
+    } else if (ssl->state == SSL_CLOSED) {
+      return consumed ? consumed : -1;
+    }
+
+    // Consume or discard the decrypted bytes
+    if (new_app_input && (ssl->state == RUNNING || ssl->state == SHUTTING_DOWN)) {
+      // present app_inbytes to io_next only if it has new content
+      while (ssl->app_inbytes.size > 0) {
+        if (!ssl->app_input_closed) {
+          pn_io_layer_t *io_next = ssl->io_layer->next;
+          ssize_t count = io_next->process_input(io_next, ssl->app_inbytes.start, ssl->app_inbytes.size);
+          if (count > 0) {
+            forwarded += count;
+            // advance() can increase app_inbytes.size if double buffered
+            app_inbytes_advance(ssl, count);
+            ssl_log(ssl, "Application consumed %d bytes from peer\n", (int) count);
+          } else if (count == 0) {
+            size_t old_size = ssl->app_inbytes.size;
+            app_inbytes_advance(ssl, 0);
+            if (ssl->app_inbytes.size == old_size) {
+              break;  // no additional contiguous decrypted data available, get more network data
+            }
+          } else {
+            // count < 0
+            ssl_log(ssl, "Application layer closed its input, error=%d (discarding %d bytes)\n",
+                 (int) count, (int)ssl->app_inbytes.size);
+            app_inbytes_advance(ssl, ssl->app_inbytes.size);    // discard
+            read_closed(ssl, count);
+          }
+        } else {
+          ssl_log(ssl, "Input closed discard %d bytes\n",
+               (int)ssl->app_inbytes.size);
+          app_inbytes_advance(ssl, ssl->app_inbytes.size);      // discard
+        }
+      }
+    }
+  } while (available || (ssl->sc_in_count && !ssl->sc_in_incomplete));
+
+  if (ssl->app_input_closed && ssl->state >= SHUTTING_DOWN) {
+    consumed = ssl->app_input_closed;
+    ssl->io_layer->process_input = process_input_done;
+  }
+  ssl_log(ssl, "process_input_ssl() returning %d, forwarded %d\n", (int) consumed, (int) forwarded);
+  return consumed;
+}
+
+static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t max_len)
+{
+  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+  if (!ssl) return PN_ERR;
+  ssl_log( ssl, "process_output_ssl( max_len=%d )\n",max_len );
+
+  ssize_t written = 0;
+  ssize_t total_app_bytes = 0;
+  bool work_pending;
+
+  if (ssl->state == CLIENT_HELLO) {
+    // output buffers eclusively for internal handshake use until negotiation complete
+    client_handshake_init(ssl);
+    if (ssl->state == SSL_CLOSED)
+      return PN_ERR;
+    ssl->state = NEGOTIATING;
+  }
+
+  do {
+    work_pending = false;
+
+    if (ssl->network_out_pending > 0) {
+      size_t wcount = _pni_min(ssl->network_out_pending, max_len);
+      memmove(buffer, ssl->network_outp, wcount);
+      ssl->network_outp += wcount;
+      ssl->network_out_pending -= wcount;
+      buffer += wcount;
+      max_len -= wcount;
+      written += wcount;
+    }
+
+    if (ssl->network_out_pending == 0 && ssl->state == RUNNING  && !ssl->app_output_closed) {
+      // refill the buffer with app data and encrypt it
+
+      char *app_data = ssl->sc_outbuf + ssl->sc_sizes.cbHeader;
+      char *app_outp = app_data;
+      size_t remaining = ssl->max_data_size;
+      ssize_t app_bytes;
+      do {
+        pn_io_layer_t *io_next = ssl->io_layer->next;
+        app_bytes = io_next->process_output(io_next, app_outp, remaining);
+        if (app_bytes > 0) {
+          app_outp += app_bytes;
+          remaining -= app_bytes;
+          ssl_log( ssl, "Gathered %d bytes from app to send to peer\n", app_bytes );
+        } else {
+          if (app_bytes < 0) {
+            ssl_log(ssl, "Application layer closed its output, error=%d (%d bytes pending send)\n",
+                 (int) app_bytes, (int) ssl->network_out_pending);
+            ssl->app_output_closed = app_bytes;
+            if (ssl->app_input_closed)
+              ssl->state = SHUTTING_DOWN;
+          } else if (total_app_bytes == 0 && ssl->app_input_closed) {
+            // We've drained all the App layer can provide
+            ssl_log(ssl, "Application layer blocked on input, closing\n");
+            ssl->state = SHUTTING_DOWN;
+            ssl->app_output_closed = PN_ERR;
+          }
+        }
+      } while (app_bytes > 0);
+      if (app_outp > app_data) {
+        work_pending = (max_len > 0);
+        ssl_encrypt(ssl, app_data, app_outp - app_data);
+      }
+    }
+
+    if (ssl->network_out_pending == 0 && ssl->state == SHUTTING_DOWN) {
+      if (!ssl->queued_shutdown) {
+        start_ssl_shutdown(ssl);
+        work_pending = true;
+      } else {
+        ssl->state = SSL_CLOSED;
+      }
+    }
+  } while (work_pending);
+
+  if (written == 0 && ssl->state == SSL_CLOSED) {
+    written = ssl->app_output_closed ? ssl->app_output_closed : PN_EOS;
+    ssl->io_layer->process_output = process_output_done;
+  }
+  ssl_log(ssl, "process_output_ssl() returning %d\n", (int) written);
+  return written;
+}
+
+
+static int setup_cleartext_connection( pn_ssl_t *ssl )
+{
+  ssl_log( ssl, "Cleartext connection detected.\n");
+  ssl->io_layer->process_input = pn_io_layer_input_passthru;
+  ssl->io_layer->process_output = pn_io_layer_output_passthru;
+  return 0;
+}
+
+
+// until we determine if the client is using SSL or not:
+
+static ssize_t process_input_unknown(pn_io_layer_t *io_layer, const char *input_data, size_t len)
+{
+  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+  switch (check_for_ssl_connection( input_data, len )) {
+  case SSL_CONNECTION:
+    setup_ssl_connection( ssl );
+    return ssl->io_layer->process_input( ssl->io_layer, input_data, len );
+  case CLEAR_CONNECTION:
+    setup_cleartext_connection( ssl );
+    return ssl->io_layer->process_input( ssl->io_layer, input_data, len );
+  default:
+    return 0;
+  }
+}
+
+static ssize_t process_output_unknown(pn_io_layer_t *io_layer, char *input_data, size_t len)
+{
+  // do not do output until we know if SSL is used or not
+  return 0;
+}
+
+static connection_mode_t check_for_ssl_connection( const char *data, size_t len )
+{
+  if (len >= 5) {
+    const unsigned char *buf = (unsigned char *)data;
+    /*
+     * SSLv2 Client Hello format
+     * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
+     *
+     * Bytes 0-1: RECORD-LENGTH
+     * Byte    2: MSG-CLIENT-HELLO (1)
+     * Byte    3: CLIENT-VERSION-MSB
+     * Byte    4: CLIENT-VERSION-LSB
+     *
+     * Allowed versions:
+     * 2.0 - SSLv2
+     * 3.0 - SSLv3
+     * 3.1 - TLS 1.0
+     * 3.2 - TLS 1.1
+     * 3.3 - TLS 1.2
+     *
+     * The version sent in the Client-Hello is the latest version supported by
+     * the client. NSS may send version 3.x in an SSLv2 header for
+     * maximum compatibility.
+     */
+    int isSSL2Handshake = buf[2] == 1 &&   // MSG-CLIENT-HELLO
+      ((buf[3] == 3 && buf[4] <= 3) ||    // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+       (buf[3] == 2 && buf[4] == 0));     // SSL 2
+
+    /*
+     * SSLv3/TLS Client Hello format
+     * RFC 2246
+     *
+     * Byte    0: ContentType (handshake - 22)
+     * Bytes 1-2: ProtocolVersion {major, minor}
+     *
+     * Allowed versions:
+     * 3.0 - SSLv3
+     * 3.1 - TLS 1.0
+     * 3.2 - TLS 1.1
+     * 3.3 - TLS 1.2
+     */
+    int isSSL3Handshake = buf[0] == 22 &&  // handshake
+      (buf[1] == 3 && buf[2] <= 3);       // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+
+    if (isSSL2Handshake || isSSL3Handshake) {
+      return SSL_CONNECTION;
+    } else {
+      return CLEAR_CONNECTION;
+    }
+  }
+  return UNKNOWN_CONNECTION;
+}
+
+static ssize_t process_input_done(pn_io_layer_t *io_layer, const char *input_data, size_t len)
+{
+  return PN_EOS;
+}
+
+static ssize_t process_output_done(pn_io_layer_t *io_layer, char *input_data, size_t len)
+{
+  return PN_EOS;
+}
+
+// return # output bytes sitting in this layer
+static size_t buffered_output(pn_io_layer_t *io_layer)
+{
+  size_t count = 0;
+  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+  if (ssl) {
+    count += ssl->network_out_pending;
+    if (count == 0 && ssl->state == SHUTTING_DOWN && ssl->queued_shutdown)
+      count++;
+  }
+  return count;
+}
+
+// return # input bytes sitting in this layer
+static size_t buffered_input( pn_io_layer_t *io_layer )
+{
+  size_t count = 0;
+  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+  if (ssl) {
+    count += ssl->in_data_count;
+  }
+  return count;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/windows/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/selector.c b/proton-c/src/windows/selector.c
index b01c27a..a7ee49f 100644
--- a/proton-c/src/windows/selector.c
+++ b/proton-c/src/windows/selector.c
@@ -65,8 +65,8 @@ void pn_selector_initialize(void *obj)
   selector->iocp = NULL;
   selector->deadlines = NULL;
   selector->capacity = 0;
-  selector->selectables = pn_list(0, 0);
-  selector->iocp_descriptors = pn_list(0, PN_REFCOUNT);
+  selector->selectables = pn_list(PN_WEAKREF, 0);
+  selector->iocp_descriptors = pn_list(PN_OBJECT, 0);
   selector->deadline = 0;
   selector->current = 0;
   selector->current_triggered = NULL;
@@ -95,7 +95,7 @@ void pn_selector_finalize(void *obj)
 pn_selector_t *pni_selector()
 {
   static const pn_class_t clazz = PN_CLASS(pn_selector);
-  pn_selector_t *selector = (pn_selector_t *) pn_new(sizeof(pn_selector_t), &clazz);
+  pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
   return selector;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/windows/write_pipeline.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/write_pipeline.c b/proton-c/src/windows/write_pipeline.c
index 3160fa8..438ba88 100644
--- a/proton-c/src/windows/write_pipeline.c
+++ b/proton-c/src/windows/write_pipeline.c
@@ -168,8 +168,9 @@ static void write_pipeline_finalize(void *object)
 
 write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd)
 {
+  static const pn_cid_t CID_write_pipeline = CID_pn_void;
   static const pn_class_t clazz = PN_CLASS(write_pipeline);
-  write_pipeline_t *pipeline = (write_pipeline_t *) pn_new(sizeof(write_pipeline_t), &clazz);
+  write_pipeline_t *pipeline = (write_pipeline_t *) pn_class_new(&clazz, sizeof(write_pipeline_t));
   pipeline->iocpd = iocpd;
   pipeline->primary->base.iocpd = iocpd;
   return pipeline;
@@ -243,15 +244,15 @@ size_t pni_write_pipeline_reserve(write_pipeline_t *pl, size_t count)
 
   iocp_t *iocp = pl->iocpd->iocp;
   confirm_as_writer(pl);
-  int wanted = (count / IOCP_WBUFSIZE);
+  size_t wanted = (count / IOCP_WBUFSIZE);
   if (count % IOCP_WBUFSIZE)
     wanted++;
   size_t pending = pl->pending_count;
   assert(pending < pl->depth);
-  int bufs = pn_min(wanted, pl->depth - pending);
+  size_t bufs = pn_min(wanted, pl->depth - pending);
   // Can draw from shared pool or the primary... but share with others.
   size_t writers = iocp->writer_count;
-  int shared_count = (iocp->shared_available_count + writers - 1) / writers;
+  size_t shared_count = (iocp->shared_available_count + writers - 1) / writers;
   bufs = pn_min(bufs, shared_count + 1);
   pl->reserved_count = pending + bufs;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/amqp/Binary.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/Binary.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/Binary.java
index 31989d2..a416f3f 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/Binary.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/Binary.java
@@ -50,6 +50,7 @@ public final class Binary
         return ByteBuffer.wrap(_data, _offset, _length);
     }
 
+    @Override
     public final int hashCode()
     {
         int hc = _hashCode;
@@ -64,13 +65,20 @@ public final class Binary
         return hc;
     }
 
+    @Override
     public final boolean equals(Object o)
     {
-        Binary buf = (Binary) o;
-        if(o == null)
+        if (this == o)
+        {
+            return true;
+        }
+
+        if (o == null || getClass() != o.getClass())
         {
             return false;
         }
+
+        Binary buf = (Binary) o;
         final int size = _length;
         if (size != buf._length)
         {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java
index 4b45e01..d681ffe 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java
@@ -21,7 +21,11 @@
 package org.apache.qpid.proton.codec;
 
 import java.nio.ByteBuffer;
-import java.util.*;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
 
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.Decimal128;
@@ -770,29 +774,43 @@ public final class EncoderImpl implements ByteBufferEncoder
     void writeRaw(String string)
     {
         final int length = string.length();
-        char c;
+        int c;
 
         for (int i = 0; i < length; i++)
         {
             c = string.charAt(i);
-            if ((c >= 0x0001) && (c <= 0x007F))
+            if ((c & 0xFF80) == 0)          /* U+0000..U+007F */
             {
                 _buffer.put((byte) c);
-
             }
-            else if (c > 0x07FF)
+            else if ((c & 0xF800) == 0)     /* U+0080..U+07FF */
+            {
+                _buffer.put((byte)(0xC0 | ((c >> 6) & 0x1F)));
+                _buffer.put((byte)(0x80 | (c & 0x3F)));
+            }
+            else if ((c & 0xD800) != 0xD800)     /* U+0800..U+FFFF - excluding surrogate pairs */
             {
-                _buffer.put((byte) (0xE0 | ((c >> 12) & 0x0F)));
-                _buffer.put((byte) (0x80 | ((c >>  6) & 0x3F)));
-                _buffer.put((byte) (0x80 | (c & 0x3F)));
+                _buffer.put((byte)(0xE0 | ((c >> 12) & 0x0F)));
+                _buffer.put((byte)(0x80 | ((c >> 6) & 0x3F)));
+                _buffer.put((byte)(0x80 | (c & 0x3F)));
             }
             else
             {
-                _buffer.put((byte) (0xC0 | ((c >>  6) & 0x1F)));
-                _buffer.put((byte) (0x80 | (c & 0x3F)));
+                int low;
+
+                if(((c & 0xDC00) == 0xDC00) || (++i == length) || ((low = string.charAt(i)) & 0xDC00) != 0xDC00)
+                {
+                    throw new IllegalArgumentException("String contains invalid Unicode code points");
+                }
+
+                c = 0x010000 + ((c & 0x03FF) << 10) + (low & 0x03FF);
+
+                _buffer.put((byte)(0xF0 | ((c >> 18) & 0x07)));
+                _buffer.put((byte)(0x80 | ((c >> 12) & 0x3F)));
+                _buffer.put((byte)(0x80 | ((c >> 6) & 0x3F)));
+                _buffer.put((byte)(0x80 | (c & 0x3F)));
             }
         }
-
     }
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/codec/StringType.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/StringType.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/StringType.java
index 3728a42..aa988f9 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/StringType.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/StringType.java
@@ -83,29 +83,22 @@ public class StringType extends AbstractPrimitiveType<String>
         return encoding;
     }
 
-    private static int calculateUTF8Length(final String s)
+    static int calculateUTF8Length(final String s)
     {
         int len = s.length();
-        int i = 0;
-        final int length = s.length();
-        while(i < length)
+        final int length = len;
+        for (int i = 0; i < length; i++)
         {
-            char c = s.charAt(i);
-            if(c > 127)
+            int c = s.charAt(i);
+            if ((c & 0xFF80) != 0)         /* U+0080..    */
             {
                 len++;
-                if(c > 0x07ff)
+                // surrogate pairs should always combine to create a code point with a 4 octet representation
+                if(((c & 0xF800) != 0) && ((c & 0xD800) != 0xD800))     /* U+0800..  excluding surrogate pairs  */
                 {
                     len++;
-                    if(c >= 0xD800 && c <= 0xDBFF)
-                    {
-                        i++;
-                        len++;
-                    }
                 }
             }
-            i++;
-
         }
         return len;
     }


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


[12/51] [abbrv] qpid-proton git commit: JavaScript binding now pretty much in a releasable state. Needs a little bit of tidying up, a few more tests and examples, but it now has a more or less complete implementation of qpid-config to test interoperabili

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/tests/javascript/message.js
----------------------------------------------------------------------
diff --git a/tests/javascript/message.js b/tests/javascript/message.js
new file mode 100644
index 0000000..8f03ec8
--- /dev/null
+++ b/tests/javascript/message.js
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * This is a fairly literal JavaScript port of message.py used to unit test the
+ * proton.Message wrapper class.
+ */
+
+// Check if the environment is Node.js and if so import the required libraries.
+if (typeof exports !== "undefined" && exports !== null) {
+    unittest = require("./unittest.js");
+    assert = require("assert");
+    proton = require("qpid-proton");
+}
+
+/**
+ * JavaScript Implementation of Python's range() function taken from:
+ * http://stackoverflow.com/questions/8273047/javascript-function-similar-to-python-range
+ */
+var range = function(start, stop, step) {
+    if (typeof stop == 'undefined') {
+        // one param defined
+        stop = start;
+        start = 0;
+    };
+    if (typeof step == 'undefined') {
+        step = 1;
+    };
+    if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
+        return [];
+    };
+    var result = [];
+    for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
+        result.push(i);
+    };
+    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.
+    /**
+     * The following call is the equivalent of "super" in Java. It's not necessary
+     * here as the unittest.TestCase constructor doesn't set any state, but it
+     * is the correct thing to do when implementing classical inheritance in
+     * JavaScript so I've kept it here as a useful reminder of the "pattern".
+     */
+    //unittest.TestCase.prototype.constructor.call(this);
+};
+
+Test.prototype = new unittest.TestCase(); // Here's where the inheritance occurs.
+Test.prototype.constructor = Test; // Otherwise instances of Test would have a constructor of unittest.TestCase.
+
+Test.prototype.setUp = function() {
+    this.msg = new proton.Message();
+};
+
+Test.prototype.tearDown = function() {
+    this.msg.free();
+    this.msg = null;
+};
+
+
+// Extend Test more simply by creating a prototype instance and adding test methods as properties.
+
+var AccessorsTest = new Test();
+
+AccessorsTest._test = function(name, defaultValue, values) {
+    // 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.
+    // This scenario is what happens in the tests that use the range() function.
+    values = (Object.prototype.toString.call(values[0]) === '[object Array]') ? values[0] : values;
+
+    // Work out the accessor/mutator names noting that boolean accessors use "is" not "get".
+    var setter = 'set' + name;
+    var getter = (typeof defaultValue === 'boolean') ? 'is' + name : 'get' + name;
+
+    // Get the message's default value first.
+    var d = this.msg[getter]();
+
+    // Compare the message's default with the expected default value passed in the test case.
+    compare(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;
+
+        this.msg[setter](v); // This call will "consume" Binary data.
+        var gotten = this.msg[getter]();
+        compare(value, gotten);
+    }
+};
+
+AccessorsTest._testString = function(name) {
+    this._test(name, "", "asdf", "fdsa", "");
+};
+
+AccessorsTest._testTime = function(name) {
+    // The ExpiryTime and CreationTime methods can take either a number or a Date Object.
+    this._test(name, new Date(0), new Date(0), 123456789, new Date(987654321));
+};
+
+AccessorsTest.testID = function() {
+    console.log("testID");
+    this._test("ID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
+    console.log("OK\n");
+};
+
+AccessorsTest.testCorrelationID = function() {
+    console.log("testCorrelationID");
+    this._test("CorrelationID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
+    console.log("OK\n");
+};
+
+AccessorsTest.testDurable = function() {
+    console.log("testDurable");
+    this._test("Durable", false, true, false);
+    console.log("OK\n");
+};
+
+AccessorsTest.testPriority = function() {
+    console.log("testPriority");
+    this._test("Priority", proton.Message.DEFAULT_PRIORITY, range(0, 256));
+    console.log("OK\n");
+};
+
+AccessorsTest.testTTL = function() {
+    console.log("testTTL");
+    this._test("TTL", 0, range(12345, 54321));
+    console.log("OK\n");
+};
+
+AccessorsTest.testFirstAcquirer = function() {
+    console.log("testFirstAcquirer");
+    this._test("FirstAcquirer", false, true, false);
+    console.log("OK\n");
+};
+
+AccessorsTest.testDeliveryCount = function() {
+    console.log("testDeliveryCount");
+    this._test("DeliveryCount", 0, range(0, 1024));
+    console.log("OK\n");
+};
+
+AccessorsTest.testUserID = function() {
+    console.log("testUserID");
+    this._test("UserID", "", "asdf", "fdsa", new proton.Data.Binary("ВИНАРЫ"), "", new proton.Data.Uuid(), "");
+    console.log("OK\n");
+};
+
+AccessorsTest.testAddress = function() {
+    console.log("testAddress");
+    this._testString("Address");
+    console.log("OK\n");
+};
+
+AccessorsTest.testSubject = function() {
+    console.log("testSubject");
+    this._testString("Subject");
+    console.log("OK\n");
+};
+
+AccessorsTest.testReplyTo = function() {
+    console.log("testReplyTo");
+    this._testString("ReplyTo");
+    console.log("OK\n");
+};
+
+AccessorsTest.testContentType = function() {
+    console.log("testContentType");
+    this._testString("ContentType");
+    console.log("OK\n");
+};
+
+AccessorsTest.testContentEncoding = function() {
+    console.log("testContentEncoding");
+    this._testString("ContentEncoding");
+    console.log("OK\n");
+};
+
+AccessorsTest.testExpiryTime = function() {
+    console.log("testExpiryTime");
+    this._testTime("ExpiryTime");
+    console.log("OK\n");
+};
+
+AccessorsTest.testCreationTime = function() {
+    console.log("testCreationTime");
+    this._testTime("CreationTime");
+    console.log("OK\n");
+};
+
+AccessorsTest.testGroupID = function() {
+    console.log("testGroupID");
+    this._testString("GroupID");
+    console.log("OK\n");
+};
+
+AccessorsTest.testGroupSequence = function() {
+    console.log("testGroupSequence");
+    this._test("GroupSequence", 0, 0, -10, 10, 20, -20);
+    console.log("OK\n");
+};
+
+AccessorsTest.testReplyToGroupID = function() {
+    console.log("testReplyToGroupID");
+    this._testString("ReplyToGroupID");
+    console.log("OK\n");
+};
+
+
+var CodecTest = new Test();
+
+CodecTest.testRoundTrip = function() {
+    console.log("testRoundTrip");
+    this.msg.setID("asdf");
+    this.msg.setCorrelationID(new proton.Data.Uuid());
+    this.msg.setTTL(3);
+    this.msg.setPriority(100);
+    this.msg.setAddress("address");
+    this.msg.setSubject("subject");
+    this.msg.body = "Hello World!";
+
+    var data = this.msg.encode();
+    var msg2 = new proton.Message();
+    msg2.decode(data);
+
+    assert(this.msg.getID() === msg2.getID());
+    assert(this.msg.getCorrelationID().toString() === msg2.getCorrelationID().toString());
+    assert(this.msg.getTTL() === msg2.getTTL());
+    assert(this.msg.getPriority() === msg2.getPriority());
+    assert(this.msg.getAddress() === msg2.getAddress());
+    assert(this.msg.getSubject() === msg2.getSubject());
+    assert(this.msg.body === msg2.body);
+
+    msg2.free();
+    console.log("OK\n");
+};
+
+/*
+// load and save are deprecated, might to an equivalent using encode/decode
+var LoadSaveTest = new Test();
+
+
+LoadSaveTest.testIntegral = function() {
+    console.log("testIntegral");
+
+    console.log("OK\n");
+};
+
+LoadSaveTest.testFloating = function() {
+    console.log("testFloating");
+
+    console.log("OK\n");
+};
+*/
+
+
+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


[35/51] [abbrv] qpid-proton git commit: Export the proton version numbers to JavaScript via the bindings

Posted by rh...@apache.org.
Export the proton version numbers to JavaScript via the bindings

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1625355 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/929eab4d
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/929eab4d
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/929eab4d

Branch: refs/heads/master
Commit: 929eab4dc6c5f486bf646951776337c3cbd79e7c
Parents: abd646b
Author: fadams <fa...@unknown>
Authored: Tue Sep 16 19:00:14 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Tue Sep 16 19:00:14 2014 +0000

----------------------------------------------------------------------
 proton-c/bindings/javascript/CMakeLists.txt   | 13 +--------
 proton-c/bindings/javascript/binding-close.js |  6 ++++
 proton-c/bindings/javascript/binding.c        | 32 +++++++++++++++++++++-
 3 files changed, 38 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/929eab4d/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index 695fbd1..390c408 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -103,16 +103,6 @@ set(COMPILE_WARNING_FLAGS "-Werror -Wall -pedantic-errors -Wno-comment -Wno-warn
 # from a Windows platform
 set(PLATFORM_DEFINITIONS "USE_CLOCK_GETTIME;USE_UUID_GENERATE;USE_STRERROR_R;USE_ATOLL")
 
-# TODO temporary messages - remove.
-message(STATUS "COMPILE_WARNING_FLAGS: ${COMPILE_WARNING_FLAGS}")
-message(STATUS "PLATFORM_DEFINITIONS: ${PLATFORM_DEFINITIONS}")
-message(STATUS "UUID_LIB: ${UUID_LIB}")
-message(STATUS "SSL_LIB: ${SSL_LIB}")
-message(STATUS "TIME_LIB: ${TIME_LIB}")
-message(STATUS "PLATFORM_LIBS: ${PLATFORM_LIBS}") # can be empty for emscripten
-
-
-
 # The following is largely a copy from the the main proton-c/CMakeLists.txt.
 # The main difference is prefixing paths with ${PN_PATH}/ as we can't use a
 # relative path from this CMakeLists.txt.
@@ -221,7 +211,7 @@ set_target_properties(
   # fiddly with node.js packages. This behaviour might be reinstated if the
   # packaging mechanism improves.
 
-  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/module.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/error.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/message.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_bytes', '_pn_error_tex
 t', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '
 _pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence'
 , '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put
 _decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/module.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/error.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/message.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_get_version_major', '_
 pn_get_version_minor', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message',
  '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_messa
 ge_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_d
 ecimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
   )
 
 # This command packages up the compiled proton.js into a node.js package called
@@ -271,6 +261,5 @@ if (NODE_JSDOC_FOUND)
                       ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js
                       ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js)
     add_dependencies(docs docs-js)
-
 endif (NODE_JSDOC_FOUND)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/929eab4d/proton-c/bindings/javascript/binding-close.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding-close.js b/proton-c/bindings/javascript/binding-close.js
index 9faf241..b7f1d93 100644
--- a/proton-c/bindings/javascript/binding-close.js
+++ b/proton-c/bindings/javascript/binding-close.js
@@ -18,4 +18,10 @@
  *
  */
 
+// These values are essentially constants sitting in the proton namespace.
+// We have to set them after pn_get_version_major/pn_get_version_minor have been
+// defined so we must do it here in binding-close.js as it's a --post-js block.
+Module['VERSION_MAJOR'] = _pn_get_version_major();
+Module['VERSION_MINOR'] = _pn_get_version_minor();
+
 })(); // End of self calling lambda used to wrap library.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/929eab4d/proton-c/bindings/javascript/binding.c
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.c b/proton-c/bindings/javascript/binding.c
index 425efb4..ecc65dc 100644
--- a/proton-c/bindings/javascript/binding.c
+++ b/proton-c/bindings/javascript/binding.c
@@ -1,4 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
 
+/*
+ * This file is largely just a stub, we're actually creating a JavaScript library
+ * rather than an executable so most of the  work is done at the link stage.
+ * We do however need to link the libqpid-proton-bitcode.so with *something* and
+ * this is it. This file also provides a way to pass any global variable or
+ * #defined values to the JavaScript binding by providing wrapper functions.
+ */
 #include <stdio.h>
-// Just a stub.
+#include <proton/version.h>
+
+// To access #define values in JavaScript we need to wrap them in a function.
+int pn_get_version_major() {return PN_VERSION_MAJOR;}
+int pn_get_version_minor() {return PN_VERSION_MINOR;}
 


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


[18/51] [abbrv] qpid-proton git commit: Update with merge of latest proton codebase and checked against latest emscripten incoming branch

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
index 1949652..62cb10d 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
@@ -17,14 +17,14 @@
 
 package org.apache.qpid.proton.engine.impl;
 
-import static org.apache.qpid.proton.engine.impl.ByteBufferUtils.newReadableBuffer;
-import static org.apache.qpid.proton.engine.impl.ByteBufferUtils.pour;
 import static org.apache.qpid.proton.engine.impl.ByteBufferUtils.pourArrayToBuffer;
 import static org.apache.qpid.proton.engine.impl.ByteBufferUtils.pourBufferToArray;
 
 import java.nio.ByteBuffer;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.UnsignedInteger;
@@ -32,6 +32,7 @@ import org.apache.qpid.proton.amqp.UnsignedShort;
 import org.apache.qpid.proton.amqp.transport.Attach;
 import org.apache.qpid.proton.amqp.transport.Begin;
 import org.apache.qpid.proton.amqp.transport.Close;
+import org.apache.qpid.proton.amqp.transport.ConnectionError;
 import org.apache.qpid.proton.amqp.transport.Detach;
 import org.apache.qpid.proton.amqp.transport.Disposition;
 import org.apache.qpid.proton.amqp.transport.End;
@@ -44,10 +45,8 @@ import org.apache.qpid.proton.amqp.transport.Transfer;
 import org.apache.qpid.proton.codec.AMQPDefinedTypes;
 import org.apache.qpid.proton.codec.DecoderImpl;
 import org.apache.qpid.proton.codec.EncoderImpl;
-import org.apache.qpid.proton.codec.WritableBuffer;
 import org.apache.qpid.proton.engine.Connection;
 import org.apache.qpid.proton.engine.EndpointState;
-import org.apache.qpid.proton.engine.EngineFactory;
 import org.apache.qpid.proton.engine.Event;
 import org.apache.qpid.proton.engine.ProtonJTransport;
 import org.apache.qpid.proton.engine.Sasl;
@@ -66,7 +65,20 @@ public class TransportImpl extends EndpointImpl
     implements ProtonJTransport, FrameBody.FrameBodyHandler<Integer>,
         FrameHandler, TransportOutputWriter
 {
-    private static final byte AMQP_FRAME_TYPE = 0;
+    static final int BUFFER_RELEASE_THRESHOLD = Integer.getInteger("proton.transport_buffer_release_threshold", 2 * 1024 * 1024);
+
+    private static final boolean getBooleanEnv(String name)
+    {
+        String value = System.getenv(name);
+        return "true".equalsIgnoreCase(value) ||
+            "1".equals(value) ||
+            "yes".equalsIgnoreCase(value);
+    }
+
+    private static final boolean FRM_ENABLED = getBooleanEnv("PN_TRACE_FRM");
+
+    // trace levels
+    private int _levels = (FRM_ENABLED ? this.TRACE_FRM : 0);
 
     private FrameParser _frameParser;
 
@@ -100,16 +112,16 @@ public class TransportImpl extends EndpointImpl
     private Open _open;
     private SaslImpl _sasl;
     private SslImpl _ssl;
-    private ProtocolTracer _protocolTracer = null;
-
-    private ByteBuffer _lastInputBuffer;
+    private final Ref<ProtocolTracer> _protocolTracer = new Ref(null);
 
     private TransportResult _lastTransportResult = TransportResultFactory.ok();
 
     private boolean _init;
+    private boolean _processingStarted;
 
     private FrameHandler _frameHandler = this;
     private boolean _head_closed = false;
+    private TransportException _tail_error = null;
 
     /**
      * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
@@ -134,7 +146,6 @@ public class TransportImpl extends EndpointImpl
                                        FrameWriter.AMQP_FRAME_TYPE,
                                        _protocolTracer,
                                        this);
-
     }
 
     private void init()
@@ -149,6 +160,11 @@ public class TransportImpl extends EndpointImpl
     }
 
     @Override
+    public void trace(int levels) {
+        _levels = levels;
+    }
+
+    @Override
     public int getMaxFrameSize()
     {
         return _maxFrameSize;
@@ -194,9 +210,10 @@ public class TransportImpl extends EndpointImpl
     @Override
     public void bind(Connection conn)
     {
-        // TODO - check if already bound
-        ((ConnectionImpl) conn).setTransport(this);
         _connectionEndpoint = (ConnectionImpl) conn;
+        // TODO - check if already bound
+        _connectionEndpoint.setTransport(this);
+        _connectionEndpoint.incref();
 
         if(getRemoteState() != EndpointState.UNINITIALIZED)
         {
@@ -211,6 +228,23 @@ public class TransportImpl extends EndpointImpl
     }
 
     @Override
+    public void unbind()
+    {
+        _connectionEndpoint.modifyEndpoints();
+
+        _connectionEndpoint.setTransport(null);
+        _connectionEndpoint.decref();
+
+        for (TransportSession ts: _transportSessionState.values()) {
+            ts.unbind();
+        }
+
+        for (TransportLink tl: _transportLinkState.values()) {
+            tl.unbind();
+        }
+    }
+
+    @Override
     public int input(byte[] bytes, int offset, int length)
     {
         oldApiCheckStateBeforeInput(length).checkIsOk();
@@ -278,8 +312,13 @@ public class TransportImpl extends EndpointImpl
     {
         if(_sasl == null)
         {
+            if(_processingStarted)
+            {
+                throw new IllegalStateException("Sasl can't be initiated after transport has started processing");
+            }
+
             init();
-            _sasl = new SaslImpl(_remoteMaxFrameSize);
+            _sasl = new SaslImpl(this, _remoteMaxFrameSize);
             TransportWrapper transportWrapper = _sasl.wrap(_inputProcessor, _outputProcessor);
             _inputProcessor = transportWrapper;
             _outputProcessor = transportWrapper;
@@ -334,38 +373,37 @@ public class TransportImpl extends EndpointImpl
                        && transportLink.isLocalHandleSet()
                        && !_isCloseSent)
                     {
-                        if(!(link instanceof SenderImpl)
-                           || link.getQueued() == 0
-                           || transportLink.detachReceived()
-                           || transportSession.endReceived()
-                           || _closeReceived)
-                        {
-                            UnsignedInteger localHandle = transportLink.getLocalHandle();
-                            transportLink.clearLocalHandle();
-                            transportSession.freeLocalHandle(localHandle);
+                        if((link instanceof SenderImpl)
+                           && link.getQueued() > 0
+                           && !transportLink.detachReceived()
+                           && !transportSession.endReceived()
+                           && !_closeReceived) {
+                            endpoint = endpoint.transportNext();
+                            continue;
+                        }
 
+                        UnsignedInteger localHandle = transportLink.getLocalHandle();
+                        transportLink.clearLocalHandle();
+                        transportSession.freeLocalHandle(localHandle);
 
-                            Detach detach = new Detach();
-                            detach.setHandle(localHandle);
-                            // TODO - need an API for detaching rather than closing the link
-                            detach.setClosed(true);
 
-                            ErrorCondition localError = link.getCondition();
-                            if( localError.getCondition() !=null )
-                            {
-                                detach.setError(localError);
-                            }
+                        Detach detach = new Detach();
+                        detach.setHandle(localHandle);
+                        // TODO - need an API for detaching rather than closing the link
+                        detach.setClosed(true);
 
+                        ErrorCondition localError = link.getCondition();
+                        if( localError.getCondition() !=null )
+                        {
+                            detach.setError(localError);
+                        }
 
-                            writeFrame(transportSession.getLocalChannel(), detach, null, null);
-                            endpoint.clearModified();
 
-                            // TODO - temporary hack for PROTON-154, this line should be removed and replaced
-                            //        with proper handling for closed links
-                            link.free();
-                        }
+                        writeFrame(transportSession.getLocalChannel(), detach, null, null);
                     }
 
+                    endpoint.clearModified();
+
                 }
                 endpoint = endpoint.transportNext();
             }
@@ -411,8 +449,6 @@ public class TransportImpl extends EndpointImpl
                         sender.setDrained(0);
 
                         writeFlow(transportSession, transportLink);
-
-                        endpoint.clearModified();
                     }
 
                 }
@@ -470,7 +506,7 @@ public class TransportImpl extends EndpointImpl
         if(!delivery.isDone() &&
            (delivery.getDataLength() > 0 || delivery != snd.current()) &&
            tpSession.hasOutgoingCredit() && tpLink.hasCredit() &&
-           tpLink.getLocalHandle() != null)
+           tpLink.getLocalHandle() != null && !_frameWriter.isFull())
         {
             UnsignedInteger deliveryId = tpSession.getOutgoingDeliveryId();
             TransportDelivery tpDelivery = new TransportDelivery(deliveryId, delivery, tpLink);
@@ -529,6 +565,8 @@ public class TransportImpl extends EndpointImpl
                 delivery.setDataLength(payload.remaining());
                 session.incrementOutgoingBytes(-delta);
             }
+
+            getConnectionImpl().put(Event.Type.LINK_FLOW, snd);
         }
 
         if(wasDone && delivery.getLocalState() != null)
@@ -596,10 +634,6 @@ public class TransportImpl extends EndpointImpl
                         {
                             transportLink.addCredit(credits);
                             writeFlow(transportSession, transportLink);
-                            if(receiver.getLocalState() == EndpointState.ACTIVE)
-                            {
-                                endpoint.clearModified();
-                            }
                         }
                     }
                 }
@@ -689,10 +723,6 @@ public class TransportImpl extends EndpointImpl
 
                             writeFrame(transportSession.getLocalChannel(), attach, null, null);
                             transportLink.sentAttach();
-                            if(link.getLocalState() == EndpointState.ACTIVE && (link instanceof SenderImpl || !link.hasCredit()))
-                            {
-                                endpoint.clearModified();
-                            }
                         }
                     }
                 }
@@ -712,15 +742,22 @@ public class TransportImpl extends EndpointImpl
 
     private void processOpen()
     {
-        if(_connectionEndpoint != null && _connectionEndpoint.getLocalState() != EndpointState.UNINITIALIZED && !_isOpenSent)
-        {
+        if ((_tail_error != null ||
+             (_connectionEndpoint != null &&
+              _connectionEndpoint.getLocalState() != EndpointState.UNINITIALIZED)) &&
+            !_isOpenSent) {
             Open open = new Open();
-            String cid = _connectionEndpoint.getLocalContainerId();
-            open.setContainerId(cid == null ? "" : cid);
-            open.setHostname(_connectionEndpoint.getHostname());
-            open.setDesiredCapabilities(_connectionEndpoint.getDesiredCapabilities());
-            open.setOfferedCapabilities(_connectionEndpoint.getOfferedCapabilities());
-            open.setProperties(_connectionEndpoint.getProperties());
+            if (_connectionEndpoint != null) {
+                String cid = _connectionEndpoint.getLocalContainerId();
+                open.setContainerId(cid == null ? "" : cid);
+                open.setHostname(_connectionEndpoint.getHostname());
+                open.setDesiredCapabilities(_connectionEndpoint.getDesiredCapabilities());
+                open.setOfferedCapabilities(_connectionEndpoint.getOfferedCapabilities());
+                open.setProperties(_connectionEndpoint.getProperties());
+            } else {
+                open.setContainerId("");
+            }
+
             if (_maxFrameSize > 0) {
                 open.setMaxFrameSize(UnsignedInteger.valueOf(_maxFrameSize));
             }
@@ -731,7 +768,6 @@ public class TransportImpl extends EndpointImpl
             _isOpenSent = true;
 
             writeFrame(0, open, null, null);
-
         }
     }
 
@@ -762,10 +798,6 @@ public class TransportImpl extends EndpointImpl
 
                         writeFrame(channelId, begin, null, null);
                         transportSession.sentBegin();
-                        if(session.getLocalState() == EndpointState.ACTIVE)
-                        {
-                            endpoint.clearModified();
-                        }
                     }
                 }
                 endpoint = endpoint.transportNext();
@@ -829,21 +861,27 @@ public class TransportImpl extends EndpointImpl
                 SessionImpl session;
                 TransportSession transportSession;
 
-                if((endpoint instanceof SessionImpl)
-                   && (session = (SessionImpl)endpoint).getLocalState() == EndpointState.CLOSED
-                   && (transportSession = session.getTransportSession()).isLocalChannelSet()
-                   && !hasSendableMessages(session)
-                   && !_isCloseSent)
-                {
-                    int channel = freeLocalChannel(transportSession);
-                    End end = new End();
-                    ErrorCondition localError = endpoint.getCondition();
-                    if( localError.getCondition() !=null )
+                if((endpoint instanceof SessionImpl)) {
+                    if ((session = (SessionImpl)endpoint).getLocalState() == EndpointState.CLOSED
+                        && (transportSession = session.getTransportSession()).isLocalChannelSet()
+                        && !_isCloseSent)
                     {
-                        end.setError(localError);
+                        if (hasSendableMessages(session)) {
+                            endpoint = endpoint.transportNext();
+                            continue;
+                        }
+
+                        int channel = freeLocalChannel(transportSession);
+                        End end = new End();
+                        ErrorCondition localError = endpoint.getCondition();
+                        if( localError.getCondition() !=null )
+                        {
+                            end.setError(localError);
+                        }
+
+                        writeFrame(channel, end, null, null);
                     }
 
-                    writeFrame(channel, end, null, null);
                     endpoint.clearModified();
                 }
 
@@ -854,6 +892,9 @@ public class TransportImpl extends EndpointImpl
 
     private boolean hasSendableMessages(SessionImpl session)
     {
+        if (_connectionEndpoint == null) {
+            return false;
+        }
 
         if(!_closeReceived && (session == null || !session.getTransportSession().endReceived()))
         {
@@ -878,14 +919,24 @@ public class TransportImpl extends EndpointImpl
 
     private void processClose()
     {
-        if(_connectionEndpoint != null && _connectionEndpoint.getLocalState() == EndpointState.CLOSED && !_isCloseSent)
-        {
+        if ((_tail_error != null ||
+             (_connectionEndpoint != null &&
+              _connectionEndpoint.getLocalState() == EndpointState.CLOSED)) &&
+            !_isCloseSent) {
             if(!hasSendableMessages(null))
             {
                 Close close = new Close();
 
-                ErrorCondition localError = _connectionEndpoint.getCondition();
-                if( localError.getCondition() !=null )
+                ErrorCondition localError;
+
+                if (_connectionEndpoint == null) {
+                    localError = new ErrorCondition(ConnectionError.FRAMING_ERROR,
+                                                    _tail_error.toString());
+                } else {
+                    localError =  _connectionEndpoint.getCondition();
+                }
+
+                if(localError.getCondition() != null)
                 {
                     close.setError(localError);
                 }
@@ -893,6 +944,10 @@ public class TransportImpl extends EndpointImpl
                 _isCloseSent = true;
 
                 writeFrame(0, close, null, null);
+
+                if (_connectionEndpoint != null) {
+                    _connectionEndpoint.clearModified();
+                }
             }
         }
     }
@@ -912,10 +967,10 @@ public class TransportImpl extends EndpointImpl
     }
 
     @Override
-    public void free()
-    {
-        super.free();
-    }
+    void postFinal() {}
+
+    @Override
+    void doFree() { }
 
     //==================================================================================================================
     // handle incoming amqp data
@@ -967,6 +1022,9 @@ public class TransportImpl extends EndpointImpl
             {
                 // TODO check null
                 transportSession = _localSessions.get(begin.getRemoteChannel().intValue());
+                if (transportSession == null) {
+                    throw new NullPointerException("uncorrelated channel: " + begin.getRemoteChannel());
+                }
                 session = transportSession.getSession();
 
             }
@@ -975,10 +1033,7 @@ public class TransportImpl extends EndpointImpl
             transportSession.setNextIncomingId(begin.getNextOutgoingId());
             _remoteSessions.put(channel, transportSession);
 
-            EventImpl ev = _connectionEndpoint.put(Event.Type.SESSION_REMOTE_STATE);
-            if (ev != null) {
-                ev.init(session);
-            }
+            _connectionEndpoint.put(Event.Type.SESSION_REMOTE_OPEN, session);
         }
 
     }
@@ -1034,10 +1089,7 @@ public class TransportImpl extends EndpointImpl
 
             }
 
-            EventImpl ev = _connectionEndpoint.put(Event.Type.LINK_REMOTE_STATE);
-            if (ev != null) {
-                ev.init(link);
-            }
+            _connectionEndpoint.put(Event.Type.LINK_REMOTE_OPEN, link);
         }
     }
 
@@ -1102,16 +1154,13 @@ public class TransportImpl extends EndpointImpl
                 LinkImpl link = transportLink.getLink();
                 transportLink.receivedDetach();
                 transportSession.freeRemoteHandle(transportLink.getRemoteHandle());
+                _connectionEndpoint.put(Event.Type.LINK_REMOTE_CLOSE, link);
+                transportLink.clearRemoteHandle();
                 link.setRemoteState(EndpointState.CLOSED);
                 if(detach.getError() != null)
                 {
                     link.getRemoteCondition().copyFrom(detach.getError());
                 }
-
-                EventImpl ev = _connectionEndpoint.put(Event.Type.LINK_REMOTE_STATE);
-                if (ev != null) {
-                    ev.init(link);
-                }
             }
             else
             {
@@ -1140,10 +1189,7 @@ public class TransportImpl extends EndpointImpl
                 session.getRemoteCondition().copyFrom(errorCondition);
             }
 
-            EventImpl ev = _connectionEndpoint.put(Event.Type.SESSION_REMOTE_STATE);
-            if (ev != null) {
-                ev.init(session);
-            }
+            _connectionEndpoint.put(Event.Type.SESSION_REMOTE_CLOSE, session);
         }
     }
 
@@ -1160,10 +1206,7 @@ public class TransportImpl extends EndpointImpl
                 _connectionEndpoint.getRemoteCondition().copyFrom(close.getError());
             }
 
-            EventImpl ev = _connectionEndpoint.put(Event.Type.CONNECTION_REMOTE_STATE);
-            if (ev != null) {
-                ev.init(_connectionEndpoint);
-            }
+            _connectionEndpoint.put(Event.Type.CONNECTION_REMOTE_CLOSE, _connectionEndpoint);
         }
 
     }
@@ -1176,11 +1219,12 @@ public class TransportImpl extends EndpointImpl
             throw new IllegalStateException("Transport cannot accept frame: " + frame);
         }
 
-        log(this, INCOMING, frame);
+        log(INCOMING, frame);
 
-        if( _protocolTracer != null )
+        ProtocolTracer tracer = _protocolTracer.get();
+        if( tracer != null )
         {
-            _protocolTracer.receivedFrame(frame);
+            tracer.receivedFrame(frame);
         }
 
         frame.getBody().invoke(this,frame.getPayload(), frame.getChannel());
@@ -1188,10 +1232,15 @@ public class TransportImpl extends EndpointImpl
     }
 
     @Override
-    public void closed()
+    public void closed(TransportException error)
     {
-        if (!_closeReceived) {
-            throw new TransportException("connection aborted");
+        if (!_closeReceived || error != null) {
+            if (error == null) {
+                _tail_error = new TransportException("connection aborted");
+            } else {
+                _tail_error = error;
+            }
+            _head_closed = true;
         }
     }
 
@@ -1204,13 +1253,13 @@ public class TransportImpl extends EndpointImpl
     @Override
     public ProtocolTracer getProtocolTracer()
     {
-        return _protocolTracer;
+        return _protocolTracer.get();
     }
 
     @Override
     public void setProtocolTracer(ProtocolTracer protocolTracer)
     {
-        this._protocolTracer = protocolTracer;
+        this._protocolTracer.set(protocolTracer);
     }
 
     @Override
@@ -1260,6 +1309,8 @@ public class TransportImpl extends EndpointImpl
     @Override
     public void process() throws TransportException
     {
+        _processingStarted = true;
+
         try {
             init();
             _inputProcessor.process();
@@ -1303,6 +1354,12 @@ public class TransportImpl extends EndpointImpl
         _outputProcessor.close_head();
     }
 
+    public boolean isClosed() {
+        int p = pending();
+        int c = capacity();
+        return  p == END_OF_STREAM && c == END_OF_STREAM;
+    }
+
     @Override
     public String toString()
     {
@@ -1337,21 +1394,11 @@ public class TransportImpl extends EndpointImpl
     static String INCOMING = "<-";
     static String OUTGOING = "->";
 
-    private static final boolean getBooleanEnv(String name)
+    void log(String event, TransportFrame frame)
     {
-        String value = System.getenv(name);
-        return "true".equalsIgnoreCase(value) ||
-            "1".equals(value) ||
-            "yes".equalsIgnoreCase(value);
-    }
-
-    private static final boolean ENABLED = getBooleanEnv("PN_TRACE_FRM");
-
-    static void log(Object ctx, String event, TransportFrame frame)
-    {
-        if (ENABLED) {
+        if ((_levels & TRACE_FRM) != 0) {
             StringBuilder msg = new StringBuilder();
-            msg.append("[").append(System.identityHashCode(ctx)).append(":")
+            msg.append("[").append(System.identityHashCode(this)).append(":")
                 .append(frame.getChannel()).append("]");
             msg.append(" ").append(event).append(" ").append(frame.getBody());
             if (frame.getPayload() != null) {
@@ -1366,7 +1413,8 @@ public class TransportImpl extends EndpointImpl
     }
 
     @Override
-    protected void localStateChanged()
-    {
-    }
+    void localOpen() {}
+
+    @Override
+    void localClose() {}
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportLink.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportLink.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportLink.java
index d9de3a7..4b94a42 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportLink.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportLink.java
@@ -51,6 +51,12 @@ class TransportLink<T extends LinkImpl>
                        : new TransportSender((SenderImpl)link));
     }
 
+    void unbind()
+    {
+        clearLocalHandle();
+        clearRemoteHandle();
+    }
+
     public UnsignedInteger getLocalHandle()
     {
         return _localHandle;
@@ -58,6 +64,9 @@ class TransportLink<T extends LinkImpl>
 
     public void setLocalHandle(UnsignedInteger localHandle)
     {
+        if (_localHandle == null) {
+            _link.incref();
+        }
         _localHandle = localHandle;
     }
 
@@ -78,6 +87,9 @@ class TransportLink<T extends LinkImpl>
 
     public void clearLocalHandle()
     {
+        if (_localHandle != null) {
+            _link.decref();
+        }
         _localHandle = null;
     }
 
@@ -88,9 +100,20 @@ class TransportLink<T extends LinkImpl>
 
     public void setRemoteHandle(UnsignedInteger remoteHandle)
     {
+        if (_remoteHandle == null) {
+            _link.incref();
+        }
         _remoteHandle = remoteHandle;
     }
 
+    public void clearRemoteHandle()
+    {
+        if (_remoteHandle != null) {
+            _link.decref();
+        }
+        _remoteHandle = null;
+    }
+
     public UnsignedInteger getDeliveryCount()
     {
         return _deliveryCount;
@@ -122,10 +145,7 @@ class TransportLink<T extends LinkImpl>
         _remoteLinkCredit = flow.getLinkCredit();
 
 
-        EventImpl ev = _link.getConnectionImpl().put(Event.Type.LINK_FLOW);
-        if (ev != null) {
-            ev.init(_link);
-        }
+        _link.getConnectionImpl().put(Event.Type.LINK_FLOW, _link);
     }
 
     void setLinkCredit(UnsignedInteger linkCredit)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptor.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptor.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptor.java
index cc23355..2c43bfe 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptor.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptor.java
@@ -26,23 +26,20 @@ import org.apache.qpid.proton.engine.Transport;
 
 class TransportOutputAdaptor implements TransportOutput
 {
-    private TransportOutputWriter _transportOutputWriter;
+    private static final ByteBuffer _emptyHead = newReadableBuffer(0).asReadOnlyBuffer();
 
-    private final ByteBuffer _outputBuffer;
-    private final ByteBuffer _head;
+    private final TransportOutputWriter _transportOutputWriter;
+    private final int _maxFrameSize;
+
+    private ByteBuffer _outputBuffer = null;
+    private ByteBuffer _head = null;
     private boolean _output_done = false;
     private boolean _head_closed = false;
 
     TransportOutputAdaptor(TransportOutputWriter transportOutputWriter, int maxFrameSize)
     {
         _transportOutputWriter = transportOutputWriter;
-        if (maxFrameSize > 0) {
-            _outputBuffer = newWriteableBuffer(maxFrameSize);
-        } else {
-            _outputBuffer = newWriteableBuffer(4*1024);
-        }
-        _head = _outputBuffer.asReadOnlyBuffer();
-        _head.limit(0);
+        _maxFrameSize = maxFrameSize > 0 ? maxFrameSize : 4*1024;
     }
 
     @Override
@@ -52,13 +49,26 @@ class TransportOutputAdaptor implements TransportOutput
             return Transport.END_OF_STREAM;
         }
 
+        if(_outputBuffer == null)
+        {
+            init_buffers();
+        }
+
         _output_done = _transportOutputWriter.writeInto(_outputBuffer);
         _head.limit(_outputBuffer.position());
 
-        if (_output_done && _outputBuffer.position() == 0) {
+        if (_outputBuffer.position() == 0 && _outputBuffer.capacity() > TransportImpl.BUFFER_RELEASE_THRESHOLD)
+        {
+            release_buffers();
+        }
+
+        if (_output_done && (_outputBuffer == null || _outputBuffer.position() == 0))
+        {
             return Transport.END_OF_STREAM;
-        } else {
-            return _outputBuffer.position();
+        }
+        else
+        {
+            return _outputBuffer == null ? 0 : _outputBuffer.position();
         }
     }
 
@@ -66,24 +76,40 @@ class TransportOutputAdaptor implements TransportOutput
     public ByteBuffer head()
     {
         pending();
-        return _head;
+        return _head != null ? _head : _emptyHead;
     }
 
     @Override
     public void pop(int bytes)
     {
-        _outputBuffer.flip();
-        _outputBuffer.position(bytes);
-        _outputBuffer.compact();
-        _head.position(0);
-        _head.limit(_outputBuffer.position());
+        if (_outputBuffer != null) {
+            _outputBuffer.flip();
+            _outputBuffer.position(bytes);
+            _outputBuffer.compact();
+            _head.position(0);
+            _head.limit(_outputBuffer.position());
+            if (_outputBuffer.position() == 0 && _outputBuffer.capacity() > TransportImpl.BUFFER_RELEASE_THRESHOLD) {
+                release_buffers();
+            }
+        }
     }
 
     @Override
     public void close_head()
     {
         _head_closed = true;
-        _transportOutputWriter.closed();
+        _transportOutputWriter.closed(null);
+        release_buffers();
+    }
+
+    private void init_buffers() {
+        _outputBuffer = newWriteableBuffer(_maxFrameSize);
+        _head = _outputBuffer.asReadOnlyBuffer();
+        _head.limit(0);
     }
 
+    private void release_buffers() {
+        _head = null;
+        _outputBuffer = null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputWriter.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputWriter.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputWriter.java
index 2428da1..76c0df7 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputWriter.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportOutputWriter.java
@@ -20,6 +20,8 @@ package org.apache.qpid.proton.engine.impl;
 
 import java.nio.ByteBuffer;
 
+import org.apache.qpid.proton.engine.TransportException;
+
 interface TransportOutputWriter
 {
     /**
@@ -28,6 +30,6 @@ interface TransportOutputWriter
      */
     boolean writeInto(ByteBuffer outputBuffer);
 
-    void closed();
+    void closed(TransportException error);
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportSession.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportSession.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportSession.java
index 873254a..6d96043 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportSession.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportSession.java
@@ -69,6 +69,12 @@ class TransportSession
         _session = session;
     }
 
+    void unbind()
+    {
+        unsetLocalChannel();
+        unsetRemoteChannel();
+    }
+
     public SessionImpl getSession()
     {
         return _session;
@@ -81,6 +87,9 @@ class TransportSession
 
     public void setLocalChannel(int localChannel)
     {
+        if (!isLocalChannelSet()) {
+            _session.incref();
+        }
         _localChannel = localChannel;
     }
 
@@ -91,6 +100,9 @@ class TransportSession
 
     public void setRemoteChannel(int remoteChannel)
     {
+        if (!isRemoteChannelSet()) {
+            _session.incref();
+        }
         _remoteChannel = remoteChannel;
     }
 
@@ -116,11 +128,17 @@ class TransportSession
 
     public void unsetLocalChannel()
     {
+        if (isLocalChannelSet()) {
+            _session.decref();
+        }
         _localChannel = -1;
     }
 
     public void unsetRemoteChannel()
     {
+        if (isRemoteChannelSet()) {
+            _session.decref();
+        }
         _remoteChannel = -1;
     }
 
@@ -262,7 +280,7 @@ class TransportSession
             _unsettledIncomingDeliveriesById.put(_incomingDeliveryId, delivery);
             getSession().incrementIncomingDeliveries(1);
         }
-        if( transfer.getState()!=null ) 
+        if( transfer.getState()!=null )
         {
             delivery.setRemoteDeliveryState(transfer.getState());
         }
@@ -308,15 +326,12 @@ class TransportSession
             delivery.getLink().modified(false);
         }
 
-        EventImpl ev = getSession().getConnection().put(Event.Type.DELIVERY);
-        if (ev != null) {
-            ev.init(delivery);
-        }
+        getSession().getConnection().put(Event.Type.DELIVERY, delivery);
     }
 
     public void freeLocalChannel()
     {
-        _localChannel = -1;
+        unsetLocalChannel();
     }
 
     private void setRemoteIncomingWindow(UnsignedInteger incomingWindow)
@@ -394,10 +409,7 @@ class TransportSession
                 }
                 delivery.updateWork();
 
-                EventImpl ev = getSession().getConnection().put(Event.Type.DELIVERY);
-                if (ev != null) {
-                    ev.init(delivery);
-                }
+                getSession().getConnection().put(Event.Type.DELIVERY, delivery);
             }
             id = id.add(UnsignedInteger.ONE);
         }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java
index 38341bf..2599290 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java
@@ -338,22 +338,13 @@ public class SimpleSslTransportWrapper implements SslTransportWrapper
 
         _inputBuffer.flip();
 
-        try
-        {
-            try {
-                unwrapInput();
-            } catch (SSLException e) {
-                throw new TransportException(e);
-            }
-        }
-        catch (TransportException e)
-        {
+        try {
+            unwrapInput();
+        } catch (SSLException e) {
+            _logger.log(Level.WARNING, e.getMessage());
             _inputBuffer.position(_inputBuffer.limit());
             _tail_closed = true;
-            throw e;
-        }
-        finally
-        {
+        } finally {
             _inputBuffer.compact();
         }
     }
@@ -374,17 +365,17 @@ public class SimpleSslTransportWrapper implements SslTransportWrapper
         try {
             wrapOutput();
         } catch (SSLException e) {
-            throw new TransportException(e);
+            _logger.log(Level.WARNING, e.getMessage());
+            _head_closed = true;
         }
 
         _head.limit(_outputBuffer.position());
 
-        if (_head_closed && _outputBuffer.position() == 0)
-        {
+        if (_head_closed && _outputBuffer.position() == 0) {
             return Transport.END_OF_STREAM;
-        } else {
-            return _outputBuffer.position();
         }
+
+        return _outputBuffer.position();
     }
 
     @Override
@@ -408,6 +399,10 @@ public class SimpleSslTransportWrapper implements SslTransportWrapper
     public void close_head()
     {
         _underlyingOutput.close_head();
+        int p = pending();
+        if (p > 0) {
+            pop(p);
+        }
     }
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java
index b9ec972..fbcb0f5 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java
@@ -19,7 +19,6 @@
 package org.apache.qpid.proton.engine.impl.ssl;
 
 import org.apache.qpid.proton.ProtonUnsupportedOperationException;
-import org.apache.qpid.proton.engine.EngineFactory;
 import org.apache.qpid.proton.engine.ProtonJSslDomain;
 import org.apache.qpid.proton.engine.SslDomain;
 import org.apache.qpid.proton.engine.SslPeerDetails;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslPeerDetailsImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslPeerDetailsImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslPeerDetailsImpl.java
index a873e8e..87a9fe3 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslPeerDetailsImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslPeerDetailsImpl.java
@@ -18,7 +18,6 @@
  */
 package org.apache.qpid.proton.engine.impl.ssl;
 
-import org.apache.qpid.proton.engine.EngineFactory;
 import org.apache.qpid.proton.engine.ProtonJSslPeerDetails;
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/message/Message.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/message/Message.java b/proton-j/src/main/java/org/apache/qpid/proton/message/Message.java
index d039001..aede34b 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/message/Message.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/message/Message.java
@@ -28,6 +28,8 @@ import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
 import org.apache.qpid.proton.amqp.messaging.Properties;
 import org.apache.qpid.proton.amqp.messaging.Section;
 
+import org.apache.qpid.proton.message.impl.MessageImpl;
+
 /**
  * Represents a Message within Proton.
  *
@@ -36,6 +38,27 @@ import org.apache.qpid.proton.amqp.messaging.Section;
  */
 public interface Message
 {
+
+    public static final class Factory
+    {
+        public static Message create() {
+            return new MessageImpl();
+        }
+
+        public static Message create(Header header,
+                                     DeliveryAnnotations deliveryAnnotations,
+                                     MessageAnnotations messageAnnotations,
+                                     Properties properties,
+                                     ApplicationProperties applicationProperties,
+                                     Section body,
+                                     Footer footer) {
+            return new MessageImpl(header, deliveryAnnotations,
+                                   messageAnnotations, properties,
+                                   applicationProperties, body, footer);
+        }
+    }
+
+
     short DEFAULT_PRIORITY = 4;
 
     boolean isDurable();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/message/MessageFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/message/MessageFactory.java b/proton-j/src/main/java/org/apache/qpid/proton/message/MessageFactory.java
deleted file mode 100644
index 1323726..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/message/MessageFactory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton.message;
-
-import org.apache.qpid.proton.ProtonFactory;
-import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
-import org.apache.qpid.proton.amqp.messaging.DeliveryAnnotations;
-import org.apache.qpid.proton.amqp.messaging.Footer;
-import org.apache.qpid.proton.amqp.messaging.Header;
-import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
-import org.apache.qpid.proton.amqp.messaging.Properties;
-import org.apache.qpid.proton.amqp.messaging.Section;
-
-public interface MessageFactory extends ProtonFactory
-{
-    Message createMessage();
-    Message createMessage(Header header,
-                          DeliveryAnnotations deliveryAnnotations, MessageAnnotations messageAnnotations,
-                          Properties properties, ApplicationProperties applicationProperties,
-                          Section body, Footer footer);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageFactoryImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageFactoryImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageFactoryImpl.java
deleted file mode 100644
index 293fd8c..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageFactoryImpl.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton.message.impl;
-
-import org.apache.qpid.proton.ProtonFactoryImpl;
-import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
-import org.apache.qpid.proton.amqp.messaging.DeliveryAnnotations;
-import org.apache.qpid.proton.amqp.messaging.Footer;
-import org.apache.qpid.proton.amqp.messaging.Header;
-import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
-import org.apache.qpid.proton.amqp.messaging.Properties;
-import org.apache.qpid.proton.amqp.messaging.Section;
-import org.apache.qpid.proton.message.MessageFactory;
-import org.apache.qpid.proton.message.ProtonJMessage;
-
-public class MessageFactoryImpl extends ProtonFactoryImpl implements MessageFactory
-{
-
-    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
-    @Override
-    public ProtonJMessage createMessage()
-    {
-        return new MessageImpl();
-    }
-
-    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
-    @Override
-    public ProtonJMessage createMessage(Header header,
-                                 DeliveryAnnotations deliveryAnnotations, MessageAnnotations messageAnnotations,
-                                 Properties properties, ApplicationProperties applicationProperties,
-                                 Section body, Footer footer)
-    {
-        return new MessageImpl(header,
-                               deliveryAnnotations, messageAnnotations,
-                               properties, applicationProperties,
-                               body, footer);
-    }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
index 272756d..c43ba3e 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
@@ -573,8 +573,15 @@ public class MessageImpl implements ProtonJMessage
     @Override
     public int decode(byte[] data, int offset, int length)
     {
-        DecoderImpl decoder = tlsCodec.get().decoder;
         final ByteBuffer buffer = ByteBuffer.wrap(data, offset, length);
+        decode(buffer);
+
+        return length-buffer.remaining();
+    }
+
+    public void decode(ByteBuffer buffer)
+    {
+        DecoderImpl decoder = tlsCodec.get().decoder;
         decoder.setByteBuffer(buffer);
 
         _header = null;
@@ -680,9 +687,6 @@ public class MessageImpl implements ProtonJMessage
         }
 
         decoder.setByteBuffer(null);
-        
-        return length-buffer.remaining();
-
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
index cf8dd9a..6d3f362 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
@@ -25,6 +25,8 @@ import java.io.IOException;
 import org.apache.qpid.proton.TimeoutException;
 import org.apache.qpid.proton.message.Message;
 
+import org.apache.qpid.proton.messenger.impl.MessengerImpl;
+
 /**
  *
  *  Messenger defines a high level interface for sending and receiving
@@ -69,6 +71,18 @@ import org.apache.qpid.proton.message.Message;
 */
 public interface Messenger
 {
+
+    public static final class Factory
+    {
+        public static Messenger create() {
+            return new MessengerImpl();
+        }
+
+        public static Messenger create(String name) {
+            return new MessengerImpl(name);
+        }
+    }
+
     /**
      * Flag for use with reject(), accept() and settle() methods.
      */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/messenger/MessengerFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/MessengerFactory.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/MessengerFactory.java
deleted file mode 100644
index 9d85aae..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/MessengerFactory.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.proton.messenger;
-
-import org.apache.qpid.proton.ProtonFactory;
-
-public interface MessengerFactory extends ProtonFactory
-{
-    Messenger createMessenger();
-    Messenger createMessenger(String name);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerFactoryImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerFactoryImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerFactoryImpl.java
deleted file mode 100644
index 6a2bd12..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerFactoryImpl.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.proton.messenger.impl;
-
-import org.apache.qpid.proton.ProtonFactoryImpl;
-import org.apache.qpid.proton.messenger.Messenger;
-import org.apache.qpid.proton.messenger.MessengerFactory;
-
-public class MessengerFactoryImpl extends ProtonFactoryImpl implements MessengerFactory
-{
-    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
-    @Override
-    public Messenger createMessenger()
-    {
-        return new MessengerImpl();
-    }
-
-    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
-    @Override
-    public Messenger createMessenger(String name)
-    {
-        return new MessengerImpl(name);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
index 29bb9ca..e6475b9 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
@@ -29,17 +29,14 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import org.apache.qpid.proton.Proton;
-import org.apache.qpid.proton.ProtonFactoryLoader;
 import org.apache.qpid.proton.InterruptException;
 import org.apache.qpid.proton.TimeoutException;
 import org.apache.qpid.proton.driver.Connector;
 import org.apache.qpid.proton.driver.Driver;
-import org.apache.qpid.proton.driver.DriverFactory;
 import org.apache.qpid.proton.driver.Listener;
 import org.apache.qpid.proton.engine.Connection;
 import org.apache.qpid.proton.engine.Delivery;
 import org.apache.qpid.proton.engine.EndpointState;
-import org.apache.qpid.proton.engine.EngineFactory;
 import org.apache.qpid.proton.engine.Link;
 import org.apache.qpid.proton.engine.Receiver;
 import org.apache.qpid.proton.engine.Sasl;
@@ -49,10 +46,8 @@ import org.apache.qpid.proton.engine.SslDomain;
 import org.apache.qpid.proton.engine.Ssl;
 import org.apache.qpid.proton.engine.Transport;
 import org.apache.qpid.proton.message.Message;
-import org.apache.qpid.proton.message.MessageFactory;
 import org.apache.qpid.proton.messenger.Messenger;
 import org.apache.qpid.proton.messenger.MessengerException;
-import org.apache.qpid.proton.messenger.MessengerFactory;
 import org.apache.qpid.proton.messenger.Status;
 import org.apache.qpid.proton.messenger.Tracker;
 import org.apache.qpid.proton.amqp.messaging.Source;
@@ -1449,14 +1444,16 @@ public class MessengerImpl implements Messenger
         {
             _receivers++;
             _blocked.add((Receiver)link);
+            link.setContext(Boolean.TRUE);
         }
     }
 
     // a link is being removed, account for it.
     private void linkRemoved(Link _link)
     {
-        if (_link instanceof Receiver)
+        if (_link instanceof Receiver && (Boolean) _link.getContext())
         {
+            _link.setContext(Boolean.FALSE);
             Receiver link = (Receiver)_link;
             assert _receivers > 0;
             _receivers--;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/resources/cengine.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/cengine.py b/proton-j/src/main/resources/cengine.py
index 320f539..c47ab58 100644
--- a/proton-j/src/main/resources/cengine.py
+++ b/proton-j/src/main/resources/cengine.py
@@ -25,7 +25,7 @@ from org.apache.qpid.proton.amqp.transaction import Coordinator
 from org.apache.qpid.proton.amqp.transport import ErrorCondition, \
   SenderSettleMode, ReceiverSettleMode
 from org.apache.qpid.proton.engine import EndpointState, Sender, \
-  Receiver, TransportException
+  Receiver, Transport, TransportException
 
 from java.util import EnumSet
 from jarray import array, zeros
@@ -57,10 +57,10 @@ PN_NONDURABLE = 0
 PN_CONFIGURATION = 1
 PN_DELIVERIES = 2
 
-PN_LINK_CLOSE = 0
-PN_SESSION_CLOSE = 1
-PN_CONNECTION_CLOSE = 2
-PN_NEVER = 3
+PN_EXPIRE_WITH_LINK = 0
+PN_EXPIRE_WITH_SESSION = 1
+PN_EXPIRE_WITH_CONNECTION = 2
+PN_EXPIRE_NEVER = 3
 
 PN_DIST_MODE_UNSPECIFIED = 0
 PN_DIST_MODE_COPY = 1
@@ -72,10 +72,10 @@ PN_REJECTED = (0x0000000000000025)
 PN_RELEASED = (0x0000000000000026)
 PN_MODIFIED = (0x0000000000000027)
 
-PN_TRACE_OFF = (0)
-PN_TRACE_RAW = (1)
-PN_TRACE_FRM = (2)
-PN_TRACE_DRV = (4)
+PN_TRACE_OFF = Transport.TRACE_OFF
+PN_TRACE_RAW = Transport.TRACE_RAW
+PN_TRACE_FRM = Transport.TRACE_FRM
+PN_TRACE_DRV = Transport.TRACE_DRV
 
 def wrap(obj, wrapper):
   if obj:
@@ -98,7 +98,11 @@ class pn_condition:
       self.description = None
       self.info.clear()
     else:
-      self.name = impl.getCondition().toString()
+      cond = impl.getCondition()
+      if cond is None:
+        self.name = None
+      else:
+        self.name = cond.toString()
       self.description = impl.getDescription()
       obj2dat(impl.getInfo(), self.info)
 
@@ -222,6 +226,9 @@ def pn_connection_set_container(conn, name):
 def pn_connection_remote_container(conn):
   return conn.impl.getRemoteContainer()
 
+def pn_connection_get_hostname(conn):
+  return conn.impl.getHostname()
+
 def pn_connection_set_hostname(conn, name):
   conn.impl.setHostname(name)
 
@@ -244,6 +251,9 @@ def pn_connection_close(conn):
   conn.on_close()
   conn.impl.close()
 
+def pn_connection_free(conn):
+  conn.impl.free()
+
 class pn_session_wrapper(endpoint_wrapper):
   pass
 
@@ -325,7 +335,7 @@ def pn_receiver(ssn, name):
   return wrap(ssn.impl.receiver(name), pn_link_wrapper)
 
 def pn_session_free(ssn):
-  ssn.impl = None
+  ssn.impl.free()
 
 TERMINUS_TYPES_J2P = {
   Source: PN_SOURCE,
@@ -354,17 +364,17 @@ DURABILITY_J2P = {
 }
 
 EXPIRY_POLICY_P2J = {
-  PN_LINK_CLOSE: TerminusExpiryPolicy.LINK_DETACH,
-  PN_SESSION_CLOSE: TerminusExpiryPolicy.SESSION_END,
-  PN_CONNECTION_CLOSE: TerminusExpiryPolicy.CONNECTION_CLOSE,
-  PN_NEVER: TerminusExpiryPolicy.NEVER
+  PN_EXPIRE_WITH_LINK: TerminusExpiryPolicy.LINK_DETACH,
+  PN_EXPIRE_WITH_SESSION: TerminusExpiryPolicy.SESSION_END,
+  PN_EXPIRE_WITH_CONNECTION: TerminusExpiryPolicy.CONNECTION_CLOSE,
+  PN_EXPIRE_NEVER: TerminusExpiryPolicy.NEVER
 }
 
 EXPIRY_POLICY_J2P = {
-  TerminusExpiryPolicy.LINK_DETACH: PN_LINK_CLOSE,
-  TerminusExpiryPolicy.SESSION_END: PN_SESSION_CLOSE,
-  TerminusExpiryPolicy.CONNECTION_CLOSE: PN_CONNECTION_CLOSE,
-  TerminusExpiryPolicy.NEVER: PN_NEVER
+  TerminusExpiryPolicy.LINK_DETACH: PN_EXPIRE_WITH_LINK,
+  TerminusExpiryPolicy.SESSION_END: PN_EXPIRE_WITH_SESSION,
+  TerminusExpiryPolicy.CONNECTION_CLOSE: PN_EXPIRE_WITH_CONNECTION,
+  TerminusExpiryPolicy.NEVER: PN_EXPIRE_NEVER
 }
 
 DISTRIBUTION_MODE_P2J = {
@@ -385,7 +395,7 @@ class pn_terminus:
     self.type = type
     self.address = None
     self.durability = PN_NONDURABLE
-    self.expiry_policy = PN_SESSION_CLOSE
+    self.expiry_policy = PN_EXPIRE_WITH_SESSION
     self.distribution_mode = PN_DIST_MODE_UNSPECIFIED
     self.timeout = 0
     self.dynamic = False
@@ -587,6 +597,9 @@ def pn_link_remote_rcv_settle_mode(link):
 def pn_link_is_sender(link):
   return isinstance(link.impl, Sender)
 
+def pn_link_is_receiver(link):
+  return isinstance(link.impl, Receiver)
+
 def pn_link_head(conn, mask):
   local, remote = mask2set(mask)
   return wrap(conn.impl.linkHead(local, remote), pn_link_wrapper)
@@ -652,7 +665,7 @@ def pn_link_current(link):
   return wrap(link.impl.current(), pn_delivery_wrapper)
 
 def pn_link_free(link):
-  link.impl = None
+  link.impl.free()
 
 def pn_work_head(conn):
   return wrap(conn.impl.getWorkHead(), pn_delivery_wrapper)
@@ -802,6 +815,9 @@ def pn_delivery_get_context(dlv):
 def pn_delivery_set_context(dlv, ctx):
   dlv.context = ctx
 
+def pn_delivery_partial(dlv):
+  return dlv.impl.isPartial()
+
 def pn_delivery_pending(dlv):
   return dlv.impl.pending()
 
@@ -847,7 +863,6 @@ class pn_transport_wrapper:
 
   def __init__(self, impl):
     self.impl = impl
-    self.error = pn_error(0, None)
 
 def pn_transport():
   return wrap(Proton.transport(), pn_transport_wrapper)
@@ -877,15 +892,15 @@ def pn_transport_bind(trans, conn):
   trans.impl.bind(conn.impl)
   return 0
 
+def pn_transport_unbind(trans):
+  trans.impl.unbind()
+  return 0
+
 def pn_transport_trace(trans, n):
-  # XXX
-  pass
+  trans.impl.trace(n)
 
 def pn_transport_pending(trans):
-  try:
-    return trans.impl.pending()
-  except TransportException, e:
-    return trans.error.set(PN_ERR, str(e))
+  return trans.impl.pending()
 
 def pn_transport_peek(trans, size):
   size = min(trans.impl.pending(), size)
@@ -893,6 +908,7 @@ def pn_transport_peek(trans, size):
   if size:
     bb = trans.impl.head()
     bb.get(ba)
+    bb.position(0)
   return 0, ba.tostring()
 
 def pn_transport_pop(trans, size):
@@ -906,47 +922,51 @@ def pn_transport_push(trans, input):
   if cap < 0:
     return cap
   elif len(input) > cap:
-    return PN_OVERFLOW
-  else:
-    bb = trans.impl.tail()
-    bb.put(array(input, 'b'))
-    try:
-      trans.impl.process()
-      return 0
-    except TransportException, e:
-      trans.error = pn_error(PN_ERR, str(e))
-      return PN_ERR
+    input = input[:cap]
+
+  bb = trans.impl.tail()
+  bb.put(array(input, 'b'))
+  trans.impl.process()
+  return len(input)
 
 def pn_transport_close_head(trans):
-  try:
-    trans.impl.close_head()
-    return 0
-  except TransportException, e:
-    trans.error = pn_error(PN_ERR, str(e))
-    return PN_ERR
+  trans.impl.close_head()
+  return 0
 
 def pn_transport_close_tail(trans):
-  try:
-    trans.impl.close_tail()
-    return 0
-  except TransportException, e:
-    trans.error = pn_error(PN_ERR, str(e))
-    return PN_ERR
+  trans.impl.close_tail()
+  return 0
 
-def pn_transport_error(trans):
-  return trans.error
+def pn_transport_closed(trans):
+  return trans.impl.isClosed()
 
 from org.apache.qpid.proton.engine import Event
 
-PN_EVENT_CATEGORY_PROTOCOL = Event.Category.PROTOCOL
-
-PN_CONNECTION_LOCAL_STATE = Event.Type.CONNECTION_LOCAL_STATE
-PN_CONNECTION_REMOTE_STATE = Event.Type.CONNECTION_REMOTE_STATE
-PN_SESSION_LOCAL_STATE = Event.Type.SESSION_LOCAL_STATE
-PN_SESSION_REMOTE_STATE = Event.Type.SESSION_REMOTE_STATE
-PN_LINK_LOCAL_STATE = Event.Type.LINK_LOCAL_STATE
-PN_LINK_REMOTE_STATE = Event.Type.LINK_REMOTE_STATE
+PN_EVENT_CATEGORY_CONNECTION = Event.Category.CONNECTION
+PN_EVENT_CATEGORY_SESSION = Event.Category.SESSION
+PN_EVENT_CATEGORY_LINK = Event.Category.LINK
+PN_EVENT_CATEGORY_DELIVERY = Event.Category.DELIVERY
+PN_EVENT_CATEGORY_TRANSPORT = Event.Category.TRANSPORT
+
+PN_CONNECTION_INIT = Event.Type.CONNECTION_INIT
+PN_CONNECTION_OPEN = Event.Type.CONNECTION_OPEN
+PN_CONNECTION_REMOTE_OPEN = Event.Type.CONNECTION_REMOTE_OPEN
+PN_CONNECTION_CLOSE = Event.Type.CONNECTION_CLOSE
+PN_CONNECTION_REMOTE_CLOSE = Event.Type.CONNECTION_REMOTE_CLOSE
+PN_CONNECTION_FINAL = Event.Type.CONNECTION_FINAL
+PN_SESSION_INIT = Event.Type.SESSION_INIT
+PN_SESSION_OPEN = Event.Type.SESSION_OPEN
+PN_SESSION_REMOTE_OPEN = Event.Type.SESSION_REMOTE_OPEN
+PN_SESSION_CLOSE = Event.Type.SESSION_CLOSE
+PN_SESSION_REMOTE_CLOSE = Event.Type.SESSION_REMOTE_CLOSE
+PN_SESSION_FINAL = Event.Type.SESSION_FINAL
+PN_LINK_INIT = Event.Type.LINK_INIT
+PN_LINK_OPEN = Event.Type.LINK_OPEN
+PN_LINK_REMOTE_OPEN = Event.Type.LINK_REMOTE_OPEN
+PN_LINK_CLOSE = Event.Type.LINK_CLOSE
+PN_LINK_REMOTE_CLOSE = Event.Type.LINK_REMOTE_CLOSE
 PN_LINK_FLOW = Event.Type.LINK_FLOW
+PN_LINK_FINAL = Event.Type.LINK_FINAL
 PN_DELIVERY = Event.Type.DELIVERY
 PN_TRANSPORT = Event.Type.TRANSPORT
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/resources/csasl.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/csasl.py b/proton-j/src/main/resources/csasl.py
index 68c573d..a24246d 100644
--- a/proton-j/src/main/resources/csasl.py
+++ b/proton-j/src/main/resources/csasl.py
@@ -29,6 +29,7 @@ PN_SASL_AUTH=1
 PN_SASL_SYS=2
 PN_SASL_PERM=3
 PN_SASL_TEMP=4
+PN_SASL_SKIPPED=5
 
 PN_SASL_CONF = 0
 PN_SASL_IDLE = 1
@@ -53,7 +54,8 @@ SASL_OUTCOMES_P2J = {
   PN_SASL_AUTH: Sasl.PN_SASL_AUTH,
   PN_SASL_SYS: Sasl.PN_SASL_SYS,
   PN_SASL_PERM: Sasl.PN_SASL_PERM,
-  PN_SASL_TEMP: Sasl.PN_SASL_TEMP
+  PN_SASL_TEMP: Sasl.PN_SASL_TEMP,
+  PN_SASL_SKIPPED: Sasl.PN_SASL_SKIPPED
 }
 
 SASL_OUTCOMES_J2P = {
@@ -62,7 +64,8 @@ SASL_OUTCOMES_J2P = {
   Sasl.PN_SASL_AUTH: PN_SASL_AUTH,
   Sasl.PN_SASL_SYS: PN_SASL_SYS,
   Sasl.PN_SASL_PERM: PN_SASL_PERM,
-  Sasl.PN_SASL_TEMP: PN_SASL_TEMP
+  Sasl.PN_SASL_TEMP: PN_SASL_TEMP,
+  Sasl.PN_SASL_SKIPPED: PN_SASL_SKIPPED
 }
 
 def pn_sasl_state(sasl):
@@ -77,6 +80,9 @@ def pn_sasl_client(sasl):
 def pn_sasl_server(sasl):
   sasl.server()
 
+def pn_sasl_allow_skip(sasl, allow):
+  sasl.allowSkip(allow)
+
 def pn_sasl_done(sasl, outcome):
   sasl.done(SASL_OUTCOMES_P2J[outcome])
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/ProtonFactoryLoaderTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/ProtonFactoryLoaderTest.java b/proton-j/src/test/java/org/apache/qpid/proton/ProtonFactoryLoaderTest.java
deleted file mode 100644
index 16e7bbf..0000000
--- a/proton-j/src/test/java/org/apache/qpid/proton/ProtonFactoryLoaderTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton;
-
-import static org.apache.qpid.proton.ProtonFactory.ImplementationType.ANY;
-import static org.apache.qpid.proton.ProtonFactory.ImplementationType.PROTON_C;
-import static org.apache.qpid.proton.ProtonFactory.ImplementationType.PROTON_J;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import org.apache.qpid.proton.ProtonFactory.ImplementationType;
-import org.apache.qpid.proton.factoryloadertesting.DummyProtonFactory;
-import org.junit.Test;
-
-public class ProtonFactoryLoaderTest
-{
-    private String _previousImplementationType;
-
-    @Test
-    public void testLoadFactoryForAnyImplementationType()
-    {
-        ImplementationType implementationType = ANY;
-
-        ProtonFactoryLoader<DummyProtonFactory> factoryLoader =
-                new ProtonFactoryLoader<DummyProtonFactory>(DummyProtonFactory.class, implementationType);
-
-        assertNotNull(factoryLoader);
-    }
-
-    @Test
-    public void testLoadFactoryForProtonJ()
-    {
-        testImplementationType(PROTON_J);
-    }
-
-    @Test
-    public void testLoadFactoryForProtonC()
-    {
-        testImplementationType(PROTON_C);
-    }
-
-    private void testImplementationType(ImplementationType implementationType)
-    {
-        ProtonFactoryLoader<DummyProtonFactory> factoryLoader =
-                new ProtonFactoryLoader<DummyProtonFactory>(DummyProtonFactory.class, implementationType);
-
-        assertEquals(implementationType, factoryLoader.loadFactory().getImplementationType());
-    }
-
-    @Test
-    public void testLoadFactoryUsingProtonCImplementationTypeFromSystemProperty()
-    {
-        testLoadFactoryUsingImplementationTypeFromSystemProperty(PROTON_C.name());
-    }
-
-    @Test
-    public void testLoadFactoryUsingProtonJImplementationTypeFromSystemProperty()
-    {
-        testLoadFactoryUsingImplementationTypeFromSystemProperty(PROTON_J.name());
-    }
-
-    @Test
-    public void testLoadFactoryUsingDefaultImplementationType()
-    {
-        testLoadFactoryUsingImplementationTypeFromSystemProperty(null);
-    }
-
-    private void testLoadFactoryUsingImplementationTypeFromSystemProperty(String implementationTypeName)
-    {
-        try
-        {
-            setImplementationTypeSystemProperty(implementationTypeName);
-            ProtonFactoryLoader<DummyProtonFactory> factoryLoader = new ProtonFactoryLoader<DummyProtonFactory>(DummyProtonFactory.class);
-            DummyProtonFactory factory = factoryLoader.loadFactory();
-
-            assertNotNull(factory);
-
-            if(implementationTypeName != null)
-            {
-                assertEquals(
-                        ImplementationType.valueOf(implementationTypeName),
-                        factory.getImplementationType());
-            }
-        }
-        finally
-        {
-            resetImplementationTypeSystemProperty();
-        }
-    }
-
-    private void setImplementationTypeSystemProperty(String implementationTypeName)
-    {
-        _previousImplementationType = System.getProperty(ProtonFactoryLoader.IMPLEMENTATION_TYPE_PROPERTY);
-        setOrClearSystemProperty(implementationTypeName);
-    }
-
-    private void resetImplementationTypeSystemProperty()
-    {
-        setOrClearSystemProperty(_previousImplementationType);
-    }
-
-    private void setOrClearSystemProperty(String propertyValue)
-    {
-        if(propertyValue == null)
-        {
-            System.clearProperty(ProtonFactoryLoader.IMPLEMENTATION_TYPE_PROPERTY);
-        }
-        else
-        {
-            System.setProperty(ProtonFactoryLoader.IMPLEMENTATION_TYPE_PROPERTY, propertyValue);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/FrameParserTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/FrameParserTest.java b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/FrameParserTest.java
index 7ff5062..347184b 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/FrameParserTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/FrameParserTest.java
@@ -41,6 +41,7 @@ import org.apache.qpid.proton.amqp.transport.Open;
 import org.apache.qpid.proton.codec.AMQPDefinedTypes;
 import org.apache.qpid.proton.codec.DecoderImpl;
 import org.apache.qpid.proton.codec.EncoderImpl;
+import org.apache.qpid.proton.engine.Transport;
 import org.apache.qpid.proton.engine.TransportException;
 import org.apache.qpid.proton.engine.TransportResult;
 import org.apache.qpid.proton.engine.TransportResult.Status;
@@ -63,9 +64,6 @@ public class FrameParserTest
 
     private final AmqpFramer _amqpFramer = new AmqpFramer();
 
-    @Rule
-    public ExpectedException _expectedException = ExpectedException.none();
-
     @Before
     public void setUp()
     {
@@ -80,16 +78,8 @@ public class FrameParserTest
         String headerMismatchMessage = "AMQP header mismatch";
         ByteBuffer buffer = _frameParser.tail();
         buffer.put("hello".getBytes());
-        try {
-            _frameParser.process();
-            fail("expected exception");
-        } catch (TransportException e) {
-            assertThat(e.getMessage(), containsString(headerMismatchMessage));
-        }
-
-        _expectedException.expect(TransportException.class);
-        _expectedException.expectMessage(headerMismatchMessage);
-        _frameParser.tail();
+        _frameParser.process();
+        assertEquals(_frameParser.capacity(), Transport.END_OF_STREAM);
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportImplTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportImplTest.java b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportImplTest.java
index f0603f6..7dce8f8 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportImplTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportImplTest.java
@@ -207,4 +207,19 @@ public class TransportImplTest
         assertTrue("Expecting second buffer to have bytes", buf.remaining() > 0);
         assertTrue("Expecting second buffer to not be full", buf.remaining() < Transport.MIN_MAX_FRAME_SIZE);
     }
+
+    @Test
+    public void testAttemptToInitiateSaslAfterProcessingBeginsCausesIllegalStateException()
+    {
+        _transport.process();
+
+        try
+        {
+            _transport.sasl();
+        }
+        catch(IllegalStateException ise)
+        {
+            //expected, sasl must be initiated before processing begins
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptorTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptorTest.java b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptorTest.java
index 2061eeb..19c2f7b 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptorTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportOutputAdaptorTest.java
@@ -25,6 +25,8 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import org.apache.qpid.proton.engine.TransportException;
+
 import java.nio.ByteBuffer;
 
 import org.junit.Test;
@@ -143,7 +145,7 @@ public class TransportOutputAdaptorTest
             _cannedOutput = cannedOutput;
         }
 
-        public void closed()
+        public void closed(TransportException error)
         {
             // do nothing
         }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java
index 59c5859..45e2273 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java
@@ -32,6 +32,7 @@ import java.nio.ByteBuffer;
 
 import javax.net.ssl.SSLException;
 
+import org.apache.qpid.proton.engine.Transport;
 import org.apache.qpid.proton.engine.TransportException;
 import org.junit.Before;
 import org.junit.Rule;
@@ -132,16 +133,8 @@ public class SimpleSslTransportWrapperTest
         _dummySslEngine.rejectNextEncodedPacket(sslException);
 
         _sslWrapper.tail().put("<-A->".getBytes());
-        try {
-            _sslWrapper.process();
-            fail("no exception");
-        } catch (TransportException e) {
-            assertSame(sslException, e.getCause());
-            assertEquals("", _underlyingInput.getAcceptedInput());
-        }
-
-        _expectedException.expect(TransportException.class);
-        _sslWrapper.tail();
+        _sslWrapper.process();
+        assertEquals(_sslWrapper.capacity(), Transport.END_OF_STREAM);
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonCFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonCFactory.java b/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonCFactory.java
deleted file mode 100644
index bdd76b9..0000000
--- a/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonCFactory.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton.factoryloadertesting;
-
-
-public class DummyProtonCFactory implements DummyProtonFactory
-{
-    @Override
-    public ImplementationType getImplementationType()
-    {
-        return ImplementationType.PROTON_C;
-    }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonFactory.java b/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonFactory.java
deleted file mode 100644
index e80e403..0000000
--- a/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonFactory.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton.factoryloadertesting;
-
-import org.apache.qpid.proton.ProtonFactory;
-
-public interface DummyProtonFactory extends ProtonFactory
-{
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonJFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonJFactory.java b/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonJFactory.java
deleted file mode 100644
index aba12af..0000000
--- a/proton-j/src/test/java/org/apache/qpid/proton/factoryloadertesting/DummyProtonJFactory.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton.factoryloadertesting;
-
-
-public class DummyProtonJFactory implements DummyProtonFactory
-{
-    @Override
-    public ImplementationType getImplementationType()
-    {
-        return ImplementationType.PROTON_J;
-    }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java
index 0edf65c..9c5dbb3 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java
@@ -26,7 +26,6 @@ import static org.apache.qpid.proton.engine.EndpointState.ACTIVE;
 import static org.apache.qpid.proton.engine.EndpointState.CLOSED;
 import static org.apache.qpid.proton.engine.EndpointState.UNINITIALIZED;
 import static org.apache.qpid.proton.systemtests.TestLoggingHelper.bold;
-import static org.apache.qpid.proton.systemtests.engine.ProtonFactoryTestFixture.isProtonJ;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 
@@ -34,7 +33,7 @@ import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.logging.Logger;
 
-import org.apache.qpid.proton.ProtonFactoryLoader;
+import org.apache.qpid.proton.Proton;
 import org.apache.qpid.proton.amqp.messaging.Accepted;
 import org.apache.qpid.proton.amqp.messaging.AmqpValue;
 import org.apache.qpid.proton.amqp.messaging.Section;
@@ -45,10 +44,8 @@ import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
 import org.apache.qpid.proton.engine.Delivery;
 import org.apache.qpid.proton.engine.Endpoint;
 import org.apache.qpid.proton.engine.EndpointState;
-import org.apache.qpid.proton.engine.EngineFactory;
 import org.apache.qpid.proton.engine.Receiver;
 import org.apache.qpid.proton.message.Message;
-import org.apache.qpid.proton.message.MessageFactory;
 import org.junit.Test;
 
 /**
@@ -80,26 +77,23 @@ public class ProtonEngineExampleTest
 
     private final String _targetAddress = _server.containerId + "-link1-target";
 
-    private final EngineFactory _engineFactory = new ProtonFactoryLoader<EngineFactory>(EngineFactory.class).loadFactory();
-    private final MessageFactory _messageFactory = new ProtonFactoryLoader<MessageFactory>(MessageFactory.class).loadFactory();
-
     @Test
     public void test() throws Exception
     {
         LOGGER.fine(bold("======== About to create transports"));
 
-        _client.transport = _engineFactory.createTransport();
+        _client.transport = Proton.transport();
         ProtocolTracerEnabler.setProtocolTracer(_client.transport, TestLoggingHelper.CLIENT_PREFIX);
 
-        _server.transport = _engineFactory.createTransport();
+        _server.transport = Proton.transport();
         ProtocolTracerEnabler.setProtocolTracer(_server.transport, "            " + TestLoggingHelper.SERVER_PREFIX);
 
         doOutputInputCycle();
 
-        _client.connection = _engineFactory.createConnection();
+        _client.connection = Proton.connection();
         _client.transport.bind(_client.connection);
 
-        _server.connection = _engineFactory.createConnection();
+        _server.connection = Proton.connection();
         _server.transport.bind(_server.connection);
 
 
@@ -182,7 +176,7 @@ public class ProtonEngineExampleTest
 
         LOGGER.fine(bold("======== About to create a message and send it to the server"));
 
-        _client.message = _messageFactory.createMessage();
+        _client.message = Proton.message();
         Section messageBody = new AmqpValue("Hello");
         _client.message.setBody(messageBody);
         _client.messageData = new byte[BUFFER_SIZE];
@@ -195,12 +189,7 @@ public class ProtonEngineExampleTest
         assertEquals("For simplicity, assume the sender can accept all the data",
                      lengthOfEncodedMessage, numberOfBytesAcceptedBySender);
 
-        if (isProtonJ(_engineFactory))
-        {
-            // TODO PROTON-261: Proton-c ProtonJNI.pn_delivery_local_state is returning 0, which doesn't map to an
-            // value within the C enum.
-            assertNull(_client.delivery.getLocalState());
-        }
+        assertNull(_client.delivery.getLocalState());
 
         boolean senderAdvanced = _client.sender.advance();
         assertTrue("sender has not advanced", senderAdvanced);
@@ -213,11 +202,8 @@ public class ProtonEngineExampleTest
         _server.delivery = _server.connection.getWorkHead();
         assertEquals("The received delivery should be on our receiver",
                 _server.receiver, _server.delivery.getLink());
-        if (isProtonJ(_engineFactory))
-        {
-            assertNull(_server.delivery.getLocalState());
-            assertNull(_server.delivery.getRemoteState());
-        }
+        assertNull(_server.delivery.getLocalState());
+        assertNull(_server.delivery.getRemoteState());
 
         assertFalse(_server.delivery.isPartial());
         assertTrue(_server.delivery.isReadable());
@@ -226,7 +212,7 @@ public class ProtonEngineExampleTest
         int numberOfBytesProducedByReceiver = _server.receiver.recv(_server.messageData, 0, BUFFER_SIZE);
         assertEquals(numberOfBytesAcceptedBySender, numberOfBytesProducedByReceiver);
 
-        _server.message = _messageFactory.createMessage();
+        _server.message = Proton.message();
         _server.message.decode(_server.messageData, 0, numberOfBytesProducedByReceiver);
 
         boolean messageProcessed = applicationProcessMessage(_server.message);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonFactoryTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonFactoryTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonFactoryTest.java
deleted file mode 100644
index 9fd770f..0000000
--- a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonFactoryTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton.systemtests;
-
-import static org.junit.Assert.assertNotNull;
-
-import org.apache.qpid.proton.ProtonFactoryLoader;
-import org.apache.qpid.proton.engine.EngineFactory;
-import org.apache.qpid.proton.message.MessageFactory;
-import org.apache.qpid.proton.messenger.MessengerFactory;
-import org.junit.Test;
-
-public class ProtonFactoryTest
-{
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Test
-    public void testLoadFactoryWithExplicitClass()
-    {
-        ProtonFactoryLoader factoryLoader = new ProtonFactoryLoader();
-        MessageFactory messageFactory = (MessageFactory) factoryLoader.loadFactory(MessageFactory.class);
-        assertNotNull(messageFactory);
-    }
-
-    @Test
-    public void testMessageFactory()
-    {
-        ProtonFactoryLoader<MessageFactory> factoryLoader = new ProtonFactoryLoader<MessageFactory>(MessageFactory.class);
-        assertNotNull(factoryLoader.loadFactory());
-    }
-
-    @Test
-    public void testEngineFactory()
-    {
-        ProtonFactoryLoader<EngineFactory> factoryLoader = new ProtonFactoryLoader<EngineFactory>(EngineFactory.class);
-        assertNotNull(factoryLoader.loadFactory());
-    }
-
-    @Test
-    public void testMessengerFactory()
-    {
-        ProtonFactoryLoader<MessengerFactory> factoryLoader = new ProtonFactoryLoader<MessengerFactory>(MessengerFactory.class);
-        assertNotNull(factoryLoader.loadFactory());
-    }
-}


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


[21/51] [abbrv] qpid-proton git commit: Update with merge of latest proton codebase and checked against latest emscripten incoming branch

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/messenger/messenger.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/messenger.c b/proton-c/src/messenger/messenger.c
index 29b2eeb..0e2488b 100644
--- a/proton-c/src/messenger/messenger.c
+++ b/proton-c/src/messenger/messenger.c
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
+
 #include "../util.h"
 #include "../platform.h"
 #include "../platform_fmt.h"
@@ -60,30 +61,20 @@ typedef  enum {
 } pn_link_credit_mode_t;
 
 struct pn_messenger_t {
+  pn_address_t address;
   char *name;
   char *certificate;
   char *private_key;
   char *password;
   char *trusted_certificates;
-  int timeout;
-  bool blocking;
-  bool passive;
   pn_io_t *io;
   pn_list_t *pending; // pending selectables
   pn_selectable_t *interruptor;
-  bool interrupted;
   pn_socket_t ctrl[2];
   pn_list_t *listeners;
   pn_list_t *connections;
   pn_selector_t *selector;
   pn_collector_t *collector;
-  int send_threshold;
-  pn_link_credit_mode_t credit_mode;
-  int credit_batch;  // when LINK_CREDIT_AUTO
-  int credit;        // available
-  int distributed;   // credit
-  int receivers;     // # receiver links
-  int draining;      // # links in drain state
   pn_list_t *credited;
   pn_list_t *blocked;
   pn_timestamp_t next_drain;
@@ -95,13 +86,24 @@ struct pn_messenger_t {
   pn_error_t *error;
   pn_transform_t *routes;
   pn_transform_t *rewrites;
-  pn_address_t address;
   pn_tracker_t outgoing_tracker;
   pn_tracker_t incoming_tracker;
   pn_string_t *original;
   pn_string_t *rewritten;
-  bool worked;
+  pn_string_t *domain;
+  int timeout;
+  int send_threshold;
+  pn_link_credit_mode_t credit_mode;
+  int credit_batch;  // when LINK_CREDIT_AUTO
+  int credit;        // available
+  int distributed;   // credit
+  int receivers;     // # receiver links
+  int draining;      // # links in drain state
   int connection_error;
+  bool blocking;
+  bool passive;
+  bool interrupted;
+  bool worked;
 };
 
 #define CTX_HEAD                                \
@@ -611,7 +613,7 @@ pn_messenger_t *pn_messenger(const char *name)
     pni_selectable_set_context(m->interruptor, m);
     m->listeners = pn_list(0, 0);
     m->connections = pn_list(0, 0);
-    m->selector = pn_selector();
+    m->selector = pn_io_selector(m->io);
     m->collector = pn_collector();
     m->credit_mode = LINK_CREDIT_EXPLICIT;
     m->credit_batch = 1024;
@@ -635,6 +637,7 @@ pn_messenger_t *pn_messenger(const char *name)
     m->address.text = pn_string(NULL);
     m->original = pn_string(NULL);
     m->rewritten = pn_string(NULL);
+    m->domain = pn_string(NULL);
     m->connection_error = 0;
   }
 
@@ -775,6 +778,7 @@ static void pni_reclaim(pn_messenger_t *messenger)
 void pn_messenger_free(pn_messenger_t *messenger)
 {
   if (messenger) {
+    pn_free(messenger->domain);
     pn_free(messenger->rewritten);
     pn_free(messenger->original);
     pn_free(messenger->address.text);
@@ -971,7 +975,7 @@ int pni_pump_in(pn_messenger_t *messenger, const char *address, pn_link_t *recei
   size_t pending = pn_delivery_pending(d);
   int err = pn_buffer_ensure(buf, pending + 1);
   if (err) return pn_error_format(messenger->error, err, "get: error growing buffer");
-  char *encoded = pn_buffer_bytes(buf).start;
+  char *encoded = pn_buffer_memory(buf).start;
   ssize_t n = pn_link_recv(receiver, encoded, pending);
   if (n != (ssize_t) pending) {
     return pn_error_format(messenger->error, n,
@@ -1221,16 +1225,31 @@ int pn_messenger_process_events(pn_messenger_t *messenger)
   while ((event = pn_collector_peek(messenger->collector))) {
     processed++;
     switch (pn_event_type(event)) {
-    case PN_CONNECTION_REMOTE_STATE:
-    case PN_CONNECTION_LOCAL_STATE:
+    case PN_CONNECTION_INIT:
+      //printf("connection created: %p\n", (void *) pn_event_connection(event));
+      break;
+    case PN_SESSION_INIT:
+      //printf("session created: %p\n", (void *) pn_event_session(event));
+      break;
+    case PN_LINK_INIT:
+      //printf("link created: %p\n", (void *) pn_event_link(event));
+      break;
+    case PN_CONNECTION_REMOTE_OPEN:
+    case PN_CONNECTION_REMOTE_CLOSE:
+    case PN_CONNECTION_OPEN:
+    case PN_CONNECTION_CLOSE:
       pn_messenger_process_connection(messenger, event);
       break;
-    case PN_SESSION_REMOTE_STATE:
-    case PN_SESSION_LOCAL_STATE:
+    case PN_SESSION_REMOTE_OPEN:
+    case PN_SESSION_REMOTE_CLOSE:
+    case PN_SESSION_OPEN:
+    case PN_SESSION_CLOSE:
       pn_messenger_process_session(messenger, event);
       break;
-    case PN_LINK_REMOTE_STATE:
-    case PN_LINK_LOCAL_STATE:
+    case PN_LINK_REMOTE_OPEN:
+    case PN_LINK_REMOTE_CLOSE:
+    case PN_LINK_OPEN:
+    case PN_LINK_CLOSE:
       pn_messenger_process_link(messenger, event);
       break;
     case PN_LINK_FLOW:
@@ -1244,6 +1263,12 @@ int pn_messenger_process_events(pn_messenger_t *messenger)
       break;
     case PN_EVENT_NONE:
       break;
+    case PN_CONNECTION_FINAL:
+      break;
+    case PN_SESSION_FINAL:
+      break;
+    case PN_LINK_FINAL:
+      break;
     }
     pn_collector_pop(messenger->collector);
   }
@@ -1251,8 +1276,37 @@ int pn_messenger_process_events(pn_messenger_t *messenger)
   return processed;
 }
 
+/**
+ * Function to invoke AMQP related timer events, such as a heartbeat to prevent
+ * remote_idle timeout events
+ */
+static void pni_messenger_tick(pn_messenger_t *messenger)
+{
+  for (size_t i = 0; i < pn_list_size(messenger->connections); i++) {
+    pn_connection_t *connection =
+        (pn_connection_t *)pn_list_get(messenger->connections, i);
+    pn_transport_t *transport = pn_connection_transport(connection);
+    if (transport) {
+      pn_transport_tick(transport, pn_i_now());
+
+      // if there is pending data, such as an empty heartbeat frame, call
+      // process events. This should kick off the chain of selectables for
+      // reading/writing.
+      ssize_t pending = pn_transport_pending(transport);
+      if (pending > 0) {
+        pn_connection_ctx_t *cctx =
+            (pn_connection_ctx_t *)pn_connection_get_context(connection);
+        pn_messenger_process_events(messenger);
+        pn_messenger_flow(messenger);
+        pni_conn_modified(pni_context(cctx->selectable));
+      }
+    }
+  }
+}
+
 int pn_messenger_process(pn_messenger_t *messenger)
 {
+  bool doMessengerTick = true;
   pn_selectable_t *sel;
   int events;
   while ((sel = pn_selector_next(messenger->selector, &events))) {
@@ -1261,12 +1315,17 @@ int pn_messenger_process(pn_messenger_t *messenger)
     }
     if (events & PN_WRITABLE) {
       pn_selectable_writable(sel);
+      doMessengerTick = false;
     }
     if (events & PN_EXPIRED) {
       pn_selectable_expired(sel);
     }
   }
-
+  // ensure timer events are processed. Cannot call this inside the while loop
+  // as the timer events are not seen by the selector
+  if (doMessengerTick) {
+    pni_messenger_tick(messenger);
+  }
   if (messenger->interrupted) {
     messenger->interrupted = false;
     return PN_INTR;
@@ -1429,12 +1488,7 @@ pn_connection_t *pn_messenger_resolve(pn_messenger_t *messenger, const char *add
 {
   assert(messenger);
   messenger->connection_error = 0;
-  char domain[1024];
-  if (address && sizeof(domain) < strlen(address) + 1) {
-    pn_error_format(messenger->error, PN_ERR,
-                    "address exceeded maximum length: %s", address);
-    return NULL;
-  }
+  pn_string_t *domain = messenger->domain;
 
   int err = pni_route(messenger, address);
   if (err) return NULL;
@@ -1459,16 +1513,14 @@ pn_connection_t *pn_messenger_resolve(pn_messenger_t *messenger, const char *add
     return NULL;
   }
 
-  domain[0] = '\0';
+  pn_string_set(domain, "");
 
   if (user) {
-    strcat(domain, user);
-    strcat(domain, "@");
+    pn_string_addf(domain, "%s@", user);
   }
-  strcat(domain, host);
+  pn_string_addf(domain, "%s", host);
   if (port) {
-    strcat(domain, ":");
-    strcat(domain, port);
+    pn_string_addf(domain, ":%s", port);
   }
 
   for (size_t i = 0; i < pn_list_size(messenger->connections); i++) {
@@ -1480,7 +1532,7 @@ pn_connection_t *pn_messenger_resolve(pn_messenger_t *messenger, const char *add
       return connection;
     }
     const char *container = pn_connection_remote_container(connection);
-    if (pn_streq(container, domain)) {
+    if (pn_streq(container, pn_string_get(domain))) {
       return connection;
     }
   }
@@ -1529,7 +1581,16 @@ pn_link_t *pn_messenger_link(pn_messenger_t *messenger, const char *address, boo
 
   pn_session_t *ssn = pn_session(connection);
   pn_session_open(ssn);
-  link = sender ? pn_sender(ssn, "sender-xxx") : pn_receiver(ssn, "receiver-xxx");
+  if (sender) {
+    link = pn_sender(ssn, "sender-xxx");
+  } else {
+    if (name) {
+      link = pn_receiver(ssn, name);
+    } else {
+      link = pn_receiver(ssn, "");
+    }
+  }
+
   if ((sender && pn_messenger_get_outgoing_window(messenger)) ||
       (!sender && pn_messenger_get_incoming_window(messenger))) {
     // use explicit settlement via dispositions (not pre-settled)
@@ -1662,7 +1723,7 @@ int pni_pump_out(pn_messenger_t *messenger, const char *address, pn_link_t *send
 
   pn_buffer_t *buf = pni_entry_bytes(entry);
   pn_bytes_t bytes = pn_buffer_bytes(buf);
-  char *encoded = bytes.start;
+  const char *encoded = bytes.start;
   size_t size = bytes.size;
 
   // XXX: proper tag
@@ -1742,7 +1803,7 @@ int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg)
 
   pni_rewrite(messenger, msg);
   while (true) {
-    char *encoded = pn_buffer_bytes(buf).start;
+    char *encoded = pn_buffer_memory(buf).start;
     size_t size = pn_buffer_capacity(buf);
     int err = pn_message_encode(msg, encoded, &size);
     if (err == PN_OVERFLOW) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/messenger/store.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/store.c b/proton-c/src/messenger/store.c
index e36c5bb..88d6a5d 100644
--- a/proton-c/src/messenger/store.c
+++ b/proton-c/src/messenger/store.c
@@ -34,36 +34,36 @@
 typedef struct pni_stream_t pni_stream_t;
 
 struct pni_store_t {
-  size_t size;
   pni_stream_t *streams;
   pni_entry_t *store_head;
   pni_entry_t *store_tail;
+  pn_hash_t *tracked;
+  size_t size;
   int window;
   pn_sequence_t lwm;
   pn_sequence_t hwm;
-  pn_hash_t *tracked;
 };
 
 struct pni_stream_t {
   pni_store_t *store;
-  char address[1024]; // XXX
+  pn_string_t *address;
   pni_entry_t *stream_head;
   pni_entry_t *stream_tail;
   pni_stream_t *next;
 };
 
 struct pni_entry_t {
-  pn_sequence_t id;
   pni_stream_t *stream;
-  bool free;
   pni_entry_t *stream_next;
   pni_entry_t *stream_prev;
   pni_entry_t *store_next;
   pni_entry_t *store_prev;
-  pn_status_t status;
   pn_buffer_t *bytes;
   pn_delivery_t *delivery;
   void *context;
+  pn_status_t status;
+  pn_sequence_t id;
+  bool free;
 };
 
 void pni_entry_finalize(void *object)
@@ -104,13 +104,11 @@ pni_stream_t *pni_stream(pni_store_t *store, const char *address, bool create)
 {
   assert(store);
   assert(address);
-  // XXX
-  if (strlen(address) >= 1024) return NULL;
 
   pni_stream_t *prev = NULL;
   pni_stream_t *stream = store->streams;
   while (stream) {
-    if (!strcmp(stream->address, address)) {
+    if (!strcmp(pn_string_get(stream->address), address)) {
       return stream;
     }
     prev = stream;
@@ -120,7 +118,7 @@ pni_stream_t *pni_stream(pni_store_t *store, const char *address, bool create)
   if (create) {
     stream = (pni_stream_t *) malloc(sizeof(pni_stream_t));
     stream->store = store;
-    strcpy(stream->address, address);
+    stream->address = pn_string(address);
     stream->stream_head = NULL;
     stream->stream_tail = NULL;
     stream->next = NULL;
@@ -169,6 +167,8 @@ void pni_stream_free(pni_stream_t *stream)
   while ((entry = LL_HEAD(stream, stream))) {
     pni_entry_free(entry);
   }
+  pn_free(stream->address);
+  stream->address = NULL;
   free(stream);
 }
 
@@ -205,7 +205,7 @@ pni_stream_t *pni_stream_get(pni_store_t *store, const char *address)
 pni_entry_t *pni_store_put(pni_store_t *store, const char *address)
 {
   assert(store);
-  static pn_class_t clazz = PN_CLASS(pni_entry);
+  static const pn_class_t clazz = PN_CLASS(pni_entry);
 
   if (!address) address = "";
   pni_stream_t *stream = pni_stream_put(store, address);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/messenger/subscription.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/subscription.c b/proton-c/src/messenger/subscription.c
index 95f3f09..346a23f 100644
--- a/proton-c/src/messenger/subscription.c
+++ b/proton-c/src/messenger/subscription.c
@@ -64,7 +64,7 @@ pn_subscription_t *pn_subscription(pn_messenger_t *messenger,
                                    const char *host,
                                    const char *port)
 {
-  static pn_class_t clazz = PN_CLASS(pn_subscription);
+  static const pn_class_t clazz = PN_CLASS(pn_subscription);
   pn_subscription_t *sub = (pn_subscription_t *) pn_new(sizeof(pn_subscription_t), &clazz);
   sub->messenger = messenger;
   pn_string_set(sub->scheme, scheme);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/messenger/transform.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/transform.c b/proton-c/src/messenger/transform.c
index c9d2c14..801eb10 100644
--- a/proton-c/src/messenger/transform.c
+++ b/proton-c/src/messenger/transform.c
@@ -62,7 +62,7 @@ static void pn_rule_finalize(void *object)
 
 pn_rule_t *pn_rule(const char *pattern, const char *substitution)
 {
-  static pn_class_t clazz = PN_CLASS(pn_rule);
+  static const pn_class_t clazz = PN_CLASS(pn_rule);
   pn_rule_t *rule = (pn_rule_t *) pn_new(sizeof(pn_rule_t), &clazz);
   rule->pattern = pn_string(pattern);
   rule->substitution = pn_string(substitution);
@@ -82,7 +82,7 @@ static void pn_transform_finalize(void *object)
 
 pn_transform_t *pn_transform()
 {
-  static pn_class_t clazz = PN_CLASS(pn_transform);
+  static const pn_class_t clazz = PN_CLASS(pn_transform);
   pn_transform_t *transform = (pn_transform_t *) pn_new(sizeof(pn_transform_t), &clazz);
   transform->rules = pn_list(0, PN_REFCOUNT);
   transform->matched = false;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/object/object.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/object.c b/proton-c/src/object/object.c
index dd5fd17..d1b0e43 100644
--- a/proton-c/src/object/object.c
+++ b/proton-c/src/object/object.c
@@ -29,14 +29,19 @@
 #include <ctype.h>
 
 typedef struct {
-  pn_class_t *clazz;
+  const pn_class_t *clazz;
   int refcount;
 } pni_head_t;
 
 #define pni_head(PTR) \
   (((pni_head_t *) (PTR)) - 1)
 
-void *pn_new(size_t size, pn_class_t *clazz)
+void *pn_new(size_t size, const pn_class_t *clazz)
+{
+  return pn_new2(size, clazz, NULL);
+}
+
+void *pn_new2(size_t size, const pn_class_t *clazz, void *from)
 {
   pni_head_t *head = (pni_head_t *) malloc(sizeof(pni_head_t) + size);
   void *object = head + 1;
@@ -44,7 +49,7 @@ void *pn_new(size_t size, pn_class_t *clazz)
   return object;
 }
 
-void pn_initialize(void *object, pn_class_t *clazz)
+void pn_initialize(void *object, const pn_class_t *clazz)
 {
   pni_head_t *head = pni_head(object);
   head->clazz = clazz;
@@ -54,15 +59,22 @@ void pn_initialize(void *object, pn_class_t *clazz)
   }
 }
 
-void *pn_incref(void *object)
-{
+void *pn_incref(void *object) {
+  return pn_incref2(object, NULL);
+}
+
+void *pn_incref2(void *object, void *from) {
   if (object) {
     pni_head(object)->refcount++;
   }
   return object;
 }
 
-void pn_decref(void *object)
+void pn_decref(void *object) {
+  pn_decref2(object, NULL);
+}
+
+void pn_decref2(void *object, void *from)
 {
   if (object) {
     pni_head_t *head = pni_head(object);
@@ -70,7 +82,11 @@ void pn_decref(void *object)
     head->refcount--;
     if (!head->refcount) {
       pn_finalize(object);
-      free(head);
+      // Check the refcount again in case finalize created a new
+      // reference.
+      if (!head->refcount) {
+        free(head);
+      }
     }
   }
 }
@@ -83,7 +99,6 @@ void pn_finalize(void *object)
     if (head->clazz && head->clazz->finalize) {
       head->clazz->finalize(object);
     }
-    head->refcount = 0;
   }
 }
 
@@ -101,7 +116,7 @@ void pn_free(void *object)
   }
 }
 
-pn_class_t *pn_class(void *object)
+const pn_class_t *pn_class(void *object)
 {
   assert(object);
   return pni_head(object)->clazz;
@@ -127,7 +142,7 @@ intptr_t pn_compare(void *a, void *b)
     pni_head_t *hb = pni_head(b);
 
     if (ha->clazz && hb->clazz && ha->clazz == hb->clazz) {
-      pn_class_t *clazz = ha->clazz;
+      const pn_class_t *clazz = ha->clazz;
       if (clazz->compare) {
         return clazz->compare(a, b);
       }
@@ -150,13 +165,20 @@ int pn_inspect(void *object, pn_string_t *dst)
 
   if (object) {
     pni_head_t *head = pni_head(object);
+    const char *name;
     if (head->clazz) {
-      pn_class_t *clazz = head->clazz;
+      const pn_class_t *clazz = head->clazz;
       if (clazz->inspect) {
         return clazz->inspect(object, dst);
+      } else if (clazz->name) {
+        name = clazz->name;
+      } else {
+        name = "object";
       }
+    } else {
+      name = "object";
     }
-    return pn_string_addf(dst, "object<%p>", object);
+    return pn_string_addf(dst, "%s<%p>", name, object);
   } else {
     return pn_string_addf(dst, "(null)");
   }
@@ -185,9 +207,9 @@ void pn_list_set(pn_list_t *list, int index, void *value)
 {
   assert(list); assert(list->size);
   void *old = list->elements[index % list->size];
-  if (list->options & PN_REFCOUNT) pn_decref(old);
+  if (list->options & PN_REFCOUNT) pn_decref2(old, list);
   list->elements[index % list->size] = value;
-  if (list->options & PN_REFCOUNT) pn_incref(value);
+  if (list->options & PN_REFCOUNT) pn_incref2(value, list);
 }
 
 void pn_list_ensure(pn_list_t *list, size_t capacity)
@@ -207,7 +229,7 @@ int pn_list_add(pn_list_t *list, void *value)
   assert(list);
   pn_list_ensure(list, list->size + 1);
   list->elements[list->size++] = value;
-  if (list->options & PN_REFCOUNT) pn_incref(value);
+  if (list->options & PN_REFCOUNT) pn_incref2(value, list);
   return 0;
 }
 
@@ -242,7 +264,7 @@ void pn_list_del(pn_list_t *list, int index, int n)
 
   if (list->options & PN_REFCOUNT) {
     for (int i = 0; i < n; i++) {
-      pn_decref(list->elements[index + i]);
+      pn_decref2(list->elements[index + i], list);
     }
   }
 
@@ -294,7 +316,7 @@ static void pn_list_finalize(void *object)
   assert(object);
   pn_list_t *list = (pn_list_t *) object;
   for (size_t i = 0; i < list->size; i++) {
-    if (list->options & PN_REFCOUNT) pn_decref(pn_list_get(list, i));
+    if (list->options & PN_REFCOUNT) pn_decref2(pn_list_get(list, i), list);
   }
   free(list->elements);
 }
@@ -354,7 +376,7 @@ static int pn_list_inspect(void *obj, pn_string_t *dst)
 
 pn_list_t *pn_list(size_t capacity, int options)
 {
-  static pn_class_t clazz = PN_CLASS(pn_list);
+  static const pn_class_t clazz = PN_CLASS(pn_list);
 
   pn_list_t *list = (pn_list_t *) pn_new(sizeof(pn_list_t), &clazz);
   list->capacity = capacity ? capacity : 16;
@@ -380,11 +402,12 @@ struct pn_map_t {
   size_t capacity;
   size_t addressable;
   size_t size;
-  float load_factor;
   uintptr_t (*hashcode)(void *key);
   bool (*equals)(void *a, void *b);
+  float load_factor;
   bool count_keys;
   bool count_values;
+  bool inspect_keys;
 };
 
 static void pn_map_finalize(void *object)
@@ -394,8 +417,8 @@ static void pn_map_finalize(void *object)
   if (map->count_keys || map->count_values) {
     for (size_t i = 0; i < map->capacity; i++) {
       if (map->entries[i].state != PNI_ENTRY_FREE) {
-        if (map->count_keys) pn_decref(map->entries[i].key);
-        if (map->count_values) pn_decref(map->entries[i].value);
+        if (map->count_keys) pn_decref2(map->entries[i].key, map);
+        if (map->count_values) pn_decref2(map->entries[i].value, map);
       }
     }
   }
@@ -447,7 +470,11 @@ static int pn_map_inspect(void *obj, pn_string_t *dst)
       err = pn_string_addf(dst, ", ");
       if (err) return err;
     }
-    err = pn_inspect(pn_map_key(map, entry), dst);
+    if (map->inspect_keys) {
+      err = pn_inspect(pn_map_key(map, entry), dst);
+    } else {
+      err = pn_string_addf(dst, "%p", pn_map_key(map, entry));
+    }
     if (err) return err;
     err = pn_string_addf(dst, ": ");
     if (err) return err;
@@ -463,7 +490,7 @@ static int pn_map_inspect(void *obj, pn_string_t *dst)
 
 pn_map_t *pn_map(size_t capacity, float load_factor, int options)
 {
-  static pn_class_t clazz = PN_CLASS(pn_map);
+  static const pn_class_t clazz = PN_CLASS(pn_map);
 
   pn_map_t *map = (pn_map_t *) pn_new(sizeof(pn_map_t), &clazz);
   map->capacity = capacity ? capacity : 16;
@@ -474,6 +501,7 @@ pn_map_t *pn_map(size_t capacity, float load_factor, int options)
   map->equals = pn_equals;
   map->count_keys = (options & PN_REFCOUNT) || (options & PN_REFCOUNT_KEY);
   map->count_values = (options & PN_REFCOUNT) || (options & PN_REFCOUNT_VALUE);
+  map->inspect_keys = true;
   pni_map_allocate(map);
   return map;
 }
@@ -492,7 +520,7 @@ static float pni_map_load(pn_map_t *map)
 static bool pni_map_ensure(pn_map_t *map, size_t capacity)
 {
   float load = pni_map_load(map);
-  if (capacity <= map->capacity && load < map->load_factor) {
+  if (capacity <= map->capacity && load <= map->load_factor) {
     return false;
   }
 
@@ -511,8 +539,8 @@ static bool pni_map_ensure(pn_map_t *map, size_t capacity)
       void *key = entries[i].key;
       void *value = entries[i].value;
       pn_map_put(map, key, value);
-      if (map->count_keys) pn_decref(key);
-      if (map->count_values) pn_decref(value);
+      if (map->count_keys) pn_decref2(key, map);
+      if (map->count_values) pn_decref2(value, map);
     }
   }
 
@@ -531,7 +559,7 @@ static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev,
     if (create) {
       entry->state = PNI_ENTRY_TAIL;
       entry->key = key;
-      if (map->count_keys) pn_incref(key);
+      if (map->count_keys) pn_incref2(key, map);
       map->size++;
       return entry;
     } else {
@@ -571,7 +599,7 @@ static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev,
     entry->state = PNI_ENTRY_LINK;
     map->entries[empty].state = PNI_ENTRY_TAIL;
     map->entries[empty].key = key;
-    if (map->count_keys) pn_incref(key);
+    if (map->count_keys) pn_incref2(key, map);
     if (pprev) *pprev = entry;
     map->size++;
     return &map->entries[empty];
@@ -584,9 +612,9 @@ int pn_map_put(pn_map_t *map, void *key, void *value)
 {
   assert(map);
   pni_entry_t *entry = pni_map_entry(map, key, NULL, true);
-  if (map->count_values) pn_decref(entry->value);
+  if (map->count_values) pn_decref2(entry->value, map);
   entry->value = value;
-  if (map->count_values) pn_incref(value);
+  if (map->count_values) pn_incref2(value, map);
   return 0;
 }
 
@@ -603,17 +631,24 @@ void pn_map_del(pn_map_t *map, void *key)
   pni_entry_t *prev = NULL;
   pni_entry_t *entry = pni_map_entry(map, key, &prev, false);
   if (entry) {
+    void *dref_key = (map->count_keys) ? entry->key : NULL;
+    void *dref_value = (map->count_values) ? entry->value : NULL;
     if (prev) {
       prev->next = entry->next;
       prev->state = entry->state;
+    } else if (entry->next) {
+      assert(entry->state == PNI_ENTRY_LINK);
+      pni_entry_t *next = &map->entries[entry->next];
+      *entry = *next;
+      entry = next;
     }
     entry->state = PNI_ENTRY_FREE;
     entry->next = 0;
-    if (map->count_keys) pn_decref(entry->key);
     entry->key = NULL;
-    if (map->count_values) pn_decref(entry->value);
     entry->value = NULL;
     map->size--;
+    if (dref_key) pn_decref2(dref_key, map);
+    if (dref_value) pn_decref2(dref_value, map);
   }
 }
 
@@ -676,6 +711,7 @@ pn_hash_t *pn_hash(size_t capacity, float load_factor, int options)
   hash->map.equals = pni_identity_equals;
   hash->map.count_keys = false;
   hash->map.count_values = options & PN_REFCOUNT;
+  hash->map.inspect_keys = false;
   return hash;
 }
 
@@ -796,7 +832,7 @@ pn_string_t *pn_string(const char *bytes)
 
 pn_string_t *pn_stringn(const char *bytes, size_t n)
 {
-  static pn_class_t clazz = PN_CLASS(pn_string);
+  static const pn_class_t clazz = PN_CLASS(pn_string);
   pn_string_t *string = (pn_string_t *) pn_new(sizeof(pn_string_t), &clazz);
   string->capacity = n ? n * sizeof(char) : 16;
   string->bytes = (char *) malloc(string->capacity);
@@ -985,7 +1021,7 @@ static void pn_iterator_finalize(void *object)
 
 pn_iterator_t *pn_iterator()
 {
-  static pn_class_t clazz = PN_CLASS(pn_iterator);
+  static const pn_class_t clazz = PN_CLASS(pn_iterator);
   pn_iterator_t *it = (pn_iterator_t *) pn_new(sizeof(pn_iterator_t), &clazz);
   return it;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/parser.c
----------------------------------------------------------------------
diff --git a/proton-c/src/parser.c b/proton-c/src/parser.c
index 6766607..fccba75 100644
--- a/proton-c/src/parser.c
+++ b/proton-c/src/parser.c
@@ -29,10 +29,10 @@
 
 struct pn_parser_t {
   pn_scanner_t *scanner;
-  int error_code;
   char *atoms;
   size_t size;
   size_t capacity;
+  int error_code;
 };
 
 pn_parser_t *pn_parser()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/platform.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform.h b/proton-c/src/platform.h
index 6b63e2e..b0475e0 100644
--- a/proton-c/src/platform.h
+++ b/proton-c/src/platform.h
@@ -85,8 +85,10 @@ int pn_i_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap);
 #endif
 
 #if defined _MSC_VER || defined _OPENVMS
+#if !defined(va_copy)
 #define va_copy(d,s) ((d) = (s))
 #endif
+#endif
 
 #ifdef __cplusplus
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/posix/driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/driver.c b/proton-c/src/posix/driver.c
index 0ce8f9f..b128cb2 100644
--- a/proton-c/src/posix/driver.c
+++ b/proton-c/src/posix/driver.c
@@ -64,19 +64,19 @@ struct pn_driver_t {
   struct pollfd *fds;
   size_t nfds;
   int ctrl[2]; //pipe for updating selectable status
-  pn_trace_t trace;
   pn_timestamp_t wakeup;
+  pn_trace_t trace;
 };
 
 struct pn_listener_t {
   pn_driver_t *driver;
   pn_listener_t *listener_next;
   pn_listener_t *listener_prev;
+  void *context;
   int idx;
-  bool pending;
   int fd;
+  bool pending;
   bool closed;
-  void *context;
 };
 
 #define PN_NAME_MAX (256)
@@ -86,22 +86,22 @@ struct pn_connector_t {
   pn_connector_t *connector_next;
   pn_connector_t *connector_prev;
   char name[PN_NAME_MAX];
+  pn_timestamp_t wakeup;
+  pn_connection_t *connection;
+  pn_transport_t *transport;
+  pn_sasl_t *sasl;
+  pn_listener_t *listener;
+  void *context;
   int idx;
-  bool pending_tick;
-  bool pending_read;
-  bool pending_write;
   int fd;
   int status;
   pn_trace_t trace;
+  bool pending_tick;
+  bool pending_read;
+  bool pending_write;
   bool closed;
-  pn_timestamp_t wakeup;
-  pn_connection_t *connection;
-  pn_transport_t *transport;
-  pn_sasl_t *sasl;
   bool input_done;
   bool output_done;
-  pn_listener_t *listener;
-  void *context;
 };
 
 /* Impls */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/posix/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/io.c b/proton-c/src/posix/io.c
index 11379ff..4fa223f 100644
--- a/proton-c/src/posix/io.c
+++ b/proton-c/src/posix/io.c
@@ -21,6 +21,7 @@
 
 #include <proton/io.h>
 #include <proton/object.h>
+#include <proton/selector.h>
 
 #include <ctype.h>
 #include <errno.h>
@@ -43,6 +44,7 @@ struct pn_io_t {
   char host[MAX_HOST];
   char serv[MAX_SERV];
   pn_error_t *error;
+  pn_selector_t *selector;
   bool wouldblock;
 };
 
@@ -51,6 +53,7 @@ void pn_io_initialize(void *obj)
   pn_io_t *io = (pn_io_t *) obj;
   io->error = pn_error();
   io->wouldblock = false;
+  io->selector = NULL;
 }
 
 void pn_io_finalize(void *obj)
@@ -65,7 +68,7 @@ void pn_io_finalize(void *obj)
 
 pn_io_t *pn_io(void)
 {
-  static pn_class_t clazz = PN_CLASS(pn_io);
+  static const pn_class_t clazz = PN_CLASS(pn_io);
   pn_io_t *io = (pn_io_t *) pn_new(sizeof(pn_io_t), &clazz);
   return io;
 }
@@ -275,3 +278,10 @@ bool pn_wouldblock(pn_io_t *io)
 {
   return io->wouldblock;
 }
+
+pn_selector_t *pn_io_selector(pn_io_t *io)
+{
+  if (io->selector == NULL)
+    io->selector = pni_selector();
+  return io->selector;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/posix/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/selector.c b/proton-c/src/posix/selector.c
index 1c42d99..14a97ee 100644
--- a/proton-c/src/posix/selector.c
+++ b/proton-c/src/posix/selector.c
@@ -65,9 +65,9 @@ void pn_selector_finalize(void *obj)
 #define pn_selector_compare NULL
 #define pn_selector_inspect NULL
 
-pn_selector_t *pn_selector(void)
+pn_selector_t *pni_selector(void)
 {
-  static pn_class_t clazz = PN_CLASS(pn_selector);
+  static const pn_class_t clazz = PN_CLASS(pn_selector);
   pn_selector_t *selector = (pn_selector_t *) pn_new(sizeof(pn_selector_t), &clazz);
   return selector;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/protocol.h.py
----------------------------------------------------------------------
diff --git a/proton-c/src/protocol.h.py b/proton-c/src/protocol.h.py
index 0ff7aa4..76a2391 100644
--- a/proton-c/src/protocol.h.py
+++ b/proton-c/src/protocol.h.py
@@ -24,6 +24,7 @@ print "/* generated */"
 print "#ifndef _PROTON_PROTOCOL_H"
 print "#define _PROTON_PROTOCOL_H 1"
 print
+print "#include \"proton/type_compat.h\""
 
 fields = {}
 
@@ -45,36 +46,99 @@ for type in TYPES:
   fields[code] = (type["@name"], [f["@name"] for f in type.query["field"]])
   idx += 1
 
-print
+print """
+#include <stddef.h>
+
+typedef struct {
+  const unsigned char name_index;
+  const unsigned char first_field_index;
+  const unsigned char field_count;
+} pn_fields_t;
 
-print """typedef struct {
-  const char *name;
-  const char *fields[32];
-} pn_fields_t;"""
+extern const pn_fields_t FIELDS[];
+extern const char * const FIELD_STRINGPOOL;
+extern const uint16_t FIELD_NAME[];
+extern const uint16_t FIELD_FIELDS[];
+extern const unsigned char FIELD_MIN;
+extern const unsigned char FIELD_MAX;
+"""
 
+print "#ifdef DEFINE_FIELDS"
+
+print 'struct FIELD_STRINGS {'
+print '  const char FIELD_STRINGS_NULL[sizeof("")];'
+strings = set()
+for name, fnames in fields.values():
+    strings.add(name)
+    strings.update(fnames)
+for str in strings:
+    istr = str.replace("-", "_");
+    print '  const char FIELD_STRINGS_%s[sizeof("%s")];' % (istr, str)
+print "};"
+print
+print 'const struct FIELD_STRINGS FIELD_STRINGS = {'
+print '  "",'
+for str in strings:
+    print '  "%s",'% str
+print "};"
+print 'const char * const FIELD_STRINGPOOL = (const char * const) &FIELD_STRINGS;'
 print
+print "/* This is an array of offsets into FIELD_STRINGPOOL */"
+print "const uint16_t FIELD_NAME[] = {"
+print "  offsetof(struct FIELD_STRINGS, FIELD_STRINGS_NULL),"
+index = 1
+for i in range(256):
+  if i in fields:
+    name, fnames = fields[i]
+    iname = name.replace("-", "_");
+    print '  offsetof(struct FIELD_STRINGS, FIELD_STRINGS_%s), /* %d */' % (iname, index)
+    index += 1
+print "};"
 
-print "#ifndef DEFINE_FIELDS"
-print "extern"
-print "#endif"
+print "/* This is an array of offsets into FIELD_STRINGPOOL */"
+print "const uint16_t FIELD_FIELDS[] = {"
+print "  offsetof(struct FIELD_STRINGS, FIELD_STRINGS_NULL),"
+index = 1
+for i in range(256):
+  if i in fields:
+    name, fnames = fields[i]
+    if fnames:
+      for f in fnames:
+        ifname = f.replace("-", "_");
+        print '  offsetof(struct FIELD_STRINGS, FIELD_STRINGS_%s), /* %d (%s) */' % (ifname, index, name)
+        index += 1
+print "};"
 
-print "pn_fields_t FIELDS[256]"
-print "#ifdef DEFINE_FIELDS"
-print " = {"
+print "const pn_fields_t FIELDS[] = {"
 
+name_count = 1
+field_count = 1
+field_min = 256
+field_max = 0
 for i in range(256):
   if i in fields:
+    if i>field_max: field_max = i
+    if i<field_min: field_min = i
+
+for i in range(field_min, field_max+1):
+  if i in fields:
     name, fnames = fields[i]
     if fnames:
-      print '  {"%s", {%s}},' % (name, ", ".join(['"%s"' % f for f in fnames]))
+      print '  {%d, %d, %d}, /* %d (%s) */' % (name_count, field_count, len(fnames), i, name)
+      field_count += len(fnames)
     else:
-      print '  {"%s", {NULL}},' % name
+      print '  {%d, 0, 0}, /* %d (%s) */' % (name_count, i, name)
+    name_count += 1
+    if i>field_max: field_max = i
+    if i<field_min: field_min = i
   else:
-    print '  {NULL, {NULL}},'
+    print '  {0, 0, 0}, /* %d */' % i
 
-print "}"
+print "};"
+print
+print 'const unsigned char FIELD_MIN = %d;' % field_min
+print 'const unsigned char FIELD_MAX = %d;' % field_max
+print
 print "#endif"
-print ";"
-
 print
 print "#endif /* protocol.h */"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/proton-dump.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proton-dump.c b/proton-c/src/proton-dump.c
index c7216c3..4e8a04f 100644
--- a/proton-c/src/proton-dump.c
+++ b/proton-c/src/proton-dump.c
@@ -19,6 +19,8 @@
  *
  */
 
+#include "pncompat/misc_funcs.inc"
+
 #include <stdio.h>
 #include <proton/buffer.h>
 #include <proton/codec.h>
@@ -98,8 +100,34 @@ int dump(const char *file)
   return 0;
 }
 
+void usage(char* prog) {
+  printf("Usage: %s [FILE1] [FILEn] ...\n", prog);
+  printf("Displays the content of an AMQP dump file containing frame data.\n");
+  printf("\n  [FILEn]  Dump file to be displayed.\n\n");
+}
+
 int main(int argc, char **argv)
 {
+  if(argc == 1) {
+    usage(argv[0]);
+    return 0;
+  }
+
+  int c;
+
+  while ( (c = getopt(argc, argv, "h")) != -1 ) {
+    switch(c) {
+    case 'h':
+      usage(argv[0]);
+      return 0;
+      break;
+
+    case '?':
+      usage(argv[0]);
+      return 1;
+    }
+  }
+
   for (int i = 1; i < argc; i++) {
     int err = dump(argv[i]);
     if (err) return err;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/proton.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proton.c b/proton-c/src/proton.c
index 9cd44ef..2b7d313 100644
--- a/proton-c/src/proton.c
+++ b/proton-c/src/proton.c
@@ -22,12 +22,12 @@
 #if defined(_WIN32) && ! defined(__CYGWIN__)
 #define NOGDI
 #include <winsock2.h>
-#include "pncompat/misc_funcs.inc"
 #else
 #include <unistd.h>
-#include <libgen.h>
 #endif
 
+#include "pncompat/misc_funcs.inc"
+
 #include <stdio.h>
 #include <string.h>
 #include <proton/driver.h>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 3f4f536..9c7ba1e 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -19,6 +19,7 @@
  *
  */
 
+#include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -27,29 +28,28 @@
 #include <proton/engine.h> // XXX: just needed for PN_EOS
 #include <proton/sasl.h>
 #include "protocol.h"
+#include "dispatch_actions.h"
 #include "../dispatcher/dispatcher.h"
 #include "../engine/engine-internal.h"
 #include "../util.h"
 
-#define SCRATCH (1024)
 
 struct pn_sasl_t {
   pn_transport_t *transport;
   pn_io_layer_t *io_layer;
-  size_t header_count;
   pn_dispatcher_t *disp;
-  bool client;
-  bool configured;
   char *mechanisms;
   char *remote_mechanisms;
   pn_buffer_t *send_data;
   pn_buffer_t *recv_data;
   pn_sasl_outcome_t outcome;
+  bool client;
+  bool configured;
+  bool allow_skip;
   bool sent_init;
   bool rcvd_init;
   bool sent_done;
   bool rcvd_done;
-  char scratch[SCRATCH];
 };
 
 static ssize_t pn_input_read_sasl_header(pn_io_layer_t *io_layer, const char *bytes, size_t available);
@@ -57,12 +57,6 @@ static ssize_t pn_input_read_sasl(pn_io_layer_t *io_layer, const char *bytes, si
 static ssize_t pn_output_write_sasl_header(pn_io_layer_t *io_layer, char *bytes, size_t available);
 static ssize_t pn_output_write_sasl(pn_io_layer_t *io_layer, char *bytes, size_t available);
 
-int pn_do_init(pn_dispatcher_t *disp);
-int pn_do_mechanisms(pn_dispatcher_t *disp);
-int pn_do_challenge(pn_dispatcher_t *disp);
-int pn_do_response(pn_dispatcher_t *disp);
-int pn_do_outcome(pn_dispatcher_t *disp);
-
 pn_sasl_t *pn_sasl(pn_transport_t *transport)
 {
   if (!transport->sasl) {
@@ -70,12 +64,6 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport)
     sasl->disp = pn_dispatcher(1, transport);
     sasl->disp->batch = false;
 
-    pn_dispatcher_action(sasl->disp, SASL_INIT, pn_do_init);
-    pn_dispatcher_action(sasl->disp, SASL_MECHANISMS, pn_do_mechanisms);
-    pn_dispatcher_action(sasl->disp, SASL_CHALLENGE, pn_do_challenge);
-    pn_dispatcher_action(sasl->disp, SASL_RESPONSE, pn_do_response);
-    pn_dispatcher_action(sasl->disp, SASL_OUTCOME, pn_do_outcome);
-
     sasl->client = false;
     sasl->configured = false;
     sasl->mechanisms = NULL;
@@ -83,6 +71,7 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport)
     sasl->send_data = pn_buffer(16);
     sasl->recv_data = pn_buffer(16);
     sasl->outcome = PN_SASL_NONE;
+    sasl->allow_skip = false;
     sasl->sent_init = false;
     sasl->rcvd_init = false;
     sasl->sent_done = false;
@@ -95,8 +84,6 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport)
     sasl->io_layer->process_input = pn_input_read_sasl_header;
     sasl->io_layer->process_output = pn_output_write_sasl_header;
     sasl->io_layer->process_tick = pn_io_layer_tick_passthru;
-
-    sasl->header_count = 0;
   }
 
   return transport->sasl;
@@ -185,6 +172,12 @@ void pn_sasl_server(pn_sasl_t *sasl)
   }
 }
 
+void pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow)
+{
+  if (sasl)
+    sasl->allow_skip = allow;
+}
+
 void pn_sasl_plain(pn_sasl_t *sasl, const char *username, const char *password)
 {
   if (!sasl) return;
@@ -238,7 +231,7 @@ void pn_sasl_free(pn_sasl_t *sasl)
 
 void pn_client_init(pn_sasl_t *sasl)
 {
-  pn_bytes_t bytes = pn_buffer_bytes(sasl->send_data);
+  pn_buffer_memory_t bytes = pn_buffer_memory(sasl->send_data);
   pn_post_frame(sasl->disp, 0, "DL[sz]", SASL_INIT, sasl->mechanisms,
                 bytes.size, bytes.start);
   pn_buffer_clear(sasl->send_data);
@@ -294,7 +287,7 @@ void pn_sasl_process(pn_sasl_t *sasl)
   }
 
   if (pn_buffer_size(sasl->send_data)) {
-    pn_bytes_t bytes = pn_buffer_bytes(sasl->send_data);
+    pn_buffer_memory_t bytes = pn_buffer_memory(sasl->send_data);
     pn_post_frame(sasl->disp, 0, "DL[z]", sasl->client ? SASL_RESPONSE : SASL_CHALLENGE,
                   bytes.size, bytes.start);
     pn_buffer_clear(sasl->send_data);
@@ -408,27 +401,44 @@ int pn_do_outcome(pn_dispatcher_t *disp)
 }
 
 #define SASL_HEADER ("AMQP\x03\x01\x00\x00")
+#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
 #define SASL_HEADER_LEN 8
 
 static ssize_t pn_input_read_sasl_header(pn_io_layer_t *io_layer, const char *bytes, size_t available)
 {
   pn_sasl_t *sasl = (pn_sasl_t *)io_layer->context;
-  const char *point = SASL_HEADER + sasl->header_count;
-  int delta = pn_min(available, SASL_HEADER_LEN - sasl->header_count);
-  if (!available || memcmp(bytes, point, delta)) {
-    char quoted[1024];
-    pn_quote_data(quoted, 1024, bytes, available);
-    return pn_error_format(sasl->transport->error, PN_ERR,
-                           "%s header mismatch: '%s'", "SASL", quoted);
-  } else {
-    sasl->header_count += delta;
-    if (sasl->header_count == SASL_HEADER_LEN) {
-      sasl->io_layer->process_input = pn_input_read_sasl;
-      if (sasl->disp->trace & PN_TRACE_FRM)
-        pn_transport_logf(sasl->transport, "  <- %s", "SASL");
+  if (available > 0) {
+    if (available < SASL_HEADER_LEN) {
+      if (memcmp(bytes, SASL_HEADER, available) == 0 ||
+          memcmp(bytes, AMQP_HEADER, available) == 0)
+        return 0;
+    } else {
+      if (memcmp(bytes, SASL_HEADER, SASL_HEADER_LEN) == 0) {
+        sasl->io_layer->process_input = pn_input_read_sasl;
+        if (sasl->disp->trace & PN_TRACE_FRM)
+          pn_transport_logf(sasl->transport, "  <- %s", "SASL");
+        return SASL_HEADER_LEN;
+      }
+      if (memcmp(bytes, AMQP_HEADER, SASL_HEADER_LEN) == 0) {
+        if (sasl->allow_skip) {
+          sasl->outcome = PN_SASL_SKIPPED;
+          sasl->io_layer->process_input = pn_io_layer_input_passthru;
+          sasl->io_layer->process_output = pn_io_layer_output_passthru;
+          pn_io_layer_t *io_next = sasl->io_layer->next;
+          return io_next->process_input( io_next, bytes, available );
+        } else {
+            pn_do_error(sasl->transport, "amqp:connection:policy-error",
+                        "Client skipped SASL exchange - forbidden");
+            return PN_EOS;
+        }
+      }
     }
-    return delta;
   }
+  char quoted[1024];
+  pn_quote_data(quoted, 1024, bytes, available);
+  pn_do_error(sasl->transport, "amqp:connection:framing-error",
+              "%s header mismatch: '%s'", "SASL", quoted);
+  return PN_EOS;
 }
 
 static ssize_t pn_input_read_sasl(pn_io_layer_t *io_layer, const char *bytes, size_t available)
@@ -448,13 +458,10 @@ static ssize_t pn_output_write_sasl_header(pn_io_layer_t *io_layer, char *bytes,
   pn_sasl_t *sasl = (pn_sasl_t *)io_layer->context;
   if (sasl->disp->trace & PN_TRACE_FRM)
     pn_transport_logf(sasl->transport, "  -> %s", "SASL");
-  if (size >= SASL_HEADER_LEN) {
-    memmove(bytes, SASL_HEADER, SASL_HEADER_LEN);
-    sasl->io_layer->process_output = pn_output_write_sasl;
-    return SASL_HEADER_LEN;
-  } else {
-    return pn_error_format(sasl->transport->error, PN_UNDERFLOW, "underflow writing %s header", "SASL");
-  }
+  assert(size >= SASL_HEADER_LEN);
+  memmove(bytes, SASL_HEADER, SASL_HEADER_LEN);
+  sasl->io_layer->process_output = pn_output_write_sasl;
+  return SASL_HEADER_LEN;
 }
 
 static ssize_t pn_output_write_sasl(pn_io_layer_t *io_layer, char *bytes, size_t size)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/selectable.c
----------------------------------------------------------------------
diff --git a/proton-c/src/selectable.c b/proton-c/src/selectable.c
index 97283b4..1f39a38 100644
--- a/proton-c/src/selectable.c
+++ b/proton-c/src/selectable.c
@@ -90,7 +90,7 @@ pn_selectable_t *pni_selectable(ssize_t (*capacity)(pn_selectable_t *),
                                 void (*expired)(pn_selectable_t *),
                                 void (*finalize)(pn_selectable_t *))
 {
-  static pn_class_t clazz = PN_CLASS(pn_selectable);
+  static const pn_class_t clazz = PN_CLASS(pn_selectable);
   pn_selectable_t *selectable = (pn_selectable_t *) pn_new(sizeof(pn_selectable_t), &clazz);
   selectable->capacity = capacity;
   selectable->pending = pending;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index 5815845..db3af4c 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -49,23 +49,25 @@ typedef enum { UNKNOWN_CONNECTION, SSL_CONNECTION, CLEAR_CONNECTION } connection
 typedef struct pn_ssl_session_t pn_ssl_session_t;
 
 struct pn_ssl_domain_t {
-  int   ref_count;
 
   SSL_CTX       *ctx;
-  pn_ssl_mode_t mode;
 
-  bool has_ca_db;       // true when CA database configured
-  bool has_certificate; // true when certificate configured
   char *keyfile_pw;
 
   // settings used for all connections
   char *trusted_CAs;
-  pn_ssl_verify_mode_t verify_mode;
-  bool allow_unsecured;
 
   // session cache
   pn_ssl_session_t *ssn_cache_head;
   pn_ssl_session_t *ssn_cache_tail;
+
+  int   ref_count;
+  pn_ssl_mode_t mode;
+  pn_ssl_verify_mode_t verify_mode;
+
+  bool has_ca_db;       // true when CA database configured
+  bool has_certificate; // true when certificate configured
+  bool allow_unsecured;
 };
 
 
@@ -81,24 +83,25 @@ struct pn_ssl_t {
   BIO *bio_ssl;         // i/o from/to SSL socket layer
   BIO *bio_ssl_io;      // SSL "half" of network-facing BIO
   BIO *bio_net_io;      // socket-side "half" of network-facing BIO
-  bool ssl_shutdown;    // BIO_ssl_shutdown() called on socket.
-  bool ssl_closed;      // shutdown complete, or SSL error
-  ssize_t app_input_closed;   // error code returned by upper layer process input
-  ssize_t app_output_closed;  // error code returned by upper layer process output
-
-  bool read_blocked;    // SSL blocked until more network data is read
-  bool write_blocked;   // SSL blocked until data is written to network
-
   // buffers for holding I/O from "applications" above SSL
 #define APP_BUF_SIZE    (4*1024)
   char *outbuf;
+  char *inbuf;
+
+  ssize_t app_input_closed;   // error code returned by upper layer process input
+  ssize_t app_output_closed;  // error code returned by upper layer process output
+
   size_t out_size;
   size_t out_count;
-  char *inbuf;
   size_t in_size;
   size_t in_count;
 
   pn_trace_t trace;
+
+  bool ssl_shutdown;    // BIO_ssl_shutdown() called on socket.
+  bool ssl_closed;      // shutdown complete, or SSL error
+  bool read_blocked;    // SSL blocked until more network data is read
+  bool write_blocked;   // SSL blocked until data is written to network
 };
 
 struct pn_ssl_session_t {
@@ -184,7 +187,7 @@ static int ssl_failed(pn_ssl_t *ssl)
 {
     SSL_set_shutdown(ssl->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
   ssl->ssl_closed = true;
-  ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
+  ssl->app_input_closed = ssl->app_output_closed = PN_EOS;
   // fake a shutdown so the i/o processing code will close properly
   SSL_set_shutdown(ssl->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
   // try to grab the first SSL error to add to the failure log
@@ -195,7 +198,8 @@ static int ssl_failed(pn_ssl_t *ssl)
   }
   _log_ssl_error(NULL);    // spit out any remaining errors to the log file
   ssl->transport->tail_closed = true;
-  return pn_error_format( ssl->transport->error, PN_ERR, "SSL Failure: %s", buf );
+  pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: %s", buf);
+  return PN_EOS;
 }
 
 /* match the DNS name pattern from the peer certificate against our configured peer
@@ -343,7 +347,7 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
 // "openssl dhparam -C -2 2048"
 static DH *get_dh2048(void)
 {
-  static unsigned char dh2048_p[]={
+  static const unsigned char dh2048_p[]={
     0xAE,0xF7,0xE9,0x66,0x26,0x7A,0xAC,0x0A,0x6F,0x1E,0xCD,0x81,
     0xBD,0x0A,0x10,0x7E,0xFA,0x2C,0xF5,0x2D,0x98,0xD4,0xE7,0xD9,
     0xE4,0x04,0x8B,0x06,0x85,0xF2,0x0B,0xA3,0x90,0x15,0x56,0x0C,
@@ -367,7 +371,7 @@ static DH *get_dh2048(void)
     0xA4,0xED,0xFD,0x49,0x0B,0xE3,0x4A,0xF6,0x28,0xB3,0x98,0xB0,
     0x23,0x1C,0x09,0x33,
   };
-  static unsigned char dh2048_g[]={
+  static const unsigned char dh2048_g[]={
     0x02,
   };
   DH *dh;
@@ -807,7 +811,7 @@ static int setup_ssl_connection( pn_ssl_t *ssl )
 static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_data, size_t available)
 {
   pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
-  if (ssl->ssl == NULL && init_ssl_socket(ssl)) return PN_ERR;
+  if (ssl->ssl == NULL && init_ssl_socket(ssl)) return PN_EOS;
 
   _log( ssl, "process_input_ssl( data size=%d )\n",available );
 
@@ -904,14 +908,13 @@ static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_dat
             if (!max_frame) max_frame = ssl->in_size * 2;  // no limit
             if (ssl->in_size < max_frame) {
               // no max frame limit - grow it.
-              char *newbuf = (char *)malloc( max_frame );
+              size_t newsize = pn_min(max_frame, ssl->in_size * 2);
+              char *newbuf = (char *)realloc( ssl->inbuf, newsize );
               if (newbuf) {
-                ssl->in_size = max_frame;
-                memmove( newbuf, ssl->inbuf, ssl->in_count );
-                free( ssl->inbuf );
+                ssl->in_size = newsize;
                 ssl->inbuf = newbuf;
+                work_pending = true;  // can we get more input?
               }
-              work_pending = true;  // can we get more input?
             } else {
               // can't gather any more input, but app needs more?
               // This is a bug - since SSL can buffer up to max-frame,
@@ -951,8 +954,8 @@ static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_dat
 static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t max_len)
 {
   pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
-  if (!ssl) return PN_ERR;
-  if (ssl->ssl == NULL && init_ssl_socket(ssl)) return PN_ERR;
+  if (!ssl) return PN_EOS;
+  if (ssl->ssl == NULL && init_ssl_socket(ssl)) return PN_EOS;
 
   ssize_t written = 0;
   bool work_pending;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/tests/object.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/object.c b/proton-c/src/tests/object.c
index 228370f..f6d11cf 100644
--- a/proton-c/src/tests/object.c
+++ b/proton-c/src/tests/object.c
@@ -95,7 +95,7 @@ static intptr_t delta(void *a, void *b) { return (uintptr_t) b - (uintptr_t) a;
 
 static pn_class_t null_class = {0};
 
-static pn_class_t noop_class = {noop, noop, zero, delta};
+static pn_class_t noop_class = {NULL, noop, noop, zero, delta};
 
 static void test_new(size_t size, pn_class_t *clazz)
 {
@@ -119,7 +119,7 @@ static void finalizer(void *object)
 
 static void test_finalize(void)
 {
-  static pn_class_t clazz = {NULL, finalizer};
+  static pn_class_t clazz = {NULL, NULL, finalizer};
 
   int **obj = (int **) pn_new(sizeof(int **), &clazz);
   assert(obj);
@@ -141,7 +141,7 @@ static uintptr_t hashcode(void *obj) { return (uintptr_t) obj; }
 
 static void test_hashcode(void)
 {
-  static pn_class_t clazz = {NULL, NULL, hashcode};
+  static pn_class_t clazz = {NULL, NULL, NULL, hashcode};
   void *obj = pn_new(0, &clazz);
   assert(obj);
   assert(pn_hashcode(obj) == (uintptr_t) obj);
@@ -151,7 +151,7 @@ static void test_hashcode(void)
 
 static void test_compare(void)
 {
-  static pn_class_t clazz = {NULL, NULL, NULL, delta};
+  static pn_class_t clazz = {NULL, NULL, NULL, NULL, delta};
 
   void *a = pn_new(0, &clazz);
   assert(a);
@@ -499,6 +499,50 @@ static void test_hash(void)
   pn_decref(three);
 }
 
+
+// collider class: all objects have same hash, no two objects compare equal
+static intptr_t collider_compare(void *a, void *b)
+{
+  if (a == b) return 0;
+  return (a > b) ? 1 : -1;
+}
+
+static uintptr_t collider_hashcode(void *obj)
+{
+  return 23;
+}
+
+#define collider_initialize NULL
+#define collider_finalize NULL
+#define collider_inspect NULL
+
+static void test_map_links(void)
+{
+  const pn_class_t collider_clazz = PN_CLASS(collider);
+  void *keys[3];
+  for (int i = 0; i < 3; i++)
+    keys[i] = pn_new(0, &collider_clazz);
+
+  // test deleting a head, middle link, tail
+
+  for (int delete_idx=0; delete_idx < 3; delete_idx++) {
+    pn_map_t *map = pn_map(0, 0.75, 0);
+    // create a chain of entries that have same head (from identical key hashcode)
+    for (int i = 0; i < 3; i++) {
+      pn_map_put(map, keys[i], keys[i]);
+    }
+    pn_map_del(map, keys[delete_idx]);
+    for (int i = 0; i < 3; i++) {
+      void *value = (i == delete_idx) ? NULL : keys[i];
+      assert (pn_map_get(map, keys[i]) == value);
+    }
+    pn_free(map);
+  }
+  for (int i = 0; i < 3; i++)
+    pn_free(keys[i]);
+}
+
+
 static bool equals(const char *a, const char *b)
 {
   if (a == NULL && b == NULL) {
@@ -792,6 +836,7 @@ int main(int argc, char **argv)
   test_list_index();
 
   test_map();
+  test_map_links();
 
   test_hash();
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/tests/parse-url.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/parse-url.c b/proton-c/src/tests/parse-url.c
index 4489ab2..f57e739 100644
--- a/proton-c/src/tests/parse-url.c
+++ b/proton-c/src/tests/parse-url.c
@@ -64,6 +64,8 @@ static bool test_url_parse(const char* url0, const char* scheme0, const char* us
 
 int main(int argc, char **argv)
 {
+  assert(test_url_parse("", 0, 0, 0, "", 0, 0));
+  assert(test_url_parse("/Foo.bar:90087@somewhere", 0, 0, 0, "", 0, "Foo.bar:90087@somewhere"));
   assert(test_url_parse("host", 0, 0, 0, "host", 0, 0));
   assert(test_url_parse("host:423", 0, 0, 0, "host", "423", 0));
   assert(test_url_parse("user@host", 0, "user", 0, "host", 0, 0));
@@ -96,5 +98,10 @@ int main(int argc, char **argv)
   assert(test_url_parse("us%2fer:password@host", 0, "us/er", "password", "host", 0, 0));
   assert(test_url_parse("us%2Fer:password@host", 0, "us/er", "password", "host", 0, 0));
   assert(test_url_parse("user:pass%2fword%@host", 0, "user", "pass/word%", "host", 0, 0));
+  assert(test_url_parse("localhost/temp-queue://ID:ganymede-36663-1408448359876-2:123:0", 0, 0, 0, "localhost", 0, "temp-queue://ID:ganymede-36663-1408448359876-2:123:0"));
+  assert(test_url_parse("/temp-queue://ID:ganymede-36663-1408448359876-2:123:0", 0, 0, 0, "", 0, "temp-queue://ID:ganymede-36663-1408448359876-2:123:0"));
+  assert(test_url_parse("amqp://localhost/temp-queue://ID:ganymede-36663-1408448359876-2:123:0", "amqp", 0, 0, "localhost", 0, "temp-queue://ID:ganymede-36663-1408448359876-2:123:0"));
+  // Really perverse url
+  assert(test_url_parse("://:@://:", "", "", "", "", "", "/:"));
   return 0;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
index e5b4a31..1ac2876 100644
--- a/proton-c/src/transport/transport.c
+++ b/proton-c/src/transport/transport.c
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <proton/framing.h>
 #include "protocol.h"
+#include "dispatch_actions.h"
 
 #include <assert.h>
 #include <stdarg.h>
@@ -42,7 +43,7 @@ static ssize_t transport_consume(pn_transport_t *transport);
 
 void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next)
 {
-  db->deliveries = pn_hash(1024, 0.75, PN_REFCOUNT);
+  db->deliveries = pn_hash(0, 0.75, PN_REFCOUNT);
   db->next = next;
 }
 
@@ -92,16 +93,6 @@ void pn_delivery_map_clear(pn_delivery_map_t *dm)
   }
 }
 
-int pn_do_open(pn_dispatcher_t *disp);
-int pn_do_begin(pn_dispatcher_t *disp);
-int pn_do_attach(pn_dispatcher_t *disp);
-int pn_do_transfer(pn_dispatcher_t *disp);
-int pn_do_flow(pn_dispatcher_t *disp);
-int pn_do_disposition(pn_dispatcher_t *disp);
-int pn_do_detach(pn_dispatcher_t *disp);
-int pn_do_end(pn_dispatcher_t *disp);
-int pn_do_close(pn_dispatcher_t *disp);
-
 static ssize_t pn_input_read_amqp_header(pn_io_layer_t *io_layer, const char *bytes, size_t available);
 static ssize_t pn_input_read_amqp(pn_io_layer_t *io_layer, const char *bytes, size_t available);
 static ssize_t pn_output_write_amqp_header(pn_io_layer_t *io_layer, char *bytes, size_t available);
@@ -150,16 +141,6 @@ static void pn_transport_initialize(void *object)
   amqp->buffered_input = NULL;
   amqp->next = NULL;
 
-  pn_dispatcher_action(transport->disp, OPEN, pn_do_open);
-  pn_dispatcher_action(transport->disp, BEGIN, pn_do_begin);
-  pn_dispatcher_action(transport->disp, ATTACH, pn_do_attach);
-  pn_dispatcher_action(transport->disp, TRANSFER, pn_do_transfer);
-  pn_dispatcher_action(transport->disp, FLOW, pn_do_flow);
-  pn_dispatcher_action(transport->disp, DISPOSITION, pn_do_disposition);
-  pn_dispatcher_action(transport->disp, DETACH, pn_do_detach);
-  pn_dispatcher_action(transport->disp, END, pn_do_end);
-  pn_dispatcher_action(transport->disp, CLOSE, pn_do_close);
-
   transport->open_sent = false;
   transport->open_rcvd = false;
   transport->close_sent = false;
@@ -178,11 +159,10 @@ static void pn_transport_initialize(void *object)
   transport->remote_idle_timeout = 0;
   transport->keepalive_deadline = 0;
   transport->last_bytes_output = 0;
-  transport->remote_offered_capabilities = pn_data(16);
-  transport->remote_desired_capabilities = pn_data(16);
-  transport->remote_properties = pn_data(16);
-  transport->disp_data = pn_data(16);
-  transport->error = pn_error();
+  transport->remote_offered_capabilities = pn_data(0);
+  transport->remote_desired_capabilities = pn_data(0);
+  transport->remote_properties = pn_data(0);
+  transport->disp_data = pn_data(0);
   pn_condition_init(&transport->remote_condition);
 
   transport->local_channels = pn_hash(0, 0.75, PN_REFCOUNT);
@@ -193,6 +173,8 @@ static void pn_transport_initialize(void *object)
 
   transport->input_pending = 0;
   transport->output_pending = 0;
+
+  transport->done_processing = false;
 }
 
 pn_session_t *pn_channel_state(pn_transport_t *transport, uint16_t channel)
@@ -200,14 +182,20 @@ pn_session_t *pn_channel_state(pn_transport_t *transport, uint16_t channel)
   return (pn_session_t *) pn_hash_get(transport->remote_channels, channel);
 }
 
-static void pn_map_channel(pn_transport_t *transport, uint16_t channel, pn_session_t *session)
+static void pni_map_remote_channel(pn_session_t *session, uint16_t channel)
 {
+  pn_transport_t *transport = session->connection->transport;
   pn_hash_put(transport->remote_channels, channel, session);
   session->state.remote_channel = channel;
 }
 
-void pn_unmap_channel(pn_transport_t *transport, pn_session_t *ssn)
+void pni_transport_unbind_handles(pn_hash_t *handles);
+
+static void pni_unmap_remote_channel(pn_session_t *ssn)
 {
+  // XXX: should really update link state also
+  pni_transport_unbind_handles(ssn->state.remote_handles);
+  pn_transport_t *transport = ssn->connection->transport;
   uint16_t channel = ssn->state.remote_channel;
   ssn->state.remote_channel = -2;
   // note: may free the session:
@@ -222,7 +210,7 @@ static void pn_transport_finalize(void *object);
 
 pn_transport_t *pn_transport()
 {
-  static pn_class_t clazz = PN_CLASS(pn_transport);
+  static const pn_class_t clazz = PN_CLASS(pn_transport);
   pn_transport_t *transport = (pn_transport_t *) pn_new(sizeof(pn_transport_t),
                                                         &clazz);
   if (!transport) return NULL;
@@ -265,7 +253,6 @@ static void pn_transport_finalize(void *object)
   pn_free(transport->remote_desired_capabilities);
   pn_free(transport->remote_properties);
   pn_free(transport->disp_data);
-  pn_error_free(transport->error);
   pn_condition_tini(&transport->remote_condition);
   pn_free(transport->local_channels);
   pn_free(transport->remote_channels);
@@ -281,22 +268,35 @@ int pn_transport_bind(pn_transport_t *transport, pn_connection_t *connection)
   if (connection->transport) return PN_STATE_ERR;
   transport->connection = connection;
   connection->transport = transport;
-  pn_incref(connection);
+  pn_incref2(connection, transport);
   if (transport->open_rcvd) {
     PN_SET_REMOTE(connection->endpoint.state, PN_REMOTE_ACTIVE);
-    pn_event_t *event = pn_collector_put(connection->collector,
-                                         PN_CONNECTION_REMOTE_STATE);
-    if (event) {
-      pn_event_init_connection(event, connection);
-    }
-    if (!pn_error_code(transport->error)) {
-      transport->disp->halt = false;
-      transport_consume(transport);        // blech - testBindAfterOpen
-    }
+    pn_collector_put(connection->collector, PN_CONNECTION_REMOTE_OPEN, connection);
+    transport->disp->halt = false;
+    transport_consume(transport);        // blech - testBindAfterOpen
   }
   return 0;
 }
 
+void pni_transport_unbind_handles(pn_hash_t *handles)
+{
+  for (pn_handle_t h = pn_hash_head(handles); h; h = pn_hash_next(handles, h)) {
+    uintptr_t key = pn_hash_key(handles, h);
+    pn_hash_del(handles, key);
+  }
+}
+
+void pni_transport_unbind_channels(pn_hash_t *channels)
+{
+  for (pn_handle_t h = pn_hash_head(channels); h; h = pn_hash_next(channels, h)) {
+    uintptr_t key = pn_hash_key(channels, h);
+    pn_session_t *ssn = (pn_session_t *) pn_hash_value(channels, h);
+    pni_transport_unbind_handles(ssn->state.local_handles);
+    pni_transport_unbind_handles(ssn->state.remote_handles);
+    pn_hash_del(channels, key);
+  }
+}
+
 int pn_transport_unbind(pn_transport_t *transport)
 {
   assert(transport);
@@ -305,6 +305,7 @@ int pn_transport_unbind(pn_transport_t *transport)
   pn_connection_t *conn = transport->connection;
   transport->connection = NULL;
 
+  // XXX: what happens if the endpoints are freed before we get here?
   pn_session_t *ssn = pn_session_head(conn, 0);
   while (ssn) {
     pn_delivery_map_clear(&ssn->state.incoming);
@@ -319,28 +320,31 @@ int pn_transport_unbind(pn_transport_t *transport)
     endpoint = endpoint->endpoint_next;
   }
 
+  pni_transport_unbind_channels(transport->local_channels);
+  pni_transport_unbind_channels(transport->remote_channels);
+
   pn_connection_unbound(conn);
-  pn_decref(conn);
+  pn_decref2(conn, transport);
   return 0;
 }
 
 pn_error_t *pn_transport_error(pn_transport_t *transport)
 {
-  return transport->error;
+  return NULL;
 }
 
-static void pn_map_handle(pn_session_t *ssn, uint32_t handle, pn_link_t *link)
+static void pni_map_remote_handle(pn_link_t *link, uint32_t handle)
 {
   link->state.remote_handle = handle;
-  pn_hash_put(ssn->state.remote_handles, handle, link);
+  pn_hash_put(link->session->state.remote_handles, handle, link);
 }
 
-void pn_unmap_handle(pn_session_t *ssn, pn_link_t *link)
+static void pni_unmap_remote_handle(pn_link_t *link)
 {
-  uint32_t handle = link->state.remote_handle;
+  uintptr_t handle = link->state.remote_handle;
   link->state.remote_handle = -2;
   // may delete link:
-  pn_hash_del(ssn->state.remote_handles, handle);
+  pn_hash_del(link->session->state.remote_handles, handle);
 }
 
 pn_link_t *pn_handle_state(pn_session_t *ssn, uint32_t handle)
@@ -392,13 +396,12 @@ void pni_disposition_encode(pn_disposition_t *disposition, pn_data_t *data)
   }
 }
 
-int pn_post_close(pn_transport_t *transport, const char *condition)
+int pn_post_close(pn_transport_t *transport, const char *condition, const char *description)
 {
   pn_condition_t *cond = NULL;
   if (transport->connection) {
     cond = pn_connection_condition(transport->connection);
   }
-  const char *description = NULL;
   pn_data_t *info = NULL;
   if (!condition && pn_condition_is_set(cond)) {
     condition = pn_condition_get_name(cond);
@@ -418,13 +421,16 @@ int pn_do_error(pn_transport_t *transport, const char *condition, const char *fm
   // XXX: result
   vsnprintf(buf, 1024, fmt, ap);
   va_end(ap);
-  pn_error_set(transport->error, PN_ERR, buf);
   if (!transport->close_sent) {
-    pn_post_close(transport, condition);
+    if (!transport->open_sent) {
+      pn_post_frame(transport->disp, 0, "DL[S]", OPEN, "");
+    }
+
+    pn_post_close(transport, condition, buf);
     transport->close_sent = true;
   }
   transport->disp->halt = true;
-  pn_transport_logf(transport, "ERROR %s %s", condition, pn_error_text(transport->error));
+  pn_transport_logf(transport, "ERROR %s %s", condition, buf);
   return PN_ERR;
 }
 
@@ -459,7 +465,6 @@ int pn_do_open(pn_dispatcher_t *disp)
     }
     disp->remote_max_frame = transport->remote_max_frame;
     pn_buffer_clear( disp->frame );
-    pn_buffer_ensure( disp->frame, disp->remote_max_frame );
   }
   if (container_q) {
     transport->remote_container = pn_bytes_strdup(remote_container);
@@ -474,12 +479,7 @@ int pn_do_open(pn_dispatcher_t *disp)
 
   if (conn) {
     PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_ACTIVE);
-
-    pn_event_t *event = pn_collector_put(conn->collector,
-                                         PN_CONNECTION_REMOTE_STATE);
-    if (event) {
-      pn_event_init_connection(event, conn);
-    }
+    pn_collector_put(conn->collector, PN_CONNECTION_REMOTE_OPEN, conn);
   } else {
     transport->disp->halt = true;
   }
@@ -506,15 +506,9 @@ int pn_do_begin(pn_dispatcher_t *disp)
     ssn = pn_session(transport->connection);
   }
   ssn->state.incoming_transfer_count = next;
-  pn_map_channel(transport, disp->channel, ssn);
+  pni_map_remote_channel(ssn, disp->channel);
   PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_ACTIVE);
-
-  pn_event_t *event = pn_collector_put(transport->connection->collector,
-                                       PN_SESSION_REMOTE_STATE);
-  if (event) {
-    pn_event_init_session(event, ssn);
-  }
-
+  pn_collector_put(transport->connection->collector, PN_SESSION_REMOTE_OPEN, ssn);
   return 0;
 }
 
@@ -537,18 +531,18 @@ pn_link_t *pn_find_link(pn_session_t *ssn, pn_bytes_t name, bool is_sender)
 static pn_expiry_policy_t symbol2policy(pn_bytes_t symbol)
 {
   if (!symbol.start)
-    return PN_SESSION_CLOSE;
+    return PN_EXPIRE_WITH_SESSION;
 
   if (!strncmp(symbol.start, "link-detach", symbol.size))
-    return PN_LINK_CLOSE;
+    return PN_EXPIRE_WITH_LINK;
   if (!strncmp(symbol.start, "session-end", symbol.size))
-    return PN_SESSION_CLOSE;
+    return PN_EXPIRE_WITH_SESSION;
   if (!strncmp(symbol.start, "connection-close", symbol.size))
-    return PN_CONNECTION_CLOSE;
+    return PN_EXPIRE_WITH_CONNECTION;
   if (!strncmp(symbol.start, "never", symbol.size))
-    return PN_NEVER;
+    return PN_EXPIRE_NEVER;
 
-  return PN_SESSION_CLOSE;
+  return PN_EXPIRE_WITH_SESSION;
 }
 
 static pn_distribution_mode_t symbol2dist_mode(const pn_bytes_t symbol)
@@ -613,6 +607,10 @@ int pn_do_attach(pn_dispatcher_t *disp)
   strname[name.size] = '\0';
 
   pn_session_t *ssn = pn_channel_state(transport, disp->channel);
+  if (!ssn) {
+      pn_do_error(transport, "amqp:connection:no-session", "attach without a session");
+      return PN_EOS;
+  }
   pn_link_t *link = pn_find_link(ssn, name, is_sender);
   if (!link) {
     if (is_sender) {
@@ -626,7 +624,7 @@ int pn_do_attach(pn_dispatcher_t *disp)
     free(strheap);
   }
 
-  pn_map_handle(ssn, handle, link);
+  pni_map_remote_handle(link, handle);
   PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_ACTIVE);
   pn_terminus_t *rsrc = &link->remote_source;
   if (source.start || src_dynamic) {
@@ -684,12 +682,7 @@ int pn_do_attach(pn_dispatcher_t *disp)
     link->state.delivery_count = idc;
   }
 
-  pn_event_t *event = pn_collector_put(transport->connection->collector,
-                                       PN_LINK_REMOTE_STATE);
-  if (event) {
-    pn_event_init_link(event, link);
-  }
-
+  pn_collector_put(transport->connection->collector, PN_LINK_REMOTE_OPEN, link);
   return 0;
 }
 
@@ -770,11 +763,7 @@ int pn_do_transfer(pn_dispatcher_t *disp)
     pn_post_flow(transport, ssn, link);
   }
 
-  pn_event_t *event = pn_collector_put(transport->connection->collector, PN_DELIVERY);
-  if (event) {
-    pn_event_init_delivery(event, delivery);
-  }
-
+  pn_collector_put(transport->connection->collector, PN_DELIVERY, delivery);
   return 0;
 }
 
@@ -824,10 +813,7 @@ int pn_do_flow(pn_dispatcher_t *disp)
       }
     }
 
-    pn_event_t *event = pn_collector_put(transport->connection->collector, PN_LINK_FLOW);
-    if (event) {
-      pn_event_init_link(event, link);
-    }
+    pn_collector_put(transport->connection->collector, PN_LINK_FLOW, link);
   }
 
   return 0;
@@ -922,10 +908,7 @@ int pn_do_disposition(pn_dispatcher_t *disp)
       delivery->updated = true;
       pn_work_update(transport->connection, delivery);
 
-      pn_event_t *event = pn_collector_put(transport->connection->collector, PN_DELIVERY);
-      if (event) {
-        pn_event_init_delivery(event, delivery);
-      }
+      pn_collector_put(transport->connection->collector, PN_DELIVERY, delivery);
     }
   }
 
@@ -955,16 +938,12 @@ int pn_do_detach(pn_dispatcher_t *disp)
   if (closed)
   {
     PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_CLOSED);
-    pn_event_t *event = pn_collector_put(transport->connection->collector,
-                                         PN_LINK_REMOTE_STATE);
-    if (event) {
-      pn_event_init_link(event, link);
-    }
+    pn_collector_put(transport->connection->collector, PN_LINK_REMOTE_CLOSE, link);
   } else {
     // TODO: implement
   }
 
-  pn_unmap_handle(ssn, link);
+  pni_unmap_remote_handle(link);
   return 0;
 }
 
@@ -975,12 +954,8 @@ int pn_do_end(pn_dispatcher_t *disp)
   int err = pn_scan_error(disp->args, &ssn->endpoint.remote_condition, SCAN_ERROR_DEFAULT);
   if (err) return err;
   PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_CLOSED);
-  pn_event_t *event = pn_collector_put(transport->connection->collector,
-                                       PN_SESSION_REMOTE_STATE);
-  if (event) {
-    pn_event_init_session(event, ssn);
-  }
-  pn_unmap_channel(transport, ssn);
+  pn_collector_put(transport->connection->collector, PN_SESSION_REMOTE_CLOSE, ssn);
+  pni_unmap_remote_channel(ssn);
   return 0;
 }
 
@@ -992,11 +967,7 @@ int pn_do_close(pn_dispatcher_t *disp)
   if (err) return err;
   transport->close_rcvd = true;
   PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_CLOSED);
-  pn_event_t *event = pn_collector_put(transport->connection->collector,
-                                       PN_CONNECTION_REMOTE_STATE);
-  if (event) {
-    pn_event_init_connection(event, conn);
-  }
+  pn_collector_put(transport->connection->collector, PN_CONNECTION_REMOTE_CLOSE, conn);
   return 0;
 }
 
@@ -1043,11 +1014,7 @@ static ssize_t transport_consume(pn_transport_t *transport)
     } else if (n == 0) {
       break;
     } else {
-      if (n != PN_EOS) {
-        pn_transport_logf(transport, "ERROR[%i] %s\n",
-                          pn_error_code(transport->error),
-                          pn_error_text(transport->error));
-      }
+      assert(n == PN_EOS);
       if (transport->disp->trace & (PN_TRACE_RAW | PN_TRACE_FRM))
         pn_transport_log(transport, "  <- EOS");
       transport->input_pending = 0;  // XXX ???
@@ -1071,9 +1038,10 @@ static ssize_t pn_input_read_header(pn_transport_t *transport, const char *bytes
   if (!available || memcmp(bytes, point, delta)) {
     char quoted[1024];
     pn_quote_data(quoted, 1024, bytes, available);
-    return pn_error_format(transport->error, PN_ERR,
-                           "%s header mismatch: '%s'%s", protocol, quoted,
-                           available ? "" : " (connection aborted)");
+    pn_do_error(transport, "amqp:connection:framing-error",
+                "%s header mismatch: '%s'%s", protocol, quoted,
+                available ? "" : " (connection aborted)");
+    return PN_EOS;
   } else {
     transport->header_count += delta;
     if (transport->header_count == size) {
@@ -1102,21 +1070,20 @@ static ssize_t pn_input_read_amqp(pn_io_layer_t *io_layer, const char *bytes, si
   if (transport->close_rcvd) {
     if (available > 0) {
       pn_do_error(transport, "amqp:connection:framing-error", "data after close");
-      return PN_ERR;
-    } else {
       return PN_EOS;
     }
   }
 
   if (!available) {
     pn_do_error(transport, "amqp:connection:framing-error", "connection aborted");
-    return PN_ERR;
+    return PN_EOS;
   }
 
 
   ssize_t n = pn_dispatcher_input(transport->disp, bytes, available);
   if (n < 0) {
-    return pn_error_set(transport->error, n, "dispatch error");
+    //return pn_error_set(transport->error, n, "dispatch error");
+    return PN_EOS;
   } else if (transport->close_rcvd) {
     return PN_EOS;
   } else {
@@ -1230,6 +1197,15 @@ size_t pn_session_incoming_window(pn_session_t *ssn)
   }
 }
 
+static void pni_map_local_channel(pn_session_t *ssn)
+{
+  pn_transport_t *transport = ssn->connection->transport;
+  pn_session_state_t *state = &ssn->state;
+  uint16_t channel = allocate_alias(transport->local_channels);
+  state->local_channel = channel;
+  pn_hash_put(transport->local_channels, channel, ssn);
+}
+
 int pn_process_ssn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
 {
   if (endpoint->type == SESSION && transport->open_sent)
@@ -1238,16 +1214,14 @@ int pn_process_ssn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
     pn_session_state_t *state = &ssn->state;
     if (!(endpoint->state & PN_LOCAL_UNINIT) && state->local_channel == (uint16_t) -1)
     {
-      uint16_t channel = allocate_alias(transport->local_channels);
+      pni_map_local_channel(ssn);
       state->incoming_window = pn_session_incoming_window(ssn);
       state->outgoing_window = pn_session_outgoing_window(ssn);
-      pn_post_frame(transport->disp, channel, "DL[?HIII]", BEGIN,
+      pn_post_frame(transport->disp, state->local_channel, "DL[?HIII]", BEGIN,
                     ((int16_t) state->remote_channel >= 0), state->remote_channel,
                     state->outgoing_transfer_count,
                     state->incoming_window,
                     state->outgoing_window);
-      state->local_channel = channel;
-      pn_hash_put(transport->local_channels, channel, ssn);
     }
   }
 
@@ -1258,18 +1232,25 @@ static const char *expiry_symbol(pn_expiry_policy_t policy)
 {
   switch (policy)
   {
-  case PN_LINK_CLOSE:
+  case PN_EXPIRE_WITH_LINK:
     return "link-detach";
-  case PN_SESSION_CLOSE:
+  case PN_EXPIRE_WITH_SESSION:
     return NULL;
-  case PN_CONNECTION_CLOSE:
+  case PN_EXPIRE_WITH_CONNECTION:
     return "connection-close";
-  case PN_NEVER:
+  case PN_EXPIRE_NEVER:
     return "never";
   }
   return NULL;
 }
 
+static void pni_map_local_handle(pn_link_t *link) {
+  pn_link_state_t *state = &link->state;
+  pn_session_state_t *ssn_state = &link->session->state;
+  state->local_handle = allocate_alias(ssn_state->local_handles);
+  pn_hash_put(ssn_state->local_handles, state->local_handle, link);
+}
+
 int pn_process_link_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
 {
   if (transport->open_sent && (endpoint->type == SENDER ||
@@ -1281,8 +1262,7 @@ int pn_process_link_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
     if (((int16_t) ssn_state->local_channel >= 0) &&
         !(endpoint->state & PN_LOCAL_UNINIT) && state->local_handle == (uint32_t) -1)
     {
-      state->local_handle = allocate_alias(ssn_state->local_handles);
-      pn_hash_put(ssn_state->local_handles, state->local_handle, link);
+      pni_map_local_handle(link);
       const pn_distribution_mode_t dist_mode = link->source.distribution_mode;
       int err = pn_post_frame(transport->disp, ssn_state->local_channel,
                               "DL[SIoBB?DL[SIsIoC?sCnCC]?DL[SIsIoCC]nnI]", ATTACH,
@@ -1464,6 +1444,8 @@ int pn_process_tpwork_sender(pn_transport_t *transport, pn_delivery_t *delivery,
         link->queued--;
         link->session->outgoing_deliveries--;
       }
+
+      pn_collector_put(transport->connection->collector, PN_LINK_FLOW, link);
     }
   }
 
@@ -1573,6 +1555,14 @@ int pn_process_flow_sender(pn_transport_t *transport, pn_endpoint_t *endpoint)
   return 0;
 }
 
+static void pni_unmap_local_handle(pn_link_t *link) {
+  pn_link_state_t *state = &link->state;
+  uintptr_t handle = state->local_handle;
+  state->local_handle = -2;
+  // may delete link
+  pn_hash_del(link->session->state.local_handles, handle);
+}
+
 int pn_process_link_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
 {
   if (endpoint->type == SENDER || endpoint->type == RECEIVER)
@@ -1601,8 +1591,7 @@ int pn_process_link_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
       int err = pn_post_frame(transport->disp, ssn_state->local_channel, "DL[Io?DL[sSC]]", DETACH,
                               state->local_handle, true, (bool) name, ERROR, name, description, info);
       if (err) return err;
-      pn_hash_del(ssn_state->local_handles, state->local_handle);
-      state->local_handle = -2;
+      pni_unmap_local_handle(link);
     }
 
     pn_clear_modified(transport->connection, endpoint);
@@ -1634,6 +1623,17 @@ bool pn_pointful_buffering(pn_transport_t *transport, pn_session_t *session)
   return false;
 }
 
+static void pni_unmap_local_channel(pn_session_t *ssn) {
+  // XXX: should really update link state also
+  pni_transport_unbind_handles(ssn->state.local_handles);
+  pn_transport_t *transport = ssn->connection->transport;
+  pn_session_state_t *state = &ssn->state;
+  uintptr_t channel = state->local_channel;
+  state->local_channel = -2;
+  // may delete session
+  pn_hash_del(transport->local_channels, channel);
+}
+
 int pn_process_ssn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
 {
   if (endpoint->type == SESSION)
@@ -1643,7 +1643,9 @@ int pn_process_ssn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
     if (endpoint->state & PN_LOCAL_CLOSED && (int16_t) state->local_channel >= 0
         && !transport->close_sent)
     {
-      if (pn_pointful_buffering(transport, session)) return 0;
+      if (pn_pointful_buffering(transport, session)) {
+        return 0;
+      }
 
       const char *name = NULL;
       const char *description = NULL;
@@ -1658,8 +1660,7 @@ int pn_process_ssn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
       int err = pn_post_frame(transport->disp, state->local_channel, "DL[?DL[sSC]]", END,
                               (bool) name, ERROR, name, description, info);
       if (err) return err;
-      pn_hash_del(transport->local_channels, state->local_channel);
-      state->local_channel = -2;
+      pni_unmap_local_channel(session);
     }
 
     pn_clear_modified(transport->connection, endpoint);
@@ -1673,7 +1674,7 @@ int pn_process_conn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
   {
     if (endpoint->state & PN_LOCAL_CLOSED && !transport->close_sent) {
       if (pn_pointful_buffering(transport, NULL)) return 0;
-      int err = pn_post_close(transport, NULL);
+      int err = pn_post_close(transport, NULL, NULL);
       if (err) return err;
       transport->close_sent = true;
     }
@@ -1733,13 +1734,10 @@ static ssize_t pn_output_write_header(pn_transport_t *transport,
 {
   if (transport->disp->trace & PN_TRACE_FRM)
     pn_transport_logf(transport, "  -> %s", protocol);
-  if (size >= hdrsize) {
-    memmove(bytes, header, hdrsize);
-    transport->io_layers[PN_IO_AMQP].process_output = next;
-    return hdrsize;
-  } else {
-    return pn_error_format(transport->error, PN_UNDERFLOW, "underflow writing %s header", protocol);
-  }
+  assert(size >= hdrsize);
+  memmove(bytes, header, hdrsize);
+  transport->io_layers[PN_IO_AMQP].process_output = next;
+  return hdrsize;
 }
 
 static ssize_t pn_output_write_amqp_header(pn_io_layer_t *io_layer, char *bytes, size_t size)
@@ -1752,22 +1750,19 @@ static ssize_t pn_output_write_amqp_header(pn_io_layer_t *io_layer, char *bytes,
 static ssize_t pn_output_write_amqp(pn_io_layer_t *io_layer, char *bytes, size_t size)
 {
   pn_transport_t *transport = (pn_transport_t *)io_layer->context;
-  if (!transport->connection) {
-    return 0;
-  }
-
-  if (!pn_error_code(transport->error)) {
-    pn_error_set(transport->error, pn_process(transport), "process error");
+  if (transport->connection && !transport->done_processing) {
+    int err = pn_process(transport);
+    if (err) {
+      pn_transport_logf(transport, "process error %i", err);
+      transport->done_processing = true;
+    }
   }
 
-  // write out any buffered data _before_ returning an error code,
-  // else we could truncate an outgoing Close frame containing a
-  // useful error status
-  if (!transport->disp->available && (transport->close_sent || pn_error_code(transport->error))) {
-    if (pn_error_code(transport->error))
-      return pn_error_code(transport->error);
-    else
-      return PN_EOS;
+  // write out any buffered data _before_ returning PN_EOS, else we
+  // could truncate an outgoing Close frame containing a useful error
+  // status
+  if (!transport->disp->available && transport->close_sent) {
+    return PN_EOS;
   }
 
   return pn_dispatcher_output(transport->disp, bytes, size);
@@ -1779,20 +1774,18 @@ static ssize_t transport_produce(pn_transport_t *transport)
   pn_io_layer_t *io_layer = transport->io_layers;
   ssize_t space = transport->output_size - transport->output_pending;
 
-  if (space == 0) {     // can we expand the buffer?
+  if (space <= 0) {     // can we expand the buffer?
     int more = 0;
     if (!transport->remote_max_frame)   // no limit, so double it
       more = transport->output_size;
     else if (transport->remote_max_frame > transport->output_size)
-      more = transport->remote_max_frame - transport->output_size;
+      more = pn_min(transport->output_size, transport->remote_max_frame - transport->output_size);
     if (more) {
-      char *newbuf = (char *)malloc( transport->output_size + more );
+      char *newbuf = (char *)realloc( transport->output_buf, transport->output_size + more );
       if (newbuf) {
-        memmove( newbuf, transport->output_buf, transport->output_pending );
-        free( transport->output_buf );
         transport->output_buf = newbuf;
         transport->output_size += more;
-        space = more;
+        space += more;
       }
     }
   }
@@ -1811,11 +1804,12 @@ static ssize_t transport_produce(pn_transport_t *transport)
       if (transport->output_pending)
         break;   // return what is available
       if (transport->disp->trace & (PN_TRACE_RAW | PN_TRACE_FRM)) {
-        if (n == PN_EOS)
+        if (n < 0) {
           pn_transport_log(transport, "  -> EOS");
-        else
+        }
+        /*else
           pn_transport_logf(transport, "  -> EOS (%" PN_ZI ") %s", n,
-                            pn_error_text(transport->error));
+          pn_error_text(transport->error));*/
       }
       return n;
     }
@@ -1993,22 +1987,20 @@ ssize_t pn_transport_capacity(pn_transport_t *transport)  /* <0 == done */
   //if (pn_error_code(transport->error)) return pn_error_code(transport->error);
 
   ssize_t capacity = transport->input_size - transport->input_pending;
-  if (!capacity) {
+  if ( capacity<=0 ) {
     // can we expand the size of the input buffer?
     int more = 0;
     if (!transport->local_max_frame) {  // no limit (ha!)
       more = transport->input_size;
     } else if (transport->local_max_frame > transport->input_size) {
-      more = transport->local_max_frame - transport->input_size;
+      more = pn_min(transport->input_size, transport->local_max_frame - transport->input_size);
     }
     if (more) {
-      char *newbuf = (char *) malloc( transport->input_size + more );
+      char *newbuf = (char *) realloc( transport->input_buf, transport->input_size + more );
       if (newbuf) {
-        memmove( newbuf, transport->input_buf, transport->input_pending );
-        free( transport->input_buf );
         transport->input_buf = newbuf;
         transport->input_size += more;
-        capacity = more;
+        capacity += more;
       }
     }
   }
@@ -2024,7 +2016,7 @@ char *pn_transport_tail(pn_transport_t *transport)
   return NULL;
 }
 
-int pn_transport_push(pn_transport_t *transport, const char *src, size_t size)
+ssize_t pn_transport_push(pn_transport_t *transport, const char *src, size_t size)
 {
   assert(transport);
 
@@ -2032,14 +2024,19 @@ int pn_transport_push(pn_transport_t *transport, const char *src, size_t size)
   if (capacity < 0) {
     return capacity;
   } else if (size > (size_t) capacity) {
-    return PN_OVERFLOW;
+    size = capacity;
   }
 
   char *dst = pn_transport_tail(transport);
   assert(dst);
   memmove(dst, src, size);
 
-  return pn_transport_process(transport, size);
+  int n = pn_transport_process(transport, size);
+  if (n < 0) {
+    return n;
+  } else {
+    return size;
+  }
 }
 
 int pn_transport_process(pn_transport_t *transport, size_t size)
@@ -2062,8 +2059,7 @@ int pn_transport_process(pn_transport_t *transport, size_t size)
 int pn_transport_close_tail(pn_transport_t *transport)
 {
   transport->tail_closed = true;
-  ssize_t x = transport_consume( transport );
-  if (x < 0) return (int) x;
+  transport_consume( transport );
   return 0;
   // XXX: what if not all input processed at this point?  do we care???
 }
@@ -2084,7 +2080,7 @@ const char *pn_transport_head(pn_transport_t *transport)
   return NULL;
 }
 
-int pn_transport_peek(pn_transport_t *transport, char *dst, size_t size)
+ssize_t pn_transport_peek(pn_transport_t *transport, char *dst, size_t size)
 {
   assert(transport);
 
@@ -2092,7 +2088,7 @@ int pn_transport_peek(pn_transport_t *transport, char *dst, size_t size)
   if (pending < 0) {
     return pending;
   } else if (size > (size_t) pending) {
-    return PN_UNDERFLOW;
+    size = pending;
   }
 
   if (pending > 0) {
@@ -2101,7 +2097,7 @@ int pn_transport_peek(pn_transport_t *transport, char *dst, size_t size)
     memmove(dst, src, size);
   }
 
-  return 0;
+  return size;
 }
 
 void pn_transport_pop(pn_transport_t *transport, size_t size)
@@ -2120,11 +2116,7 @@ void pn_transport_pop(pn_transport_t *transport, size_t size)
 int pn_transport_close_head(pn_transport_t *transport)
 {
   transport->head_closed = true;
-  if (transport->close_sent && transport->output_pending == 0) {
-    return 0;
-  } else {
-    return pn_error_set(transport->error, PN_ERR, "connection aborted");
-  }
+  return 0;
 }
 
 // true if the transport will not generate further output

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/types.c
----------------------------------------------------------------------
diff --git a/proton-c/src/types.c b/proton-c/src/types.c
index 1179db2..51abc59 100644
--- a/proton-c/src/types.c
+++ b/proton-c/src/types.c
@@ -23,20 +23,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-pn_bytes_t pn_bytes(size_t size, char *start)
+pn_bytes_t pn_bytes(size_t size, const char *start)
 {
   pn_bytes_t bytes = {size, start};
   return bytes;
 }
-
-pn_bytes_t pn_bytes_dup(size_t size, const char *start)
-{
-  if (size && start)
-  {
-    char *dup = (char *) malloc(size);
-    memmove(dup, start, size);
-    return pn_bytes(size, dup);
-  } else {
-    return pn_bytes(0, NULL);
-  }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/util.c
----------------------------------------------------------------------
diff --git a/proton-c/src/util.c b/proton-c/src/util.c
index e6b9af0..16e3685 100644
--- a/proton-c/src/util.c
+++ b/proton-c/src/util.c
@@ -139,20 +139,28 @@ void pni_urldecode(const char *src, char *dst)
 
 // Parse URL syntax:
 // [ <scheme> :// ] [ <user> [ : <password> ] @ ] <host> [ : <port> ] [ / <path> ]
-// <user>, <password>, <host>, <port> cannot contain any of '@', ':', '/'
+// <scheme>, <user>, <password>, <port> cannot contain any of '@', ':', '/'
+// If the first character of <host> is '[' then it can contain any character up to ']' (this is to allow IPv6
+// literal syntax). Otherwise it also cannot contain '@', ':', '/'
+// <host> is not optional but it can be null! If it is not present an empty string will be returned
 // <path> can contain any character
 void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path)
 {
   if (!url) return;
 
-  char *scheme_end = strstr(url, "://");
-  if (scheme_end) {
-    *scheme_end = '\0';
-    *scheme = url;
-    url = scheme_end + 3;
+  char *slash = strchr(url, '/');
+
+  if (slash && slash>url) {
+    char *scheme_end = strstr(slash-1, "://");
+
+    if (scheme_end && scheme_end<slash) {
+      *scheme_end = '\0';
+      *scheme = url;
+      url = scheme_end + 3;
+      slash = strchr(url, '/');
+    }
   }
 
-  char *slash = strchr(url, '/');
   if (slash) {
     *slash = '\0';
     *path = slash + 1;


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


[46/51] [abbrv] qpid-proton git commit: Sync with proton trunk revision 1627945 and update CMakeLists.txt

Posted by rh...@apache.org.
Sync with proton trunk revision 1627945 and update CMakeLists.txt

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1627970 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/92b8098c
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/92b8098c
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/92b8098c

Branch: refs/heads/master
Commit: 92b8098ce41a6d56ab8899fe458010992ae9162e
Parents: d8ebc7f
Author: fadams <fa...@unknown>
Authored: Sat Sep 27 14:23:00 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sat Sep 27 14:23:00 2014 +0000

----------------------------------------------------------------------
 .gitignore                                      |    1 +
 .mailmap                                        |    2 +
 CMakeLists.txt                                  |   15 +-
 .../proton/jms/AutoOutboundTransformer.java     |    5 +-
 .../jms/JMSMappingOutboundTransformer.java      |   61 +-
 .../qpid/proton/jms/OutboundTransformer.java    |   34 +-
 examples/include/pncompat/misc_funcs.inc        |    5 +-
 pom.xml                                         |   68 +-
 proton-c/CMakeLists.txt                         |   26 +-
 proton-c/bindings/javascript/CMakeLists.txt     |    7 +-
 proton-c/bindings/javascript/messenger.js       |   83 +-
 proton-c/bindings/perl/perl.i                   |    1 +
 proton-c/bindings/php/php.i                     |    9 +-
 proton-c/bindings/python/cproton.i              |  201 +--
 proton-c/bindings/python/proton.py              |  232 ++-
 .../bindings/ruby/lib/qpid_proton/version.rb    |    4 +-
 proton-c/bindings/ruby/ruby.i                   |    2 +-
 proton-c/include/proton/cid.h                   |   56 +
 proton-c/include/proton/connection.h            |    5 +
 proton-c/include/proton/cproton.i               |   15 +
 proton-c/include/proton/driver.h                |    3 +-
 proton-c/include/proton/event.h                 |  111 +-
 proton-c/include/proton/link.h                  |    7 +
 proton-c/include/proton/messenger.h             |  128 ++
 proton-c/include/proton/object.h                |   81 +-
 proton-c/include/proton/sasl.h                  |    2 +-
 proton-c/include/proton/ssl.h                   |    2 +-
 proton-c/include/proton/transport.h             |   21 +-
 proton-c/include/proton/url.h                   |   98 ++
 proton-c/include/proton/util.h                  |   40 -
 proton-c/src/codec/codec.c                      |   18 +-
 proton-c/src/codec/data.h                       |    6 +-
 proton-c/src/codec/decoder.c                    |    2 +-
 proton-c/src/codec/encoder.c                    |    2 +-
 proton-c/src/dispatcher/dispatcher.c            |    4 +-
 proton-c/src/dispatcher/dispatcher.h            |    5 +-
 proton-c/src/engine/engine-internal.h           |   13 +-
 proton-c/src/engine/engine.c                    |  184 ++-
 proton-c/src/engine/event.c                     |  348 -----
 proton-c/src/engine/event.h                     |   28 -
 proton-c/src/events/event.c                     |  298 ++++
 proton-c/src/message/message.c                  |    8 +-
 proton-c/src/messenger/messenger.c              |  361 ++++-
 proton-c/src/messenger/store.c                  |    7 +-
 proton-c/src/messenger/subscription.c           |    5 +-
 proton-c/src/messenger/transform.c              |   21 +-
 proton-c/src/messenger/transform.h              |    4 +-
 proton-c/src/object/iterator.c                  |   78 ++
 proton-c/src/object/list.c                      |  225 +++
 proton-c/src/object/map.c                       |  401 ++++++
 proton-c/src/object/object.c                    | 1057 +++-----------
 proton-c/src/object/string.c                    |  270 ++++
 proton-c/src/platform.c                         |    9 +-
 proton-c/src/posix/driver.c                     |   12 +-
 proton-c/src/posix/io.c                         |    4 +-
 proton-c/src/posix/selector.c                   |   10 +-
 proton-c/src/proton.c                           |   16 +-
 proton-c/src/sasl/sasl.c                        |    8 +-
 proton-c/src/selectable.c                       |    2 +-
 proton-c/src/ssl/openssl.c                      |    9 +-
 proton-c/src/ssl/ssl_stub.c                     |    2 +
 proton-c/src/tests/object.c                     |  191 ++-
 proton-c/src/tests/parse-url.c                  |    6 +-
 proton-c/src/transport/transport.c              |  151 +-
 proton-c/src/url.c                              |  168 +++
 proton-c/src/util.c                             |    7 +-
 proton-c/src/util.h                             |    3 +
 proton-c/src/windows/driver.c                   |  611 ++++----
 proton-c/src/windows/io.c                       |   33 +-
 proton-c/src/windows/iocp.c                     |   33 +-
 proton-c/src/windows/iocp.h                     |    2 +-
 proton-c/src/windows/schannel.c                 | 1320 ++++++++++++++++++
 proton-c/src/windows/selector.c                 |    6 +-
 proton-c/src/windows/write_pipeline.c           |    9 +-
 .../org/apache/qpid/proton/amqp/Binary.java     |   12 +-
 .../apache/qpid/proton/codec/EncoderImpl.java   |   40 +-
 .../apache/qpid/proton/codec/StringType.java    |   21 +-
 .../org/apache/qpid/proton/engine/Event.java    |   82 +-
 .../org/apache/qpid/proton/engine/Link.java     |    3 +
 .../apache/qpid/proton/engine/Transport.java    |    3 +
 .../qpid/proton/engine/impl/EventImpl.java      |   33 +-
 .../qpid/proton/engine/impl/LinkImpl.java       |   14 +
 .../qpid/proton/engine/impl/SessionImpl.java    |    7 +-
 .../qpid/proton/engine/impl/TransportImpl.java  |   73 +-
 .../qpid/proton/messenger/impl/Address.java     |   75 +-
 proton-j/src/main/resources/cengine.py          |   50 +-
 proton-j/src/main/resources/cobject.py          |   42 +
 proton-j/src/main/resources/cproton.py          |    6 +
 proton-j/src/main/resources/curl.py             |   47 +
 .../org/apache/qpid/proton/amqp/BinaryTest.java |  108 ++
 .../qpid/proton/codec/StringTypeTest.java       |  148 ++
 .../qpid/proton/messenger/impl/AddressTest.java |   54 +-
 .../qpid/proton/systemtests/EngineTestBase.java |  113 ++
 .../qpid/proton/systemtests/FreeTest.java       |  236 ++++
 .../systemtests/ProtonEngineExampleTest.java    |  238 ++--
 tests/python/proton_tests/__init__.py           |    2 +-
 tests/python/proton_tests/engine.py             |  116 +-
 tests/python/proton_tests/scratch.py            |   44 +
 tests/python/proton_tests/url.py                |  125 ++
 99 files changed, 6343 insertions(+), 2631 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 8d9d2f9..2af3e68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@ target
 .settings
 .cproject
 eclipse-classes
+.pydevproject
 # End of Eclipse IDE files
 
 # The usual location for proton-c build files

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/.mailmap
----------------------------------------------------------------------
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..554997f
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,2 @@
+Clifford Jansen <cl...@apache.org>
+Ken Giusti <kg...@apache.org>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7917258..f2532e9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -85,12 +85,7 @@ mark_as_advanced (INCLUDE_INSTALL_DIR LIB_INSTALL_DIR SYSCONF_INSTALL_DIR SHARE_
 # system specified locations.
 set (BINDINGS_DIR ${LIB_INSTALL_DIR}/proton/bindings)
 
-set (SYSINSTALL_BINDINGS "*UNSPECIFIED*" CACHE BOOL "If SYSINSTALL_BINDINGS is OFF then proton bindings will be installed underneath ${BINDINGS_DIR} and each user will need to modify their interpreter configuration to load the appropriate binding. If SYSINSTALL_BINDINGS is ON, then each language interpreter will be queried for the appropriate directory and proton bindings will be installed and available system wide with no additional per user configuration.")
-
-if (SYSINSTALL_BINDINGS STREQUAL "*UNSPECIFIED*")
-  message(WARNING "SYSINSTALL_BINDINGS is unspecified, defaulting it to OFF. Please note that the default install behaviour of proton has changed. Proton bindings by default will now be installed under ${BINDINGS_DIR} and will no longer be found by system interpreters. This means that every user will be required to manually configure their interpreters to locate the proton bindings. If you wish proton bindings to be installed into the interpreter specified locations as was the default in prior releases, please specify -DSYSINSTALL_BINDINGS=ON")
-  set (SYSINSTALL_BINDINGS OFF)
-endif ()
+set (SYSINSTALL_BINDINGS OFF CACHE BOOL "If SYSINSTALL_BINDINGS is OFF then proton bindings will be installed underneath ${BINDINGS_DIR} and each user will need to modify their interpreter configuration to load the appropriate binding. If SYSINSTALL_BINDINGS is ON, then each language interpreter will be queried for the appropriate directory and proton bindings will be installed and available system wide with no additional per user configuration.")
 
 set (BINDING_LANGS PERL PHP PYTHON RUBY)
 
@@ -145,12 +140,14 @@ install (FILES examples/messenger/c/CMakeLists.txt
                examples/messenger/c/recv.c
          DESTINATION ${EXAMPLES_INSTALL_DIR}/messenger)
 
+install (FILES examples/include/pncompat/misc_defs.h
+               examples/include/pncompat/misc_funcs.inc
+         DESTINATION ${EXAMPLES_INSTALL_DIR}/messenger/pncompat)
+
 install (FILES examples/include/pncompat/internal/LICENSE
                examples/include/pncompat/internal/getopt.c
                examples/include/pncompat/internal/getopt.h
-               examples/include/pncompat/misc_defs.h
-               examples/include/pncompat/misc_funcs.inc
-         DESTINATION ${EXAMPLES_INSTALL_DIR}/messenger/pncompat)
+         DESTINATION ${EXAMPLES_INSTALL_DIR}/messenger/pncompat/internal)
 
 # add relevant CTest support
 find_program (MAVEN_EXE mvn DOC "Location of the maven program")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AutoOutboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AutoOutboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AutoOutboundTransformer.java
index a72198b..f62760b 100644
--- a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AutoOutboundTransformer.java
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AutoOutboundTransformer.java
@@ -24,8 +24,11 @@ import javax.jms.Message;
 */
 public class AutoOutboundTransformer extends JMSMappingOutboundTransformer {
 
+    private final JMSMappingOutboundTransformer transformer;
+
     public AutoOutboundTransformer(JMSVendor vendor) {
         super(vendor);
+        transformer = new JMSMappingOutboundTransformer(vendor);
     }
 
     @Override
@@ -39,7 +42,7 @@ public class AutoOutboundTransformer extends JMSMappingOutboundTransformer {
                 return null;
             }
         } else {
-            return JMSMappingOutboundTransformer.transform(this, msg);
+            return transformer.transform(msg);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
index 47c487c..f489a0d 100644
--- a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
@@ -36,14 +36,10 @@ import java.util.Enumeration;
 import java.util.HashMap;
 
 /**
-* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
-*/
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
 public class JMSMappingOutboundTransformer extends OutboundTransformer {
 
-    String prefixDeliveryAnnotations = "DA_";
-    String prefixMessageAnnotations= "MA_";
-    String prefixFooter = "FT_";
-
     public JMSMappingOutboundTransformer(JMSVendor vendor) {
         super(vendor);
     }
@@ -59,30 +55,37 @@ public class JMSMappingOutboundTransformer extends OutboundTransformer {
         } catch (MessageFormatException e) {
             return null;
         }
-        return transform(this, msg);
-    }
-
-    static EncodedMessage transform(JMSMappingOutboundTransformer options, Message msg) throws JMSException, UnsupportedEncodingException {
-        final JMSVendor vendor = options.vendor;
-
-        final String messageFormatKey = options.prefixVendor + "MESSAGE_FORMAT";
-        final String nativeKey = options.prefixVendor + "NATIVE";
-        final String firstAcquirerKey = options.prefixVendor + "FirstAcquirer";
-        final String prefixDeliveryAnnotationsKey = options.prefixVendor + options.prefixDeliveryAnnotations;
-        final String prefixMessageAnnotationsKey = options.prefixVendor + options.prefixMessageAnnotations;
-        final String subjectKey =  options.prefixVendor +"Subject";
-        final String contentTypeKey = options.prefixVendor +"ContentType";
-        final String contentEncodingKey = options.prefixVendor +"ContentEncoding";
-        final String replyToGroupIDKey = options.prefixVendor +"ReplyToGroupID";
-        final String prefixFooterKey = options.prefixVendor + options.prefixFooter;
+        ProtonJMessage amqp = convert(msg);
 
         long messageFormat;
         try {
-            messageFormat = msg.getLongProperty(messageFormatKey);
+            messageFormat = msg.getLongProperty(this.messageFormatKey);
         } catch (MessageFormatException e) {
             return null;
         }
 
+        ByteBuffer buffer = ByteBuffer.wrap(new byte[1024 * 4]);
+        final DroppingWritableBuffer overflow = new DroppingWritableBuffer();
+        int c = amqp.encode(new CompositeWritableBuffer(
+                new WritableBuffer.ByteBufferWrapper(buffer), overflow));
+        if( overflow.position() > 0 ) {
+            buffer = ByteBuffer.wrap(new byte[1024 * 4 + overflow.position()]);
+            c = amqp.encode(new WritableBuffer.ByteBufferWrapper(buffer));
+        }
+
+        return new EncodedMessage(messageFormat, buffer.array(), 0, c);
+    }
+
+    /**
+     * Perform the conversion between JMS Message and Proton Message without re-encoding it to array.
+     * This is needed because some frameworks may elect to do this on their own way (Netty for instance using Nettybuffers)
+     *
+     * @param msg
+     * @return
+     * @throws Exception
+     */
+    public ProtonJMessage convert(Message msg)
+            throws JMSException, UnsupportedEncodingException {
         Header header = new Header();
         Properties props=new Properties();
         HashMap<Symbol, Object> daMap = null;
@@ -213,17 +216,7 @@ public class JMSMappingOutboundTransformer extends OutboundTransformer {
         Footer footer=null;
         if( footerMap!=null ) footer = new Footer(footerMap);
 
-        ProtonJMessage amqp = (ProtonJMessage) org.apache.qpid.proton.message.Message.Factory.create(header, da, ma, props, ap, body, footer);
-
-        ByteBuffer buffer = ByteBuffer.wrap(new byte[1024*4]);
-        final DroppingWritableBuffer overflow = new DroppingWritableBuffer();
-        int c = amqp.encode(new CompositeWritableBuffer(new WritableBuffer.ByteBufferWrapper(buffer), overflow));
-        if( overflow.position() > 0 ) {
-            buffer = ByteBuffer.wrap(new byte[1024*4+overflow.position()]);
-            c = amqp.encode(new WritableBuffer.ByteBufferWrapper(buffer));
-        }
-
-        return new EncodedMessage(messageFormat, buffer.array(), 0, c);
+        return (ProtonJMessage) org.apache.qpid.proton.message.Message.Factory.create(header, da, ma, props, ap, body, footer);
     }
 
     private static String destinationAttributes(Destination destination) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java
index 87175b0..09a6e15 100644
--- a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java
@@ -26,10 +26,28 @@ import javax.jms.Message;
 public abstract class OutboundTransformer {
 
     JMSVendor vendor;
-    String prefixVendor = "JMS_AMQP_";
+    String prefixVendor;
 
-    public OutboundTransformer(JMSVendor vendor) {
+    String prefixDeliveryAnnotations = "DA_";
+    String prefixMessageAnnotations= "MA_";
+    String prefixFooter = "FT_";
+
+    String messageFormatKey;
+    String nativeKey;
+    String firstAcquirerKey;
+    String prefixDeliveryAnnotationsKey;
+    String prefixMessageAnnotationsKey;
+    String subjectKey;
+    String contentTypeKey;
+    String contentEncodingKey;
+    String replyToGroupIDKey;
+    String prefixFooterKey;
+
+
+
+   public OutboundTransformer(JMSVendor vendor) {
         this.vendor = vendor;
+        this.setPrefixVendor("JMS_AMQP_");
     }
 
     public abstract EncodedMessage transform(Message jms) throws Exception;
@@ -40,6 +58,18 @@ public abstract class OutboundTransformer {
 
     public void setPrefixVendor(String prefixVendor) {
         this.prefixVendor = prefixVendor;
+
+        messageFormatKey = prefixVendor + "MESSAGE_FORMAT";
+        nativeKey = prefixVendor + "NATIVE";
+        firstAcquirerKey = prefixVendor + "FirstAcquirer";
+        prefixDeliveryAnnotationsKey = prefixVendor + prefixDeliveryAnnotations;
+        prefixMessageAnnotationsKey = prefixVendor + prefixMessageAnnotations;
+        subjectKey =  prefixVendor +"Subject";
+        contentTypeKey = prefixVendor +"ContentType";
+        contentEncodingKey = prefixVendor +"ContentEncoding";
+        replyToGroupIDKey = prefixVendor +"ReplyToGroupID";
+        prefixFooterKey = prefixVendor + prefixFooter;
+
     }
 
     public JMSVendor getVendor() {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/examples/include/pncompat/misc_funcs.inc
----------------------------------------------------------------------
diff --git a/examples/include/pncompat/misc_funcs.inc b/examples/include/pncompat/misc_funcs.inc
index 166cc97..821aaf4 100644
--- a/examples/include/pncompat/misc_funcs.inc
+++ b/examples/include/pncompat/misc_funcs.inc
@@ -55,13 +55,14 @@ pn_timestamp_t time_now(void)
   return t.QuadPart / 10000 - 11644473600000;
 }
 #else
-#include <proton/util.h>
 #include <sys/time.h>
 #include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
 pn_timestamp_t time_now(void)
 {
   struct timeval now;
-  if (gettimeofday(&now, NULL)) pn_fatal("gettimeofday failed\n");
+  if (gettimeofday(&now, NULL)) {fprintf(stderr, "gettimeofday failed\n"); abort();}
   return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_usec / 1000);
 }
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index d1cd4c2..47ef4c6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,29 +78,28 @@
     </plugins>
   </build>
 
-  <profiles>
-    <profile>
-      <id>proton-j</id>
-      <activation>
-        <activeByDefault>true</activeByDefault>
-      </activation>
-      <modules>
-        <module>proton-j</module>
-        <module>tests</module>
-        <module>examples/messenger/java</module>
-      </modules>
-    </profile>
-    <profile>
-      <id>proton-jni</id>
-      <modules>
-        <module>proton-j/proton-api</module>
-        <!--proton-j-impl is required so we can use its EncoderImpl and DecoderImpl to generate test data -->
-        <module>proton-j/proton</module>
-        <module>tests</module>
-        <module>examples/messenger/java</module>
-      </modules>
-    </profile>
-  </profiles>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>${junit-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.9.5</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <modules>
+    <module>proton-j</module>
+    <module>contrib/proton-jms</module>
+    <module>contrib/proton-hawtdispatch</module>
+    <module>tests</module>
+    <module>examples/messenger/java</module>
+  </modules>
 
   <url>http://qpid.apache.org/proton</url>
   <scm>
@@ -112,4 +111,27 @@
   <ciManagement>
     <url>https://builds.apache.org/view/M-R/view/Qpid/job/Qpid-proton-j/</url>
   </ciManagement>
+
+  <profiles>
+    <profile>
+      <id>sources</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-source-plugin</artifactId>
+            <version>2.2.1</version>
+            <executions>
+              <execution>
+                <id>attach-sources</id>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
 </project>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 9f74b10..534933a 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -46,11 +46,17 @@ find_package(OpenSSL)
 
 find_package (PythonInterp REQUIRED)
 
-set(ssl_impl, none)
+if(PN_WINAPI)
+  set(ssl_impl schannel)
+  set(ssl_providers "'none','schannel','openssl'")
+else(PN_WINAPI)
+  set(ssl_impl, none)
+  set(ssl_providers "'none','openssl'")
+endif(PN_WINAPI)
 if (OPENSSL_FOUND)
   set(ssl_impl openssl)
-endif(OPENSSL_FOUND)
-set(SSL_IMPL ${ssl_impl} CACHE STRING "Library to use for SSL/TLS support. Valid values: 'none','openssl'")
+endif (OPENSSL_FOUND)
+set(SSL_IMPL ${ssl_impl} CACHE STRING "Library to use for SSL/TLS support. Valid values: ${ssl_providers}")
 mark_as_advanced (SSL_IMPL)
 
 configure_file (
@@ -96,7 +102,12 @@ if (SSL_IMPL STREQUAL openssl)
   include_directories ("${OPENSSL_INCLUDE_DIR}")
   set (SSL_LIB ${OPENSSL_LIBRARIES})
 else (SSL_IMPL STREQUAL openssl)
-  set (pn_driver_ssl_impl src/ssl/ssl_stub.c)
+  if (SSL_IMPL STREQUAL schannel)
+    set (pn_driver_ssl_impl src/windows/schannel.c)
+    set (SSL_LIB Crypt32.lib Secur32.lib)
+  else (SSL_IMPL STREQUAL schannel)
+    set (pn_driver_ssl_impl src/ssl/ssl_stub.c)
+  endif (SSL_IMPL STREQUAL schannel)
 endif (SSL_IMPL STREQUAL openssl)
 
 # First check whether we get clock_gettime without any special library linked
@@ -277,8 +288,13 @@ set (qpid-proton-platform
 
 set (qpid-proton-core
   src/object/object.c
+  src/object/list.c
+  src/object/map.c
+  src/object/string.c
+  src/object/iterator.c
 
   src/util.c
+  src/url.c
   src/error.c
   src/buffer.c
   src/parser.c
@@ -293,7 +309,7 @@ set (qpid-proton-core
 
   src/dispatcher/dispatcher.c
   src/engine/engine.c
-  src/engine/event.c
+  src/events/event.c
   src/transport/transport.c
   src/message/message.c
   src/sasl/sasl.c

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index 390c408..316dbe4 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -117,8 +117,13 @@ set(qpid-proton-platform
 
 set(qpid-proton-core
   ${PN_PATH}/src/object/object.c
+  ${PN_PATH}/src/object/list.c
+  ${PN_PATH}/src/object/map.c
+  ${PN_PATH}/src/object/string.c
+  ${PN_PATH}/src/object/iterator.c
 
   ${PN_PATH}/src/util.c
+  ${PN_PATH}/src/url.c
   ${PN_PATH}/src/error.c
   ${PN_PATH}/src/buffer.c
   ${PN_PATH}/src/parser.c
@@ -133,7 +138,7 @@ set(qpid-proton-core
 
   ${PN_PATH}/src/dispatcher/dispatcher.c
   ${PN_PATH}/src/engine/engine.c
-  ${PN_PATH}/src/engine/event.c
+  ${PN_PATH}/src/events/event.c
   ${PN_PATH}/src/transport/transport.c
   ${PN_PATH}/src/message/message.c
   ${PN_PATH}/src/sasl/sasl.c

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/bindings/javascript/messenger.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/messenger.js b/proton-c/bindings/javascript/messenger.js
index 8ab4e00..69267ff 100644
--- a/proton-c/bindings/javascript/messenger.js
+++ b/proton-c/bindings/javascript/messenger.js
@@ -29,7 +29,69 @@
  * is supplied that will be used as the name of the Messenger, otherwise a UUID
  * will be used. The Messenger is initialised to non-blocking mode as it makes
  * little sense to have blocking behaviour in a JavaScript implementation.
- * @classdesc This class is
+ * @classdesc The {@link proton.Messenger} class defines a high level interface for sending
+ * and receiving {@link proton.Message}. Every {@link proton.Messenger} contains a
+ * single logical queue of incoming messages and a single logical queue
+ * of outgoing messages. These messages in these queues may be destined
+ * for, or originate from, a variety of addresses.
+ * <p>
+ * The messenger interface is single-threaded.
+ * <pre>
+ * Address Syntax
+ * ==============
+ * </pre>
+ * An address has the following form:
+ * <pre>
+ *   [ amqp[s]:// ] [user[:password]@] domain [/[name]]
+ * </pre>
+ * Where domain can be one of:
+ * <pre>
+ *   host | host:port | ip | ip:port | name
+ * </pre>
+ * The following are valid examples of addresses:
+ * <pre>
+ *  - example.org
+ *  - example.org:1234
+ *  - amqp://example.org
+ *  - amqps://example.org
+ *  - example.org/incoming
+ *  - amqps://example.org/outgoing
+ *  - amqps://fred:trustno1@example.org
+ *  - 127.0.0.1:1234
+ *  - amqps://127.0.0.1:1234
+ *
+ * Sending & Receiving Messages
+ * ============================
+ * </pre>
+ * The {@link proton.Messenger} class works in conjuction with the {@link proton.Message} class.
+ * The {@link proton.Message} class is a mutable holder of message content.
+ * <p>
+ * The put method copies its Message to the outgoing queue, and may
+ * send queued messages if it can do so without blocking.  
+ * <pre>
+ *   var message = new proton.Message();
+ *   for (var i = 0; i < 3; i++) {
+ *      message.setAddress("amqp://host/queue");
+ *      message.setSubject = ("Hello World " + i);
+ *      messenger.put(message);
+ *   }
+ * </pre>
+ * Similarly, the recv method receives messages into the incoming
+ * queue. It may receive fewer than the requested number. The get method pops the
+ * eldest Message off the incoming queue and copies it into the Message
+ * object that you supply.
+ * <pre>
+ *   var message = new proton.Message();
+ *   messenger.recv(10);
+ *   while (messenger.incoming() > 0) {
+ *      messenger.get(message);
+ *      console.log(message.getSubject());
+ *   }
+ *   Hello World 0
+ *   Hello World 1
+ *   Hello World 2
+ * </pre>
+ *
  * @constructor proton.Messenger
  * @param {string} name the name of this Messenger instance.
  */
@@ -111,7 +173,7 @@ var _Messenger_ = Module['Messenger'].prototype;
  * exception and throws the exception. This method will try to use the message
  * populated in pn_messenger_error(), if present, but if not it will fall
  * back to using the basic error code rendering from pn_code().
- * @param code the error code to check.
+ * @param {number} code the error code to check.
  */
 _Messenger_._check = function(code) {
     if (code < 0) {
@@ -155,7 +217,9 @@ _Messenger_._emit = function(event, param) {
  * Checks any pending subscriptions and when a source address becomes available
  * emit a subscription event passing the Subscription that triggered the event.
  * Note that this doesn't seem to work for listen/bind style subscriptions,
- * that is to say subscriptions of the form amqp://~0.0.0.0 don't know why?
+ * that is to say subscriptions of the form amqp://~0.0.0.0, don't know why?
+ * As a workaround the subscribe call emits a subscription event immediately for
+ * peer subscriptions to the local Messenger, this *should* be OK.
  */
 _Messenger_._checkSubscriptions = function() {
     // Check for completed subscriptions, and emit subscribe event.
@@ -466,7 +530,7 @@ _Messenger_['subscribe'] = function(source) {
  * @returns {proton.Data.Long} a tracker.
  */
 _Messenger_['put'] = function(message, flush) {
-    flush = flush === false ? false : true;
+    flush = flush === false ? false : true; // Defaults to true if not explicitly specified.
     message._preEncode();
     this._checkErrors = true; // TODO improve error handling mechanism.
     this._check(_pn_messenger_put(this._messenger, message._message));
@@ -493,7 +557,7 @@ _Messenger_['put'] = function(message, flush) {
  * @returns {proton.Status} one of None, PENDING, REJECTED, or ACCEPTED.
  */
 _Messenger_['status'] = function(tracker) {
-    if (tracker == null) {
+    if (tracker == null) { // Use == not === to check for both null and undefined.
         var low = _pn_messenger_outgoing_tracker(this._messenger);
         var high = Runtime.getTempRet0();
         tracker = new Data.Long(low, high);
@@ -510,7 +574,7 @@ _Messenger_['status'] = function(tracker) {
  * @returns {boolean} true if delivery is still buffered.
  */
 _Messenger_['isBuffered'] = function(tracker) {
-    if (tracker == null) {
+    if (tracker == null) { // Use == not === to check for both null and undefined.
         var low = _pn_messenger_outgoing_tracker(this._messenger);
         var high = Runtime.getTempRet0();
         tracker = new Data.Long(low, high);
@@ -533,7 +597,7 @@ _Messenger_['settle'] = function(tracker) {
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
     // low/high pair around to methods that require a tracker.
     var flags = 0;
-    if (tracker == null) {
+    if (tracker == null) { // Use == not === to check for both null and undefined.
         var low = _pn_messenger_outgoing_tracker(this._messenger);
         var high = Runtime.getTempRet0();
         tracker = new Data.Long(low, high);
@@ -625,7 +689,6 @@ _Messenger_['get'] = function(message, decodeBinaryAsString) {
     // low/high pair around to methods that require a tracker.
     var low = _pn_messenger_incoming_tracker(this._messenger);
     var high = Runtime.getTempRet0();
-
     return new Data.Long(low, high);
 };
 
@@ -661,7 +724,7 @@ _Messenger_['accept'] = function(tracker) {
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
     // low/high pair around to methods that require a tracker.
     var flags = 0;
-    if (tracker == null) {
+    if (tracker == null) { // Use == not === to check for both null and undefined.
         var low = _pn_messenger_incoming_tracker(this._messenger);
         var high = Runtime.getTempRet0();
         tracker = new Data.Long(low, high);
@@ -685,7 +748,7 @@ _Messenger_['reject'] = function(tracker) {
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
     // low/high pair around to methods that require a tracker.
     var flags = 0;
-    if (tracker == null) {
+    if (tracker == null) { // Use == not === to check for both null and undefined.
         var low = _pn_messenger_incoming_tracker(this._messenger);
         var high = Runtime.getTempRet0();
         tracker = new Data.Long(low, high);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/bindings/perl/perl.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/perl.i b/proton-c/bindings/perl/perl.i
index ad059f3..26ca9d5 100644
--- a/proton-c/bindings/perl/perl.i
+++ b/proton-c/bindings/perl/perl.i
@@ -8,6 +8,7 @@
 #include <proton/messenger.h>
 #include <proton/ssl.h>
 #include <proton/driver_extras.h>
+#include <proton/url.h>
 %}
 
 %include <cstring.i>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/bindings/php/php.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/php/php.i b/proton-c/bindings/php/php.i
index 7cf4f5f..221aa47 100644
--- a/proton-c/bindings/php/php.i
+++ b/proton-c/bindings/php/php.i
@@ -29,11 +29,16 @@
 %header %{
 /* Include the headers needed by the code in this wrapper file */
 #include <proton/types.h>
-#include <proton/message.h>
+#include <proton/connection.h>
+#include <proton/condition.h>
+#include <proton/delivery.h>
 #include <proton/driver.h>
 #include <proton/driver_extras.h>
+#include <proton/event.h>
+#include <proton/message.h>
 #include <proton/messenger.h>
-#include <proton/ssl.h>
+#include <proton/session.h>
+#include <proton/url.h>
 
 #define zend_error_noreturn zend_error
 %}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/bindings/python/cproton.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/cproton.i b/proton-c/bindings/python/cproton.i
index 496897f..acbc4c5 100644
--- a/proton-c/bindings/python/cproton.i
+++ b/proton-c/bindings/python/cproton.i
@@ -23,6 +23,7 @@
 #include <winsock2.h>
 #endif
 #include <proton/engine.h>
+#include <proton/url.h>
 #include <proton/message.h>
 #include <proton/sasl.h>
 #include <proton/driver.h>
@@ -184,154 +185,6 @@ ssize_t pn_transport_push(pn_transport_t *transport, char *STRING, size_t LENGTH
 %}
 %ignore pn_message_data;
 
-%rename(pn_listener_set_context) wrap_pn_listener_set_context;
-%inline {
-  void wrap_pn_listener_set_context(pn_listener_t *l, PyObject *context) {
-    // don't incref context: we 'borrow' the reference - prevents
-    // reference loops.  Should be safe as the Python object must
-    // outlive the C object.
-    pn_listener_set_context(l, context);
-  }
-}
-%ignore pn_listener_set_context;
-
-%rename(pn_listener_context) wrap_pn_listener_context;
-%inline {
-  PyObject *wrap_pn_listener_context(pn_listener_t *l) {
-    PyObject *result = (PyObject *) pn_listener_context(l);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_listener_context;
-
-%rename(pn_connector_set_context) wrap_pn_connector_set_context;
-%inline {
-  void wrap_pn_connector_set_context(pn_connector_t *c, PyObject *context) {
-    // don't incref context: we 'borrow' the reference - prevents
-    // reference loops.  Should be safe as the Python object must
-    // outlive the C object.
-    pn_connector_set_context(c, context);
-  }
-}
-%ignore pn_connector_set_context;
-
-%rename(pn_connector_context) wrap_pn_connector_context;
-%inline {
-  PyObject *wrap_pn_connector_context(pn_connector_t *c) {
-    PyObject *result = (PyObject *) pn_connector_context(c);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_connector_context;
-
-%rename(pn_connection_get_context) wrap_pn_connection_get_context;
-%inline {
-  PyObject *wrap_pn_connection_get_context(pn_connection_t *c) {
-    PyObject *result = (PyObject *) pn_connection_get_context(c);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_connection_get_context;
-
-%rename(pn_connection_set_context) wrap_pn_connection_set_context;
-%inline {
-  void wrap_pn_connection_set_context(pn_connection_t *c, PyObject *context) {
-    // don't incref context: we 'borrow' the reference
-    pn_connection_set_context(c, context);
-  }
-}
-%ignore pn_connection_set_context;
-
-%rename(pn_session_get_context) wrap_pn_session_get_context;
-%inline {
-  PyObject *wrap_pn_session_get_context(pn_session_t *s) {
-    PyObject *result = (PyObject *) pn_session_get_context(s);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_session_get_context;
-
-%rename(pn_session_set_context) wrap_pn_session_set_context;
-%inline {
-  void wrap_pn_session_set_context(pn_session_t *s, PyObject *context) {
-    // don't incref context: we 'borrow' the reference
-    pn_session_set_context(s, context);
-  }
-}
-%ignore pn_session_set_context;
-
-%rename(pn_link_get_context) wrap_pn_link_get_context;
-%inline {
-  PyObject *wrap_pn_link_get_context(pn_link_t *l) {
-    PyObject *result = (PyObject *) pn_link_get_context(l);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_link_get_context;
-
-%rename(pn_link_set_context) wrap_pn_link_set_context;
-%inline {
-  void wrap_pn_link_set_context(pn_link_t *l, PyObject *context) {
-    // don't incref context: we 'borrow' the reference
-    pn_link_set_context(l, context);
-  }
-}
-%ignore pn_link_set_context;
-
-%rename(pn_delivery_get_context) wrap_pn_delivery_get_context;
-%inline {
-  PyObject *wrap_pn_delivery_get_context(pn_delivery_t *d) {
-    PyObject *result = (PyObject *) pn_delivery_get_context(d);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_delivery_get_context;
-
-%rename(pn_delivery_set_context) wrap_pn_delivery_set_context;
-%inline {
-  void wrap_pn_delivery_set_context(pn_delivery_t *d, PyObject *context) {
-    // don't incref context: we 'borrow' the reference
-    pn_delivery_set_context(d, context);
-  }
-}
-%ignore pn_delivery_set_context;
-
 ssize_t pn_data_decode(pn_data_t *data, char *STRING, size_t LENGTH);
 %ignore pn_data_decode;
 
@@ -375,5 +228,57 @@ bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZ
 int pn_ssl_get_peer_hostname(pn_ssl_t *ssl, char *OUTPUT, size_t *OUTPUT_SIZE);
 %ignore pn_ssl_get_peer_hostname;
 
+%immutable PN_PYREF;
+%inline %{
+  extern const pn_class_t *PN_PYREF;
+
+  #define CID_pn_pyref CID_pn_void
+  #define pn_pyref_new NULL
+  #define pn_pyref_initialize NULL
+  #define pn_pyref_finalize NULL
+  #define pn_pyref_free NULL
+  #define pn_pyref_hashcode pn_void_hashcode
+  #define pn_pyref_compare pn_void_compare
+  #define pn_pyref_inspect pn_void_inspect
+
+  static void pn_pyref_incref(void *object) {
+    PyObject* p = (PyObject*) object;
+    Py_XINCREF(p);
+  }
+
+  static void pn_pyref_decref(void *object) {
+    PyObject* p = (PyObject*) object;
+    Py_XDECREF(p);
+  }
+
+  static int pn_pyref_refcount(void *object) {
+    return 1;
+  }
+
+  static const pn_class_t *pn_pyref_reify(void *object) {
+    return PN_PYREF;
+  }
+
+  const pn_class_t PNI_PYREF = PN_METACLASS(pn_pyref);
+  const pn_class_t *PN_PYREF = &PNI_PYREF;
+
+  void *pn_py2void(PyObject *object) {
+    return object;
+  }
+
+  PyObject *pn_void2py(void *object) {
+    if (object) {
+      PyObject* p = (PyObject*) object;
+      Py_INCREF(p);
+      return p;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+
+  PyObject *pn_cast_pn_void(void *object) {
+    return pn_void2py(object);
+  }
+%}
 
 %include "proton/cproton.i"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/bindings/python/proton.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton.py b/proton-c/bindings/python/proton.py
index 7294d45..7324ffd 100644
--- a/proton-c/bindings/python/proton.py
+++ b/proton-c/bindings/python/proton.py
@@ -31,7 +31,8 @@ The proton APIs consist of the following classes:
 """
 
 from cproton import *
-import weakref
+
+import weakref, re, socket
 try:
   import uuid
 except ImportError:
@@ -89,6 +90,8 @@ try:
 except NameError:
   bytes = str
 
+VERSION_MAJOR = PN_VERSION_MAJOR
+VERSION_MINOR = PN_VERSION_MINOR
 API_LANGUAGE = "C"
 IMPLEMENTATION_LANGUAGE = "C"
 
@@ -866,7 +869,7 @@ class Message(object):
   def _set_inferred(self, value):
     self._check(pn_message_set_inferred(self._msg, bool(value)))
 
-  inferred = property(_is_inferred, _set_inferred,"""
+  inferred = property(_is_inferred, _set_inferred, doc="""
 The inferred flag for a message indicates how the message content
 is encoded into AMQP sections. If inferred is true then binary and
 list values in the body of the message will be encoded as AMQP DATA
@@ -2215,6 +2218,9 @@ class Condition:
                                         (self.name, self.description, self.info)
                                         if x])
 
+  def __str__(self):
+    return ": ".join(filter(None, [self.name, self.description, self.info]))
+
   def __eq__(self, o):
     if not isinstance(o, Condition): return False
     return self.name == o.name and \
@@ -2260,7 +2266,7 @@ class Connection(Endpoint):
     reference to the python instance in the context field of the C object.
     """
     if not c_conn: return None
-    py_conn = pn_connection_get_context(c_conn)
+    py_conn = pn_void2py(pn_connection_get_context(c_conn))
     if py_conn: return py_conn
     wrapper = Connection(_conn=c_conn)
     return wrapper
@@ -2271,7 +2277,7 @@ class Connection(Endpoint):
       self._conn = _conn
     else:
       self._conn = pn_connection()
-    pn_connection_set_context(self._conn, self)
+    pn_connection_set_context(self._conn, pn_py2void(self))
     self.offered_capabilities = None
     self.desired_capabilities = None
     self.properties = None
@@ -2404,7 +2410,7 @@ class Session(Endpoint):
     exists in the C Engine.
     """
     if c_ssn is None: return None
-    py_ssn = pn_session_get_context(c_ssn)
+    py_ssn = pn_void2py(pn_session_get_context(c_ssn))
     if py_ssn: return py_ssn
     wrapper = Session(c_ssn)
     return wrapper
@@ -2412,7 +2418,7 @@ class Session(Endpoint):
   def __init__(self, ssn):
     Endpoint.__init__(self)
     self._ssn = ssn
-    pn_session_set_context(self._ssn, self)
+    pn_session_set_context(self._ssn, pn_py2void(self))
     self._links = set()
     self.connection._sessions.add(self)
 
@@ -2501,7 +2507,7 @@ class Link(Endpoint):
     exists in the C Engine.
     """
     if c_link is None: return None
-    py_link = pn_link_get_context(c_link)
+    py_link = pn_void2py(pn_link_get_context(c_link))
     if py_link: return py_link
     if pn_link_is_sender(c_link):
       wrapper = Sender(c_link)
@@ -2512,7 +2518,7 @@ class Link(Endpoint):
   def __init__(self, c_link):
     Endpoint.__init__(self)
     self._link = c_link
-    pn_link_set_context(self._link, self)
+    pn_link_set_context(self._link, pn_py2void(self))
     self._deliveries = set()
     self.session._links.add(self)
 
@@ -2642,6 +2648,9 @@ class Link(Endpoint):
   def drained(self):
     return pn_link_drained(self._link)
 
+  def detach(self):
+    return pn_link_detach(self._link)
+
 class Terminus(object):
 
   UNSPECIFIED = PN_UNSPECIFIED
@@ -2879,25 +2888,27 @@ class Delivery(object):
     exists in the C Engine.
     """
     if not c_dlv: return None
-    py_dlv = pn_delivery_get_context(c_dlv)
+    py_dlv = pn_void2py(pn_delivery_get_context(c_dlv))
     if py_dlv: return py_dlv
     wrapper = Delivery(c_dlv)
     return wrapper
 
   def __init__(self, dlv):
     self._dlv = dlv
-    pn_delivery_set_context(self._dlv, self)
+    pn_delivery_set_context(self._dlv, pn_py2void(self))
     self.local = Disposition(pn_delivery_local(self._dlv), True)
     self.remote = Disposition(pn_delivery_remote(self._dlv), False)
     self.link._deliveries.add(self)
 
   def __del__(self):
-    pn_delivery_set_context(self._dlv, None)
+    self._release()
 
   def _release(self):
     """Release the underlying C Engine resource."""
     if self._dlv:
+      pn_delivery_set_context(self._dlv, pn_py2void(None))
       pn_delivery_settle(self._dlv)
+      self._dlv = None
 
   @property
   def tag(self):
@@ -3125,6 +3136,10 @@ The idle timeout of the connection (float, in seconds).
       self._ssl = SSL(self, domain, session_details)
     return self._ssl
 
+  @property
+  def condition(self):
+    return cond2obj(pn_transport_condition(self._trans))
+
 class SASLException(TransportException):
   pass
 
@@ -3319,29 +3334,33 @@ class SSLSessionDetails(object):
     return self._session_id
 
 
+wrappers = {
+  "pn_void": lambda x: pn_void2py(x),
+  "pn_pyref": lambda x: pn_void2py(x),
+  "pn_connection": lambda x: Connection._wrap_connection(pn_cast_pn_connection(x)),
+  "pn_session": lambda x: Session._wrap_session(pn_cast_pn_session(x)),
+  "pn_link": lambda x: Link._wrap_link(pn_cast_pn_link(x)),
+  "pn_delivery": lambda x: Delivery._wrap_delivery(pn_cast_pn_delivery(x)),
+  "pn_transport": lambda x: Transport(pn_cast_pn_transport(x))
+}
+
 class Collector:
 
   def __init__(self):
     self._impl = pn_collector()
     self._contexts = set()
 
+  def put(self, obj, etype):
+    pn_collector_put(self._impl, PN_PYREF, pn_py2void(obj), etype)
+
   def peek(self):
     event = pn_collector_peek(self._impl)
     if event is None:
       return None
 
-    tpi = pn_event_transport(event)
-    if tpi:
-      tp = Transport(tpi)
-    else:
-      tp = None
-    return Event(type=pn_event_type(event),
-                 category=pn_event_category(event),
-                 connection=Connection._wrap_connection(pn_event_connection(event)),
-                 session=Session._wrap_session(pn_event_session(event)),
-                 link=Link._wrap_link(pn_event_link(event)),
-                 delivery=Delivery._wrap_delivery(pn_event_delivery(event)),
-                 transport=tp)
+    clazz = pn_class_name(pn_event_class(event))
+    context = wrappers[clazz](pn_event_context(event))
+    return Event(clazz, context, pn_event_type(event))
 
   def pop(self):
     ev = self.peek()
@@ -3354,13 +3373,9 @@ class Collector:
 
 class Event:
 
-  CATEGORY_CONNECTION = PN_EVENT_CATEGORY_CONNECTION
-  CATEGORY_SESSION = PN_EVENT_CATEGORY_SESSION
-  CATEGORY_LINK = PN_EVENT_CATEGORY_LINK
-  CATEGORY_DELIVERY = PN_EVENT_CATEGORY_DELIVERY
-  CATEGORY_TRANSPORT = PN_EVENT_CATEGORY_TRANSPORT
-
   CONNECTION_INIT = PN_CONNECTION_INIT
+  CONNECTION_BOUND = PN_CONNECTION_BOUND
+  CONNECTION_UNBOUND = PN_CONNECTION_UNBOUND
   CONNECTION_OPEN = PN_CONNECTION_OPEN
   CONNECTION_CLOSE = PN_CONNECTION_CLOSE
   CONNECTION_REMOTE_OPEN = PN_CONNECTION_REMOTE_OPEN
@@ -3377,42 +3392,34 @@ class Event:
   LINK_INIT = PN_LINK_INIT
   LINK_OPEN = PN_LINK_OPEN
   LINK_CLOSE = PN_LINK_CLOSE
+  LINK_DETACH = PN_LINK_DETACH
   LINK_REMOTE_OPEN = PN_LINK_REMOTE_OPEN
   LINK_REMOTE_CLOSE = PN_LINK_REMOTE_CLOSE
+  LINK_REMOTE_DETACH = PN_LINK_REMOTE_DETACH
   LINK_FLOW = PN_LINK_FLOW
   LINK_FINAL = PN_LINK_FINAL
 
   DELIVERY = PN_DELIVERY
-  TRANSPORT = PN_TRANSPORT
 
-  def __init__(self, type, category,
-               connection, session, link, delivery, transport):
+  TRANSPORT = PN_TRANSPORT
+  TRANSPORT_ERROR = PN_TRANSPORT_ERROR
+  TRANSPORT_HEAD_CLOSED = PN_TRANSPORT_HEAD_CLOSED
+  TRANSPORT_TAIL_CLOSED = PN_TRANSPORT_TAIL_CLOSED
+  TRANSPORT_CLOSED = PN_TRANSPORT_CLOSED
+
+  def __init__(self, clazz, context, type):
+    self.clazz = clazz
+    self.context = context
     self.type = type
-    self.category = category
-    self.connection = connection
-    self.session = session
-    self.link = link
-    self.delivery = delivery
-    self.transport = transport
 
   def _popped(self, collector):
-    if self.type == Event.LINK_FINAL:
-      ctx = self.link
-    elif self.type == Event.SESSION_FINAL:
-      ctx = self.session
-    elif self.type == Event.CONNECTION_FINAL:
-      ctx = self.connection
-    else:
-      return
-
-    collector._contexts.remove(ctx)
-    ctx._released()
+    if self.type in (Event.LINK_FINAL, Event.SESSION_FINAL,
+                     Event.CONNECTION_FINAL):
+      collector._contexts.remove(self.context)
+      self.context._released()
 
   def __repr__(self):
-    objects = [self.connection, self.session, self.link, self.delivery,
-               self.transport]
-    return "%s(%s)" % (pn_event_type_name(self.type),
-                       ", ".join([str(o) for o in objects if o is not None]))
+    return "%s(%s)" % (pn_event_type_name(self.type), self.context)
 
 ###
 # Driver
@@ -3432,7 +3439,7 @@ class Connector(object):
     exists in the C Driver.
     """
     if not c_cxtr: return None
-    py_cxtr = pn_connector_context(c_cxtr)
+    py_cxtr = pn_void2py(pn_connector_context(c_cxtr))
     if py_cxtr: return py_cxtr
     wrapper = Connector(_cxtr=c_cxtr, _py_driver=py_driver)
     return wrapper
@@ -3441,14 +3448,14 @@ class Connector(object):
     self._cxtr = _cxtr
     assert(_py_driver)
     self._driver = weakref.ref(_py_driver)
-    pn_connector_set_context(self._cxtr, self)
+    pn_connector_set_context(self._cxtr, pn_py2void(self))
     self._connection = None
     self._driver()._connectors.add(self)
 
   def _release(self):
     """Release the underlying C Engine resource."""
     if self._cxtr:
-      pn_connector_set_context(self._cxtr, None)
+      pn_connector_set_context(self._cxtr, pn_py2void(None))
       pn_connector_free(self._cxtr)
       self._cxtr = None
 
@@ -3519,7 +3526,7 @@ class Listener(object):
     exists in the C Driver.
     """
     if not c_lsnr: return None
-    py_lsnr = pn_listener_context(c_lsnr)
+    py_lsnr = pn_void2py(pn_listener_context(c_lsnr))
     if py_lsnr: return py_lsnr
     wrapper = Listener(_lsnr=c_lsnr, _py_driver=py_driver)
     return wrapper
@@ -3528,13 +3535,13 @@ class Listener(object):
     self._lsnr = _lsnr
     assert(_py_driver)
     self._driver = weakref.ref(_py_driver)
-    pn_listener_set_context(self._lsnr, self)
+    pn_listener_set_context(self._lsnr, pn_py2void(self))
     self._driver()._listeners.add(self)
 
   def _release(self):
     """Release the underlying C Engine resource."""
     if self._lsnr:
-      pn_listener_set_context(self._lsnr, None);
+      pn_listener_set_context(self._lsnr, pn_py2void(None));
       pn_listener_free(self._lsnr)
       self._lsnr = None
 
@@ -3638,8 +3645,8 @@ __all__ = [
            "Messenger",
            "MessengerException",
            "ProtonException",
-           "PN_VERSION_MAJOR",
-           "PN_VERSION_MINOR",
+           "VERSION_MAJOR",
+           "VERSION_MINOR",
            "Receiver",
            "SASL",
            "Sender",
@@ -3659,3 +3666,106 @@ __all__ = [
            "timestamp",
            "ulong"
            ]
+
+
+class Url(object):
+  """
+  Simple URL parser/constructor, handles URLs of the form:
+
+    <scheme>://<user>:<password>@<host>:<port>/<path>
+
+  All components can be None if not specifeid in the URL string.
+
+  The port can be specified as a service name, e.g. 'amqp' in the
+  URL string but Url.port always gives the integer value.
+
+  @ivar scheme: Url scheme e.g. 'amqp' or 'amqps'
+  @ivar user: Username
+  @ivar password: Password
+  @ivar host: Host name, ipv6 literal or ipv4 dotted quad.
+  @ivar port: Integer port.
+  @ivar host_port: Returns host:port
+  """
+
+  AMQPS = "amqps"
+  AMQP = "amqp"
+
+  class Port(int):
+    """An integer port number that can be constructed from a service name string"""
+
+    def __new__(cls, value):
+      """@param value: integer port number or string service name."""
+      port = super(Url.Port, cls).__new__(cls, cls._port_int(value))
+      setattr(port, 'name', str(value))
+      return port
+
+    def __eq__(self, x): return str(self) == x or int(self) == x
+    def __ne__(self, x): return not self == x
+    def __str__(self): return str(self.name)
+
+    @staticmethod
+    def _port_int(value):
+      """Convert service, an integer or a service name, into an integer port number."""
+      try:
+        return int(value)
+      except ValueError:
+        try:
+          return socket.getservbyname(value)
+        except socket.error:
+          raise ValueError("Not a valid port number or service name: '%s'" % value)
+
+  def __init__(self, url=None, **kwargs):
+    """
+    @param url: URL string to parse.
+    @param kwargs: scheme, user, password, host, port, path.
+      If specified, replaces corresponding part in url string.
+    """
+    if url:
+      self._url = pn_url_parse(str(url))
+      if not self._url: raise ValueError("Invalid URL '%s'" % url)
+    else:
+      self._url = pn_url()
+    for k in kwargs:            # Let kwargs override values parsed from url
+      getattr(self, k)          # Check for invalid kwargs
+      setattr(self, k, kwargs[k])
+
+  class PartDescriptor(object):
+    def __init__(self, part):
+      self.getter = globals()["pn_url_get_%s" % part]
+      self.setter = globals()["pn_url_set_%s" % part]
+    def __get__(self, obj, type=None): return self.getter(obj._url)
+    def __set__(self, obj, value): return self.setter(obj._url, str(value))
+
+  scheme = PartDescriptor('scheme')
+  username = PartDescriptor('username')
+  password = PartDescriptor('password')
+  host = PartDescriptor('host')
+  path = PartDescriptor('path')
+
+  def _get_port(self):
+    portstr = pn_url_get_port(self._url)
+    return portstr and Url.Port(portstr)
+
+  def _set_port(self, value):
+    if value is None: pn_url_set_port(self._url, None)
+    else: pn_url_set_port(self._url, str(Url.Port(value)))
+
+  port = property(_get_port, _set_port)
+
+  def __str__(self): return pn_url_str(self._url)
+
+  def __repr__(self): return "Url(%r)" % str(self)
+
+  def __del__(self):
+    pn_url_free(self._url);
+    self._url = None
+
+  def defaults(self):
+    """
+    Fill in missing values (scheme, host or port) with defaults
+    @return: self
+    """
+    self.scheme = self.scheme or self.AMQP
+    self.host = self.host or '0.0.0.0'
+    self.port = self.port or self.Port(self.scheme)
+    return self

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/bindings/ruby/lib/qpid_proton/version.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/version.rb b/proton-c/bindings/ruby/lib/qpid_proton/version.rb
index cd30bf0..006353c 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/version.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/version.rb
@@ -21,8 +21,8 @@ module Qpid
 
   module Proton
 
-    PN_VERSION_MAJOR = Cproton::PN_VERSION_MAJOR
-    PN_VERSION_MINOR = Cproton::PN_VERSION_MINOR
+    VERSION_MAJOR = Cproton::PN_VERSION_MAJOR
+    VERSION_MINOR = Cproton::PN_VERSION_MINOR
 
   end
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/bindings/ruby/ruby.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/ruby.i b/proton-c/bindings/ruby/ruby.i
index 502fa92..1199875 100644
--- a/proton-c/bindings/ruby/ruby.i
+++ b/proton-c/bindings/ruby/ruby.i
@@ -26,8 +26,8 @@
 #include <proton/messenger.h>
 #include <proton/ssl.h>
 #include <proton/driver_extras.h>
-
 #include <proton/types.h>
+#include <proton/url.h>
 
 #include <uuid/uuid.h>
 %}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/cid.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/cid.h b/proton-c/include/proton/cid.h
new file mode 100644
index 0000000..0017020
--- /dev/null
+++ b/proton-c/include/proton/cid.h
@@ -0,0 +1,56 @@
+#ifndef PROTON_CID_H
+#define PROTON_CID_H 1
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+typedef enum {
+  CID_pn_object = 1,
+  CID_pn_void,
+  CID_pn_weakref,
+
+  CID_pn_string,
+  CID_pn_list,
+  CID_pn_map,
+  CID_pn_hash,
+
+  CID_pn_collector,
+  CID_pn_event,
+
+  CID_pn_encoder,
+  CID_pn_decoder,
+  CID_pn_data,
+
+  CID_pn_connection,
+  CID_pn_session,
+  CID_pn_link,
+  CID_pn_delivery,
+  CID_pn_transport,
+
+  CID_pn_message,
+
+  CID_pn_io,
+  CID_pn_selector,
+  CID_pn_selectable,
+
+  CID_pn_url
+} pn_cid_t;
+
+#endif /* cid.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/connection.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection.h b/proton-c/include/proton/connection.h
index 104f78f..e476689 100644
--- a/proton-c/include/proton/connection.h
+++ b/proton-c/include/proton/connection.h
@@ -23,7 +23,12 @@
  */
 
 #include <proton/import_export.h>
+#include <proton/codec.h>
+#include <proton/condition.h>
+#include <proton/error.h>
 #include <proton/type_compat.h>
+#include <proton/types.h>
+
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/cproton.i
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/cproton.i b/proton-c/include/proton/cproton.i
index 1a9ad7f..55f2237 100644
--- a/proton-c/include/proton/cproton.i
+++ b/proton-c/include/proton/cproton.i
@@ -26,6 +26,7 @@ typedef unsigned long int uint32_t;
 typedef long int int32_t;
 typedef unsigned long long int uint64_t;
 typedef long long int int64_t;
+typedef unsigned long int uintptr_t;
 
 /* Parse these interface header files to generate APIs for script languages */
 
@@ -53,6 +54,9 @@ typedef long long int int64_t;
 %include "proton/types.h"
 %ignore pn_string_vformat;
 %ignore pn_string_vaddf;
+%immutable PN_OBJECT;
+%immutable PN_VOID;
+%immutable PN_WEAKREF;
 %include "proton/object.h"
 
 %ignore pn_error_format;
@@ -1382,3 +1386,14 @@ typedef long long int int64_t;
 %ignore pn_data_vscan;
 
 %include "proton/codec.h"
+
+%inline %{
+  pn_connection_t *pn_cast_pn_connection(void *x) { return (pn_connection_t *) x; }
+  pn_session_t *pn_cast_pn_session(void *x) { return (pn_session_t *) x; }
+  pn_link_t *pn_cast_pn_link(void *x) { return (pn_link_t *) x; }
+  pn_delivery_t *pn_cast_pn_delivery(void *x) { return (pn_delivery_t *) x; }
+  pn_transport_t *pn_cast_pn_transport(void *x) { return (pn_transport_t *) x; }
+%}
+
+%include "proton/url.h"
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/driver.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/driver.h b/proton-c/include/proton/driver.h
index 128773b..6ba2863 100644
--- a/proton-c/include/proton/driver.h
+++ b/proton-c/include/proton/driver.h
@@ -24,10 +24,11 @@
 
 #include <proton/import_export.h>
 #include <proton/error.h>
-#include <proton/engine.h>
 #include <proton/sasl.h>
 #include <proton/selectable.h>
 #include <proton/ssl.h>
+#include <proton/transport.h>
+#include <proton/types.h>
 
 #ifdef __cplusplus
 extern "C" {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index c57c77d..7473132 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -77,19 +77,6 @@ extern "C" {
 typedef struct pn_event_t pn_event_t;
 
 /**
- * Related events are grouped into categories
- */
-typedef enum {
-    PN_EVENT_CATEGORY_NONE   = 0,
-    PN_EVENT_CATEGORY_CONNECTION = 0x00010000,
-    PN_EVENT_CATEGORY_SESSION = 0x00020000,
-    PN_EVENT_CATEGORY_LINK = 0x00030000,
-    PN_EVENT_CATEGORY_DELIVERY = 0x00040000,
-    PN_EVENT_CATEGORY_TRANSPORT = 0x00050000,
-    PN_EVENT_CATEGORY_COUNT = 6
-} pn_event_category_t;
-
-/**
  * An event type.
  */
 typedef enum {
@@ -104,130 +91,160 @@ typedef enum {
    * will ever be issued for a connection. Events of this type point
    * to the relevant connection.
    */
-  PN_CONNECTION_INIT = PN_EVENT_CATEGORY_CONNECTION + 1,
+  PN_CONNECTION_INIT,
+
+  /**
+   * The connection has been bound to a transport.
+   */
+  PN_CONNECTION_BOUND,
+
+  /**
+   * The connection has been unbound from its transport.
+   */
+  PN_CONNECTION_UNBOUND,
 
   /**
    * The local connection endpoint has been closed. Events of this
    * type point to the relevant connection.
    */
-  PN_CONNECTION_OPEN = PN_EVENT_CATEGORY_CONNECTION + 2,
+  PN_CONNECTION_OPEN,
 
   /**
    * The remote endpoint has opened the connection. Events of this
    * type point to the relevant connection.
    */
-  PN_CONNECTION_REMOTE_OPEN = PN_EVENT_CATEGORY_CONNECTION + 3,
+  PN_CONNECTION_REMOTE_OPEN,
 
   /**
    * The local connection endpoint has been closed. Events of this
    * type point to the relevant connection.
    */
-  PN_CONNECTION_CLOSE = PN_EVENT_CATEGORY_CONNECTION + 4,
+  PN_CONNECTION_CLOSE,
 
   /**
    *  The remote endpoint has closed the connection. Events of this
    *  type point to the relevant connection.
    */
-  PN_CONNECTION_REMOTE_CLOSE = PN_EVENT_CATEGORY_CONNECTION + 5,
+  PN_CONNECTION_REMOTE_CLOSE,
 
   /**
    * The connection has been freed and any outstanding processing has
    * been completed. This is the final event that will ever be issued
    * for a connection.
    */
-  PN_CONNECTION_FINAL = PN_EVENT_CATEGORY_CONNECTION + 6,
+  PN_CONNECTION_FINAL,
 
   /**
    * The session has been created. This is the first event that will
    * ever be issued for a session.
    */
-  PN_SESSION_INIT = PN_EVENT_CATEGORY_SESSION + 1,
+  PN_SESSION_INIT,
 
   /**
    * The local session endpoint has been opened. Events of this type
    * point ot the relevant session.
    */
-  PN_SESSION_OPEN = PN_EVENT_CATEGORY_SESSION + 2,
+  PN_SESSION_OPEN,
 
   /**
    * The remote endpoint has opened the session. Events of this type
    * point to the relevant session.
    */
-  PN_SESSION_REMOTE_OPEN = PN_EVENT_CATEGORY_SESSION + 3,
+  PN_SESSION_REMOTE_OPEN,
 
   /**
    * The local session endpoint has been closed. Events of this type
    * point ot the relevant session.
    */
-  PN_SESSION_CLOSE = PN_EVENT_CATEGORY_SESSION + 4,
+  PN_SESSION_CLOSE,
 
   /**
    * The remote endpoint has closed the session. Events of this type
    * point to the relevant session.
    */
-  PN_SESSION_REMOTE_CLOSE = PN_EVENT_CATEGORY_SESSION + 5,
+  PN_SESSION_REMOTE_CLOSE,
 
   /**
    * The session has been freed and any outstanding processing has
    * been completed. This is the final event that will ever be issued
    * for a session.
    */
-  PN_SESSION_FINAL = PN_EVENT_CATEGORY_SESSION + 6,
+  PN_SESSION_FINAL,
 
   /**
    * The link has been created. This is the first event that will ever
    * be issued for a link.
    */
-  PN_LINK_INIT = PN_EVENT_CATEGORY_LINK + 1,
+  PN_LINK_INIT,
 
   /**
    * The local link endpoint has been opened. Events of this type
    * point ot the relevant link.
    */
-  PN_LINK_OPEN = PN_EVENT_CATEGORY_LINK + 2,
+  PN_LINK_OPEN,
 
   /**
    * The remote endpoint has opened the link. Events of this type
    * point to the relevant link.
    */
-  PN_LINK_REMOTE_OPEN = PN_EVENT_CATEGORY_LINK + 3,
+  PN_LINK_REMOTE_OPEN,
 
   /**
    * The local link endpoint has been closed. Events of this type
    * point ot the relevant link.
    */
-  PN_LINK_CLOSE = PN_EVENT_CATEGORY_LINK + 4,
+  PN_LINK_CLOSE,
 
   /**
    * The remote endpoint has closed the link. Events of this type
    * point to the relevant link.
    */
-  PN_LINK_REMOTE_CLOSE = PN_EVENT_CATEGORY_LINK + 5,
+  PN_LINK_REMOTE_CLOSE,
+
+  /**
+   * The local link endpoint has been detached. Events of this type
+   * point to the relevant link.
+   */
+  PN_LINK_DETACH,
+
+  /**
+   * The remote endpoint has detached the link. Events of this type
+   * point to the relevant link.
+   */
+  PN_LINK_REMOTE_DETACH,
 
   /**
    * The flow control state for a link has changed. Events of this
    * type point to the relevant link.
    */
-  PN_LINK_FLOW = PN_EVENT_CATEGORY_LINK + 6,
+  PN_LINK_FLOW,
 
   /**
    * The link has been freed and any outstanding processing has been
    * completed. This is the final event that will ever be issued for a
    * link. Events of this type point to the relevant link.
    */
-  PN_LINK_FINAL = PN_EVENT_CATEGORY_LINK + 7,
+  PN_LINK_FINAL,
 
   /**
    * A delivery has been created or updated. Events of this type point
    * to the relevant delivery.
    */
-  PN_DELIVERY = PN_EVENT_CATEGORY_DELIVERY + 1,
+  PN_DELIVERY,
 
   /**
    * The transport has new data to read and/or write. Events of this
    * type point to the relevant transport.
    */
-  PN_TRANSPORT = PN_EVENT_CATEGORY_TRANSPORT + 1
+  PN_TRANSPORT,
+
+  PN_TRANSPORT_ERROR,
+
+  PN_TRANSPORT_HEAD_CLOSED,
+
+  PN_TRANSPORT_TAIL_CLOSED,
+
+  PN_TRANSPORT_CLOSED
 
 } pn_event_type_t;
 
@@ -257,6 +274,26 @@ PN_EXTERN pn_collector_t *pn_collector(void);
 PN_EXTERN void pn_collector_free(pn_collector_t *collector);
 
 /**
+ * Place a new event on a collector.
+ *
+ * This operation will create a new event of the given type and
+ * context and return a pointer to the newly created event. In some
+ * cases an event of the given type and context can be elided. When
+ * this happens, this operation will return a NULL pointer.
+ *
+ * @param[in] collector a collector object
+ * @param[in] type the event type
+ * @param[in] context the event context
+ *
+ * @return a pointer to the newly created event or NULL if the event
+ *         was elided
+ */
+
+PN_EXTERN pn_event_t *pn_collector_put(pn_collector_t *collector,
+                                       const pn_class_t *clazz, void *context,
+                                       pn_event_type_t type);
+
+/**
  * Access the head event contained by a collector.
  *
  * This operation will continue to return the same event until it is
@@ -286,12 +323,12 @@ PN_EXTERN bool pn_collector_pop(pn_collector_t *collector);
 PN_EXTERN pn_event_type_t pn_event_type(pn_event_t *event);
 
 /**
- * Get the category an event belongs to.
+ * Get the class associated with the event context.
  *
  * @param[in] event an event object
- * @return the category the event belongs to
+ * @return the class associated with the event context
  */
-PN_EXTERN pn_event_category_t pn_event_category(pn_event_t *event);
+PN_EXTERN const pn_class_t *pn_event_class(pn_event_t *event);
 
 /**
  * Get the context associated with an event.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/link.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/link.h b/proton-c/include/proton/link.h
index 8c5f82c..b2fa4b9 100644
--- a/proton-c/include/proton/link.h
+++ b/proton-c/include/proton/link.h
@@ -249,6 +249,13 @@ PN_EXTERN void pn_link_open(pn_link_t *link);
 PN_EXTERN void pn_link_close(pn_link_t *link);
 
 /**
+ * Detach a link.
+ *
+ * @param[in] link a link object
+ */
+PN_EXTERN void pn_link_detach(pn_link_t *link);
+
+/**
  * Access the locally defined source definition for a link.
  *
  * The pointer returned by this operation is valid until the link

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/messenger.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/messenger.h b/proton-c/include/proton/messenger.h
index 4d59989..6ef684f 100644
--- a/proton-c/include/proton/messenger.h
+++ b/proton-c/include/proton/messenger.h
@@ -25,6 +25,11 @@
 #include <proton/import_export.h>
 #include <proton/message.h>
 #include <proton/selectable.h>
+#include <proton/condition.h>
+#include <proton/terminus.h>
+#include <proton/link.h>
+#include <proton/transport.h>
+#include <proton/ssl.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -468,6 +473,32 @@ PN_EXTERN bool pn_messenger_stopped(pn_messenger_t *messenger);
 PN_EXTERN pn_subscription_t *pn_messenger_subscribe(pn_messenger_t *messenger, const char *source);
 
 /**
+ * Subscribes a messenger to messages from the specified source with the given
+ * timeout for the subscription's lifetime.
+ *
+ * @param[in] messenger the messenger to subscribe
+ * @param[in] source
+ * @param[in] timeout the maximum time to keep the subscription alive once the
+ *            link is closed.
+ * @return a subscription
+ */
+PN_EXTERN pn_subscription_t *
+pn_messenger_subscribe_ttl(pn_messenger_t *messenger, const char *source,
+                           pn_seconds_t timeout);
+
+/**
+ * Get a link based on link name and whether the link is a sender or receiver
+ *
+ * @param[in] messenger the messenger to get the link from
+ * @param[in] address the link address that identifies the link to receive
+ * @param[in] sender true if the link is a sender, false if the link is a
+ *            receiver
+ * @return a link, or NULL if no link matches the address / sender parameters
+ */
+PN_EXTERN pn_link_t *pn_messenger_get_link(pn_messenger_t *messenger,
+                                           const char *address, bool sender);
+
+/**
  * Get a subscription's application context.
  *
  * See ::pn_subscription_set_context().
@@ -519,6 +550,20 @@ PN_EXTERN int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg);
 PN_EXTERN pn_status_t pn_messenger_status(pn_messenger_t *messenger, pn_tracker_t tracker);
 
 /**
+ * Get delivery information about a delivery.
+ *
+ * Returns the delivery information associated with the supplied tracker.
+ * This may return NULL if the tracker has fallen outside the
+ * incoming/outgoing tracking windows of the messenger.
+ *
+ * @param[in] messenger the messenger
+ * @param[in] tracker the tracker identifying the delivery
+ * @return a pn_delivery_t representing the delivery.
+ */
+PN_EXTERN pn_delivery_t *pn_messenger_delivery(pn_messenger_t *messenger,
+                                               pn_tracker_t tracker);
+
+/**
  * Check if the delivery associated with a given tracker is still
  * waiting to be sent.
  *
@@ -752,6 +797,16 @@ PN_EXTERN int pn_messenger_accept(pn_messenger_t *messenger, pn_tracker_t tracke
 PN_EXTERN int pn_messenger_reject(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
 
 /**
+ * Get  link for the message referenced by the given tracker.
+ *
+ * @param[in] messenger a messenger object
+ * @param[in] tracker a tracker object
+ * @return a pn_link_t or NULL if the link could not be determined.
+ */
+PN_EXTERN pn_link_t *pn_messenger_tracker_link(pn_messenger_t *messenger,
+                                               pn_tracker_t tracker);
+
+/**
  * Get the number of messages in the outgoing message queue of a
  * messenger.
  *
@@ -900,6 +955,79 @@ PN_EXTERN pn_timestamp_t pn_messenger_deadline(pn_messenger_t *messenger);
  * @}
  */
 
+#define PN_FLAGS_CHECK_ROUTES                                                  \
+  (0x1) /** Messenger flag to indicate that a call                             \
+            to pn_messenger_start should check that                            \
+            any defined routes are valid */
+
+/** Sets control flags to enable additional function for the Messenger.
+ *
+ * @param[in] messenger the messenger
+ * @param[in] flags 0 or PN_FLAGS_CHECK_ROUTES
+ *
+ * @return an error code of zero if there is no error
+ */
+PN_EXTERN int pn_messenger_set_flags(pn_messenger_t *messenger,
+                                     const int flags);
+
+/** Gets the flags for a Messenger.
+ *
+ * @param[in] messenger the messenger
+ * @return The flags set for the messenger
+ */
+PN_EXTERN int pn_messenger_get_flags(pn_messenger_t *messenger);
+
+/**
+ * Set the local sender settle mode for the underlying link.
+ *
+ * @param[in] messenger the messenger
+ * @param[in] mode the sender settle mode
+ */
+PN_EXTERN int pn_messenger_set_snd_settle_mode(pn_messenger_t *messenger,
+                                               const pn_snd_settle_mode_t mode);
+
+/**
+ * Set the local receiver settle mode for the underlying link.
+ *
+ * @param[in] messenger the messenger
+ * @param[in] mode the receiver settle mode
+ */
+PN_EXTERN int pn_messenger_set_rcv_settle_mode(pn_messenger_t *messenger,
+                                               const pn_rcv_settle_mode_t mode);
+
+/**
+ * Set the tracer associated with a messenger.
+ *
+ * @param[in] messenger a messenger object
+ * @param[in] tracer the tracer callback
+ */
+PN_EXTERN void pn_messenger_set_tracer(pn_messenger_t *messenger,
+                                       pn_tracer_t tracer);
+
+/**
+ * Gets the remote idle timeout for the specified remote service address
+ *
+ * @param[in] messenger a messenger object
+ * @param[in] address of remote service whose idle timeout is required
+ * @return the timeout in milliseconds or -1 if an error occurs
+ */
+PN_EXTERN pn_millis_t
+    pn_messenger_get_remote_idle_timeout(pn_messenger_t *messenger,
+                                         const char *address);
+
+/**
+ * Sets the SSL peer authentiacation mode required when a trust
+ * certificate is used.
+ *
+ * @param[in] messenger a messenger object
+ * @param[in] mode the mode required (see pn_ssl_verify_mode_t
+ *             enum for valid values)
+ * @return 0 if successful or -1 if an error occurs
+ */
+PN_EXTERN int
+pn_messenger_set_ssl_peer_authentication_mode(pn_messenger_t *messenger,
+                                              const pn_ssl_verify_mode_t mode);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/object.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/object.h b/proton-c/include/proton/object.h
index 9f6e63c..b8ee7d6 100644
--- a/proton-c/include/proton/object.h
+++ b/proton-c/include/proton/object.h
@@ -22,6 +22,7 @@
  *
  */
 
+#include <proton/cid.h>
 #include <proton/types.h>
 #include <stdarg.h>
 #include <proton/type_compat.h>
@@ -35,40 +36,93 @@ extern "C" {
 typedef uintptr_t pn_handle_t;
 typedef intptr_t pn_shandle_t;
 
+typedef struct pn_class_t pn_class_t;
+typedef struct pn_string_t pn_string_t;
 typedef struct pn_list_t pn_list_t;
 typedef struct pn_map_t pn_map_t;
 typedef struct pn_hash_t pn_hash_t;
-typedef struct pn_string_t pn_string_t;
 typedef void *(*pn_iterator_next_t)(void *state);
 typedef struct pn_iterator_t pn_iterator_t;
 
-typedef struct {
+struct pn_class_t {
   const char *name;
+  const pn_cid_t cid;
+  void *(*newinst)(const pn_class_t *, size_t);
   void (*initialize)(void *);
+  void (*incref)(void *);
+  void (*decref)(void *);
+  int (*refcount)(void *);
   void (*finalize)(void *);
+  void (*free)(void *);
+  const pn_class_t *(*reify)(void *);
   uintptr_t (*hashcode)(void *);
   intptr_t (*compare)(void *, void *);
   int (*inspect)(void *, pn_string_t *);
-} pn_class_t;
+};
+
+PN_EXTERN extern const pn_class_t *PN_OBJECT;
+PN_EXTERN extern const pn_class_t *PN_VOID;
+PN_EXTERN extern const pn_class_t *PN_WEAKREF;
 
 #define PN_CLASS(PREFIX) {                      \
     #PREFIX,                                    \
+    CID_ ## PREFIX,                             \
+    pn_object_new,                              \
+    PREFIX ## _initialize,                      \
+    pn_object_incref,                           \
+    pn_object_decref,                           \
+    pn_object_refcount,                         \
+    PREFIX ## _finalize,                        \
+    pn_object_free,                             \
+    pn_object_reify,                            \
+    PREFIX ## _hashcode,                        \
+    PREFIX ## _compare,                         \
+    PREFIX ## _inspect                          \
+}
+
+#define PN_METACLASS(PREFIX) {                  \
+    #PREFIX,                                    \
+    CID_ ## PREFIX,                             \
+    PREFIX ## _new,                             \
     PREFIX ## _initialize,                      \
+    PREFIX ## _incref,                          \
+    PREFIX ## _decref,                          \
+    PREFIX ## _refcount,                        \
     PREFIX ## _finalize,                        \
+    PREFIX ## _free,                            \
+    PREFIX ## _reify,                           \
     PREFIX ## _hashcode,                        \
     PREFIX ## _compare,                         \
     PREFIX ## _inspect                          \
 }
 
-PN_EXTERN void *pn_new(size_t size, const pn_class_t* clazz);
-PN_EXTERN void *pn_new2(size_t size, const pn_class_t* clazz, void *from);
-PN_EXTERN void pn_initialize(void *object, const pn_class_t *clazz);
+PN_EXTERN pn_cid_t pn_class_id(const pn_class_t *clazz);
+PN_EXTERN const char *pn_class_name(const pn_class_t *clazz);
+PN_EXTERN void *pn_class_new(const pn_class_t *clazz, size_t size);
+PN_EXTERN void *pn_class_incref(const pn_class_t *clazz, void *object);
+PN_EXTERN int pn_class_refcount(const pn_class_t *clazz, void *object);
+PN_EXTERN int pn_class_decref(const pn_class_t *clazz, void *object);
+PN_EXTERN void pn_class_free(const pn_class_t *clazz, void *object);
+PN_EXTERN const pn_class_t *pn_class_reify(const pn_class_t *clazz, void *object);
+PN_EXTERN uintptr_t pn_class_hashcode(const pn_class_t *clazz, void *object);
+PN_EXTERN intptr_t pn_class_compare(const pn_class_t *clazz, void *a, void *b);
+PN_EXTERN bool pn_class_equals(const pn_class_t *clazz, void *a, void *b);
+PN_EXTERN int pn_class_inspect(const pn_class_t *clazz, void *object, pn_string_t *dst);
+
+PN_EXTERN uintptr_t pn_void_hashcode(void *object);
+PN_EXTERN intptr_t pn_void_compare(void *a, void *b);
+PN_EXTERN int pn_void_inspect(void *object, pn_string_t *dst);
+
+PN_EXTERN void *pn_object_new(const pn_class_t *clazz, size_t size);
+PN_EXTERN const pn_class_t *pn_object_reify(void *object);
+PN_EXTERN void pn_object_incref(void *object);
+PN_EXTERN int pn_object_refcount(void *object);
+PN_EXTERN void pn_object_decref(void *object);
+PN_EXTERN void pn_object_free(void *object);
+
 PN_EXTERN void *pn_incref(void *object);
-PN_EXTERN void *pn_incref2(void *object, void *from);
-PN_EXTERN void pn_decref(void *object);
-PN_EXTERN void pn_decref2(void *object, void *from);
+PN_EXTERN int pn_decref(void *object);
 PN_EXTERN int pn_refcount(void *object);
-PN_EXTERN void pn_finalize(void *object);
 PN_EXTERN void pn_free(void *object);
 PN_EXTERN const pn_class_t *pn_class(void* object);
 PN_EXTERN uintptr_t pn_hashcode(void *object);
@@ -78,7 +132,7 @@ PN_EXTERN int pn_inspect(void *object, pn_string_t *dst);
 
 #define PN_REFCOUNT (0x1)
 
-PN_EXTERN pn_list_t *pn_list(size_t capacity, int options);
+PN_EXTERN pn_list_t *pn_list(const pn_class_t *clazz, size_t capacity);
 PN_EXTERN size_t pn_list_size(pn_list_t *list);
 PN_EXTERN void *pn_list_get(pn_list_t *list, int index);
 PN_EXTERN void pn_list_set(pn_list_t *list, int index, void *value);
@@ -92,7 +146,8 @@ PN_EXTERN void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter);
 #define PN_REFCOUNT_KEY (0x2)
 #define PN_REFCOUNT_VALUE (0x4)
 
-PN_EXTERN pn_map_t *pn_map(size_t capacity, float load_factor, int options);
+PN_EXTERN pn_map_t *pn_map(const pn_class_t *key, const pn_class_t *value,
+                           size_t capacity, float load_factor);
 PN_EXTERN size_t pn_map_size(pn_map_t *map);
 PN_EXTERN int pn_map_put(pn_map_t *map, void *key, void *value);
 PN_EXTERN void *pn_map_get(pn_map_t *map, void *key);
@@ -102,7 +157,7 @@ PN_EXTERN pn_handle_t pn_map_next(pn_map_t *map, pn_handle_t entry);
 PN_EXTERN void *pn_map_key(pn_map_t *map, pn_handle_t entry);
 PN_EXTERN void *pn_map_value(pn_map_t *map, pn_handle_t entry);
 
-PN_EXTERN pn_hash_t *pn_hash(size_t capacity, float load_factor, int options);
+PN_EXTERN pn_hash_t *pn_hash(const pn_class_t *clazz, size_t capacity, float load_factor);
 PN_EXTERN size_t pn_hash_size(pn_hash_t *hash);
 PN_EXTERN int pn_hash_put(pn_hash_t *hash, uintptr_t key, void *value);
 PN_EXTERN void *pn_hash_get(pn_hash_t *hash, uintptr_t key);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/sasl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/sasl.h b/proton-c/include/proton/sasl.h
index 1f132e6..84ddf10 100644
--- a/proton-c/include/proton/sasl.h
+++ b/proton-c/include/proton/sasl.h
@@ -25,7 +25,7 @@
 #include <proton/import_export.h>
 #include <sys/types.h>
 #include <proton/type_compat.h>
-#include <proton/engine.h>
+#include <proton/types.h>
 
 #ifdef __cplusplus
 extern "C" {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/ssl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/ssl.h b/proton-c/include/proton/ssl.h
index cf5061d..013478e 100644
--- a/proton-c/include/proton/ssl.h
+++ b/proton-c/include/proton/ssl.h
@@ -25,7 +25,7 @@
 #include <proton/import_export.h>
 #include <sys/types.h>
 #include <proton/type_compat.h>
-#include <proton/engine.h>
+#include <proton/types.h>
 
 #ifdef __cplusplus
 extern "C" {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/transport.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/transport.h b/proton-c/include/proton/transport.h
index abe2853..e479188 100644
--- a/proton-c/include/proton/transport.h
+++ b/proton-c/include/proton/transport.h
@@ -24,6 +24,7 @@
 
 #include <proton/import_export.h>
 #include <proton/type_compat.h>
+#include <proton/condition.h>
 #include <stddef.h>
 #include <sys/types.h>
 
@@ -103,20 +104,18 @@ PN_EXTERN pn_transport_t *pn_transport(void);
 PN_EXTERN void pn_transport_free(pn_transport_t *transport);
 
 /**
- * Get additional error information associated with the transport.
+ * Get additional information about the condition of the transport.
  *
- * Whenever a transport operation fails (i.e. returns an error code),
- * additional error details can be obtained using this function. The
- * error object that is returned may also be used to clear the error
- * condition.
+ * When a PN_TRANSPORT_ERROR event occurs, this operation can be used
+ * to access the details of the error condtion.
  *
  * The pointer returned by this operation is valid until the
  * transport object is freed.
  *
  * @param[in] transport the transport object
- * @return the transport's error object
+ * @return the transport's condition object
  */
-PN_EXTERN pn_error_t *pn_transport_error(pn_transport_t *transport);
+PN_EXTERN pn_condition_t *pn_transport_condition(pn_transport_t *transport);
 
 /**
  * Binds the transport to an AMQP connection.
@@ -485,6 +484,14 @@ PN_EXTERN uint64_t pn_transport_get_frames_output(const pn_transport_t *transpor
  */
 PN_EXTERN uint64_t pn_transport_get_frames_input(const pn_transport_t *transport);
 
+/** Access the AMQP Connection associated with the transport.
+ *
+ * @param[in] transport a transport object
+ * @return the connection context for the transport, or NULL if
+ *         none
+ */
+PN_EXTERN pn_connection_t *pn_transport_connection(pn_transport_t *transport);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/url.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/url.h b/proton-c/include/proton/url.h
new file mode 100644
index 0000000..9731f56
--- /dev/null
+++ b/proton-c/include/proton/url.h
@@ -0,0 +1,98 @@
+#ifndef PROTON_URL_H
+#define PROTON_URL_H
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/import_export.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** @file
+ * URL API for parsing URLs.
+ *
+ * @defgroup url URL
+ * @{
+ */
+
+/** A parsed URL */
+typedef struct pn_url_t pn_url_t;
+
+/** Create an empty URL */
+PN_EXTERN pn_url_t *pn_url(void);
+
+/** Parse a string URL as a pn_url_t.
+ *@param[in] url A URL string.
+ *@return The parsed pn_url_t or NULL if url is not a valid URL string.
+ */
+PN_EXTERN pn_url_t *pn_url_parse(const char *url);
+
+/** Free a URL */
+PN_EXTERN void pn_url_free(pn_url_t *url);
+
+/** Clear the contents of the URL. */
+PN_EXTERN void pn_url_clear(pn_url_t *url);
+
+/**
+ * Return the string form of a URL.
+ *
+ *  The returned string is owned by the pn_url_t and will become invalid if it
+ *  is modified.
+ */
+PN_EXTERN const char *pn_url_str(pn_url_t *url);
+
+/**
+ *@name Getters for parts of the URL.
+ *
+ *Values belong to the URL. May return NULL if the value is not set.
+ *
+ *@{
+ */
+PN_EXTERN const char *pn_url_get_scheme(pn_url_t *url);
+PN_EXTERN const char *pn_url_get_username(pn_url_t *url);
+PN_EXTERN const char *pn_url_get_password(pn_url_t *url);
+PN_EXTERN const char *pn_url_get_host(pn_url_t *url);
+PN_EXTERN const char *pn_url_get_port(pn_url_t *url);
+PN_EXTERN const char *pn_url_get_path(pn_url_t *url);
+///@}
+
+/**
+ *@name Setters for parts of the URL.
+ *
+ *Values are copied. Value can be NULL to indicate the part is not set.
+ *
+ *@{
+ */
+PN_EXTERN void pn_url_set_scheme(pn_url_t *url, const char *scheme);
+PN_EXTERN void pn_url_set_username(pn_url_t *url, const char *username);
+PN_EXTERN void pn_url_set_password(pn_url_t *url, const char *password);
+PN_EXTERN void pn_url_set_host(pn_url_t *url, const char *host);
+PN_EXTERN void pn_url_set_port(pn_url_t *url, const char *port);
+PN_EXTERN void pn_url_set_path(pn_url_t *url, const char *path);
+///@}
+
+///@}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif


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


[03/51] [abbrv] qpid-proton git commit: Add jsdoc3 support and improve inline documentation, add proton.Data.Binary class

Posted by rh...@apache.org.
Add jsdoc3 support and improve inline documentation, add proton.Data.Binary class

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1586718 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/24481358
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/24481358
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/24481358

Branch: refs/heads/master
Commit: 24481358b4d0af0ca35cad2c8c8b4cce0c0504cb
Parents: 162d5b2
Author: fadams <fa...@unknown>
Authored: Fri Apr 11 17:06:47 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Fri Apr 11 17:06:47 2014 +0000

----------------------------------------------------------------------
 proton-c/bindings/javascript/CMakeLists.txt  |  67 +-
 proton-c/bindings/javascript/binding-open.js |  21 +
 proton-c/bindings/javascript/binding.js      | 783 +++++++++++++++++-----
 tools/cmake/Modules/FindEmscripten.cmake     |   6 +-
 tools/cmake/Modules/FindNodePackages.cmake   |  61 ++
 5 files changed, 742 insertions(+), 196 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24481358/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index bfda16f..19dc0a0 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -17,14 +17,21 @@
 # under the License.
 #
  
-# This file allows cross-compiling of proton to JavaScript using emscripten (https://github.com/kripken/emscripten)
-# As it is really a cross-compilation (as opposed to a binding a la swig) the approach is rather different and
-# somewhat replicates the main build in the proton-c/CMakeLists.txt using quite a bit of "copy and paste reuse".
-# TODO refactor this file (and proton-c/CMakeLists.txt) to keep the main compilation and cross-compilation consistent.
+# This file allows cross-compiling of proton to JavaScript using emscripten
+# (https://github.com/kripken/emscripten). As it is really a cross-compilation
+# (as opposed to a binding a la swig) the approach is rather different and
+# somewhat replicates the main build in the proton-c/CMakeLists.txt using quite
+# a bit of "copy and paste reuse".
+# TODO refactor this file (and proton-c/CMakeLists.txt) to keep the main
+# compilation and cross-compilation consistent.
 
 message(STATUS "Found emscripten, using that to build JavaScript binding")
 
-# The following variables describe the target OS we are building to - Emscripten mimics the Linux platform.
+# Find and install node.js packages that we might need. We can assume that
+# node.js is installed because Emscripten has a dependency on it.
+find_package(NodePackages)
+
+# Describe the target OS we are building to - Emscripten mimics the Linux platform.
 set(CMAKE_SYSTEM_NAME Linux)
 set(CMAKE_SYSTEM_VERSION 1)
 set(CMAKE_CROSSCOMPILING TRUE)
@@ -36,8 +43,7 @@ set(CMAKE_C_COMPILER "${EMCC}")
 include(CMakeForceCompiler)
 CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang)
 
-
-# From this point we should be using emscripten compilation tools rather than default ones
+# From this point we should be using emscripten compilation tools.
 message(STATUS "emscripten compilation environment:")
 message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
 
@@ -46,10 +52,11 @@ message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
 set(PN_PATH ${CMAKE_SOURCE_DIR}/proton-c)
 
 
-# TODO the OpenSSL stuff won't work for emscripten by default. It might well be possible to compile it from
-# source using emscripten (that's the standard practice for libraries with emscripten) see the comments in
-# https://github.com/kripken/emscripten/wiki/FAQ "Q. How do I link against system libraries like SDL, boost, etc.?"
-# Though to be honest it might be more natural to simply use a TLS protected wss:// WebSocket URL.
+# TODO the OpenSSL stuff won't work for emscripten by default. It might well be
+# possible to compile it from source using emscripten (that's the standard practice
+# for libraries with emscripten) see https://github.com/kripken/emscripten/wiki/FAQ
+# "Q. How do I link against system libraries like SDL, boost, etc.?"
+# Though it might be more natural to simply use a TLS protected wss:// WebSocket URL.
 #  set(pn_driver_ssl_impl src/ssl/openssl.c)
 #  set(SSL_LIB ${OPENSSL_LIBRARIES})
 set(pn_driver_ssl_impl ${PN_PATH}/src/ssl/ssl_stub.c)
@@ -61,9 +68,10 @@ set(pn_driver_impl ${PN_PATH}/src/posix/driver.c)
 
 
 # Generate encodings.h and protocol.h
-# It may be possible to use the ones generated for the main proton-c build but qpid-proton-core has
-# a dependency on the generated files, so I'm not sure if it'll work without a command that can
-# be run as a dependency. Probably best do it this way when cross-compiling - though more copy'n'paste
+# It may be possible to use the ones generated for the main proton-c build but
+# qpid-proton-core has a dependency on the generated files, so I'm not sure if
+# it'll work without a command that can be run as a dependency. Probably best
+# do it this way when cross-compiling - though more copy'n'paste
 add_custom_command(
   OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
   COMMAND python ${PN_PATH}/env.py PYTHONPATH=${PN_PATH} python ${PN_PATH}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
@@ -80,8 +88,9 @@ add_custom_command(
 #set(COMPILE_WARNING_FLAGS "-Werror -Wall -pedantic-errors -Wno-comment -Wno-warn-absolute-paths")
 set(COMPILE_WARNING_FLAGS "-Wall -pedantic-errors -Wno-comment -Wno-warn-absolute-paths")
 
-# Explicitly set PLATFORM_DEFINITIONS to Linux ones for emscripten as we don't want to inadvertently use
-# Windows versions if we happen to be cross-compiling from a Windows platform
+# Explicitly set PLATFORM_DEFINITIONS to Linux ones for emscripten as we don't
+# want to inadvertently use Windows versions if we happen to be cross-compiling
+# from a Windows platform
 set(PLATFORM_DEFINITIONS "USE_CLOCK_GETTIME;USE_UUID_GENERATE;USE_STRERROR_R;USE_ATOLL")
 
 # TODO temporary messages - remove.
@@ -94,8 +103,9 @@ message(STATUS "PLATFORM_LIBS: ${PLATFORM_LIBS}") # can be empty for emscripten
 
 
 
-# The following is more or less a direct copy from the the main proton-c/CMakeLists.txt.
-# The main difference is prefixing paths with ${PN_PATH}/ as we can't use a relative path from this CMakeLists.txt.
+# The following is largely a copy from the the main proton-c/CMakeLists.txt.
+# The main difference is prefixing paths with ${PN_PATH}/ as we can't use a
+# relative path from this CMakeLists.txt.
 
 set(qpid-proton-platform
   ${pn_io_impl}
@@ -169,25 +179,21 @@ set_target_properties(
   )
 
 
-
+# Compile the send-async.c and recv-async.c examples into JavaScript
 add_executable(send-async.js ${PN_PATH}/../examples/messenger/c/send-async.c)
 target_link_libraries(send-async.js qpid-proton-bitcode)
 
-#add_executable(send-async.html ${PN_PATH}/../examples/messenger/c/send-async.c)
-#target_link_libraries(send-async.html qpid-proton-bitcode)
-
 add_executable(recv-async.js ${PN_PATH}/../examples/messenger/c/recv-async.c)
 target_link_libraries(recv-async.js qpid-proton-bitcode)
 
-
-
 # TODO get the patches in my-library.js pushed properly into emscripten ASAP
 #
 set_target_properties(
-  #send-async.js recv-async.js send-async.html
   send-async.js recv-async.js
   PROPERTIES
   COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
+  RUNTIME_OUTPUT_DIRECTORY examples
+  DEPENDS ws
 
   # This build shows socket messages - useful for debugging.
   #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -s SOCKET_DEBUG=1 --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js"
@@ -216,10 +222,19 @@ set_target_properties(
   # This build is optimised and minified
   #LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --pre-js
 
-  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messen
 ger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bo
 ol', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol
 ', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_m
 essenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_
 put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get
 _binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
   )
 
 
+if (NODE_JSDOC_FOUND)
+    message(STATUS "Documentation Enabled")
+    add_custom_target(docs-js COMMAND ${JSDOC_EXE}
+                      -d ${CMAKE_CURRENT_BINARY_DIR}/html
+                      ${CMAKE_CURRENT_SOURCE_DIR}/binding.js)
+    add_dependencies(docs docs-js)
+
+endif (NODE_JSDOC_FOUND)
+
 # Some hacks so check what's getting built TODO to get rid of eventually 
 #message(STATUS "qpid-proton-platform: ${qpid-proton-platform}")
 #message(STATUS "qpid-proton-core: ${qpid-proton-core}")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24481358/proton-c/bindings/javascript/binding-open.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding-open.js b/proton-c/bindings/javascript/binding-open.js
new file mode 100644
index 0000000..40e1b12
--- /dev/null
+++ b/proton-c/bindings/javascript/binding-open.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+(function() { // Start of self-calling lambda used to avoid polluting global namespace.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24481358/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index ad6340f..6559f11 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -20,24 +20,28 @@
 
 /**
  * This file provides a JavaScript wrapper around the Proton Messenger API.
- * It will be used to wrap the emscripten compiled proton-c code and minified by
+ * It will be used to wrap the emscripten compiled proton-c code and be minified by
  * the Closure compiler, so all comments will be stripped from the actual library.
- *
- * This JavaScript wrapper provides a slightly more object oriented interface which
- * abstracts the low-level emscripten based implementation details from client code.
+ * <p>
+ * This JavaScript wrapper provides a somewhat more idiomatic object oriented
+ * interface which abstracts the low-level emscripten based implementation details
+ * from client code.
+ * @file
  */
-(function() { // Start of self-calling lambda used to avoid polluting global namespace.
 
 /**
  * The Module Object is exported by emscripten for all execution platforms, we
  * use it as a namespace to allow us to selectively export only what we wish to
  * be publicly visible from this package/module. We will use the associative
  * array form for declaring exported properties to prevent the Closure compiler
- * from minifying e.g. Module['Messenger'] = ... to export the Messenger Object.
+ * from minifying e.g. <pre>Module['Messenger'] = ...</pre>
  * Exported Objects can be used in client code using the appropriate namespace:
+ * <pre>
  * proton = require("proton.js");
  * var messenger = new proton.Messenger();
  * var message = new proton.Message();
+ * </pre>
+ * @namespace proton
  */
 var Module = {
     // Prevent emscripten runtime exiting, we will be enabling network callbacks.
@@ -101,18 +105,23 @@ var Buffer = function(size) {
 /*                                                                           */
 /*****************************************************************************/
 
-// Export Status Enum, avoiding minification.
+/**
+ * Export Status Enum, avoiding minification.
+ * @enum
+ * @alias Status
+ * @memberof proton
+ */
 Module['Status'] = {
-    'UNKNOWN':  0, // PN_STATUS_UNKNOWN  The tracker is unknown.
-    'PENDING':  1, // PN_STATUS_PENDING  The message is in flight.
-                   //                    For outgoing messages, use messenger.isBuffered()
-                   //                    to see if it has been sent or not.
-    'ACCEPTED': 2, // PN_STATUS_ACCEPTED The message was accepted.
-    'REJECTED': 3, // PN_STATUS_REJECTED The message was rejected.
-    'RELEASED': 4, // PN_STATUS_RELEASED The message was released.
-    'MODIFIED': 5, // PN_STATUS_MODIFIED The message was modified.
-    'ABORTED':  6, // PN_STATUS_ABORTED  The message was aborted.
-    'SETTLED':  7  // PN_STATUS_SETTLED  The remote party has settled the message.
+    /** PN_STATUS_UNKNOWN */  'UNKNOWN':  0, // The tracker is unknown.
+    /** PN_STATUS_PENDING */  'PENDING':  1, // The message is in flight.
+                                             // For outgoing messages, use messenger.isBuffered()
+                                             // to see if it has been sent or not.
+    /** PN_STATUS_ACCEPTED */ 'ACCEPTED': 2, // The message was accepted.
+    /** PN_STATUS_REJECTED */ 'REJECTED': 3, // The message was rejected.
+    /** PN_STATUS_RELEASED */ 'RELEASED': 4, // The message was released.
+    /** PN_STATUS_MODIFIED */ 'MODIFIED': 5, // The message was modified.
+    /** PN_STATUS_ABORTED */  'ABORTED':  6, // The message was aborted.
+    /** PN_STATUS_SETTLED */  'SETTLED':  7  // The remote party has settled the message.
 };
 
 
@@ -122,17 +131,22 @@ Module['Status'] = {
 /*                                                                           */
 /*****************************************************************************/
 
-// Export Error Enum, avoiding minification.
+/**
+ * Export Error Enum, avoiding minification.
+ * @enum
+ * @alias Error
+ * @memberof proton
+ */
 Module['Error'] = {
-    'EOS':        -1, // PN_EOS
-    'ERR':        -2, // PN_ERR
-    'OVERFLOW':   -3, // PN_OVERFLOW
-    'UNDERFLOW':  -4, // PN_UNDERFLOW
-    'STATE_ERR':  -5, // PN_STATE_ERR
-    'ARG_ERR':    -6, // PN_ARG_ERR
-    'TIMEOUT':    -7, // PN_TIMEOUT
-    'INTR':       -8, // PN_INTR
-    'INPROGRESS': -9  // PN_INPROGRESS
+    /** PN_EOS */        'EOS':        -1,
+    /** PN_ERR */        'ERR':        -2,
+    /** PN_OVERFLOW */   'OVERFLOW':   -3,
+    /** PN_UNDERFLOW */  'UNDERFLOW':  -4,
+    /** PN_STATE_ERR */  'STATE_ERR':  -5,
+    /** PN_ARG_ERR */    'ARG_ERR':    -6,
+    /** PN_TIMEOUT */    'TIMEOUT':    -7,
+    /** PN_INTR */       'INTR':       -8,
+    /** PN_INPROGRESS */ 'INPROGRESS': -9
 };
 
 
@@ -142,8 +156,17 @@ Module['Error'] = {
 /*                                                                           */
 /*****************************************************************************/
 
+/**
+ * Constructs a proton.Messenger instance giving it an (optional) name. If name
+ * is supplied that will be used as the name of the Messenger, otherwise a UUID
+ * will be used. The Messenger is initialised to non-blocking mode as it makes
+ * little sense to have blocking behaviour in a JavaScript implementation.
+ * @classdesc This class is
+ * @constructor proton.Messenger
+ * @param {string} name the name of this Messenger instance.
+ */
 Module['Messenger'] = function(name) { // Messenger Constructor.
-    /**
+    /*
      * The emscripten idiom below is used in a number of places in the JavaScript
      * bindings to map JavaScript Strings to C style strings. ALLOC_STACK will
      * increase the stack and place the item there. When the stack is next restored
@@ -234,7 +257,9 @@ _Messenger_._check = function(code) {
 
 /**
  * Retrieves the name of a Messenger.
- * @return the name of the messenger.
+ * @method getName
+ * @memberof! proton.Messenger#
+ * @returns {string} the name of the messenger.
  */
 _Messenger_['getName'] = function() {
     return Pointer_stringify(_pn_messenger_name(this._messenger));
@@ -242,7 +267,9 @@ _Messenger_['getName'] = function() {
 
 /**
  * Retrieves the timeout for a Messenger.
- * @return zero because JavaScript is fundamentally non-blocking.
+ * @method getTimeout
+ * @memberof! proton.Messenger#
+ * @returns {number} zero because JavaScript is fundamentally non-blocking.
  */
 _Messenger_['getTimeout'] = function() {
     return 0;
@@ -250,40 +277,51 @@ _Messenger_['getTimeout'] = function() {
 
 /**
  * Accessor for messenger blocking mode.
- * @return false because JavaScript is fundamentally non-blocking.
+ * @method isBlocking
+ * @memberof! proton.Messenger#
+ * @returns {boolean} false because JavaScript is fundamentally non-blocking.
  */
 _Messenger_['isBlocking'] = function() {
-    return true;
+    return false;
 };
 
 /**
  * Free the Messenger. This will close all connections that are managed
  * by the Messenger. Call the stop method before destroying the Messenger.
+ * <p>
  * N.B. This method has to be called explicitly in JavaScript as we can't
  * intercept finalisers, so we need to remember to free before removing refs.
+ * @method free
+ * @memberof! proton.Messenger#
  */
 _Messenger_['free'] = function() {
     _pn_messenger_free(this._messenger);
 };
 
 /**
- * @return the most recent error message code.
+ * @method getErrno
+ * @memberof! proton.Messenger#
+ * @returns {number} the most recent error message code.
  */
 _Messenger_['getErrno'] = function() {
     return _pn_messenger_errno(this._messenger);
 };
 
 /**
- * @return the most recent error message as a String.
+ * @method getError
+ * @memberof! proton.Messenger#
+ * @returns {string} the most recent error message as a String.
  */
 _Messenger_['getError'] = function() {
     return Pointer_stringify(_pn_error_text(_pn_messenger_error(this._messenger)));
 };
 
 /**
- * Returns the size of the outgoing window that was set with
- * pn_messenger_set_outgoing_window. The default is 0.
- * @return the outgoing window.
+ * Returns the size of the outgoing window that was set with setOutgoingWindow.
+ * The default is 0.
+ * @method getOutgoingWindow
+ * @memberof! proton.Messenger#
+ * @returns {number} the outgoing window size.
  */
 _Messenger_['getOutgoingWindow'] = function() {
     return _pn_messenger_get_outgoing_window(this._messenger);
@@ -293,20 +331,24 @@ _Messenger_['getOutgoingWindow'] = function() {
  * Sets the outgoing tracking window for the Messenger. The Messenger will
  * track the remote status of this many outgoing deliveries after calling
  * send. Defaults to zero.
- *
+ * <p>
  * A Message enters this window when you call put() with the Message.
  * If your outgoing window size is n, and you call put() n+1 times, status
  * information will no longer be available for the first Message.
- * @param window the size of the tracking window in messages.
+ * @method setOutgoingWindow
+ * @memberof! proton.Messenger#
+ * @param {number} window the size of the tracking window in messages.
  */
 _Messenger_['setOutgoingWindow'] = function(window) {
     this._check(_pn_messenger_set_outgoing_window(this._messenger, window));
 };
 
 /**
- * Returns the size of the incoming window that was set with
- * pn_messenger_set_incoming_window. The default is 0.
- * @return the incoming window.
+ * Returns the size of the incoming window that was set with setIncomingWindow.
+ * The default is 0.
+ * @method getIncomingWindow
+ * @memberof! proton.Messenger#
+ * @returns {number} the incoming window size.
  */
 _Messenger_['getIncomingWindow'] = function() {
     return _pn_messenger_get_incoming_window(this._messenger);
@@ -316,13 +358,15 @@ _Messenger_['getIncomingWindow'] = function() {
  * Sets the incoming tracking window for the Messenger. The Messenger will
  * track the remote status of this many incoming deliveries after calling
  * send. Defaults to zero.
- *
+ * <p>
  * Messages enter this window only when you take them into your application
  * using get(). If your incoming window size is n, and you get() n+1 messages
  * without explicitly accepting or rejecting the oldest message, then the
  * Message that passes beyond the edge of the incoming window will be assigned
  * the default disposition of its link.
- * @param window the size of the tracking window in messages.
+ * @method setIncomingWindow
+ * @memberof! proton.Messenger#
+ * @param {number} window the size of the tracking window in messages.
  */
 _Messenger_['setIncomingWindow'] = function(window) {
     this._check(_pn_messenger_set_incoming_window(this._messenger, window));
@@ -331,6 +375,8 @@ _Messenger_['setIncomingWindow'] = function(window) {
 /**
  * Currently a no-op placeholder. For future compatibility, do not send or
  * recv messages before starting the Messenger.
+ * @method start
+ * @memberof! proton.Messenger#
  */
 _Messenger_['start'] = function() {
     this._check(_pn_messenger_start(this._messenger));
@@ -341,17 +387,23 @@ _Messenger_['start'] = function() {
  * will not send or receive messages from its internal queues. A Messenger
  * should be stopped before being discarded to ensure a clean shutdown
  * handshake occurs on any internally managed connections.
- *
+ * <p>
  * The Messenger may require some time to stop if it is busy, and in that
- * case will return PN_INPROGRESS. In that case, call isStopped to see if
- * it has fully stopped.
+ * case will return {@link proton.Error.INPROGRESS}. In that case, call isStopped
+ * to see if it has fully stopped.
+ * @method stop
+ * @memberof! proton.Messenger#
+ * @returns {@link proton.Error.INPROGRESS} if still busy.
  */
 _Messenger_['stop'] = function() {
     return this._check(_pn_messenger_stop(this._messenger));
 };
 
 /**
- * @return Returns true iff a Messenger is in the stopped state.
+ * Returns true iff a Messenger is in the stopped state.
+ * @method isStopped
+ * @memberof! proton.Messenger#
+ * @returns {boolean} true iff a Messenger is in the stopped state.
  */
 _Messenger_['isStopped'] = function() {
     return (_pn_messenger_stopped(this._messenger) > 0);
@@ -367,8 +419,10 @@ _Messenger_['isStopped'] = function() {
  * "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
  * local interface and listen for incoming messages with the last
  * variant only permitting incoming SSL connections.
- * @param source the source address we're subscribing to.
- * @return a subscription.
+ * @method subscribe
+ * @memberof! proton.Messenger#
+ * @param {string} source the source address we're subscribing to.
+ * @returns {Subscription} a subscription.
  */
 _Messenger_['subscribe'] = function(source) {
     if (!source) {
@@ -391,15 +445,17 @@ _Messenger_['subscribe'] = function(source) {
  * Messages remaining in the outgoing queue. The send call may be used to
  * block until the outgoing queue is empty. The outgoing property may be
  * used to check the depth of the outgoing queue.
- *
+ * <p>
  * When the content in a given Message object is copied to the outgoing
  * message queue, you may then modify or discard the Message object
  * without having any impact on the content in the outgoing queue.
- *
+ * <p>
  * This method returns an outgoing tracker for the Message.  The tracker
  * can be used to determine the delivery status of the Message.
- * @param message a Message to send.
- * @return a tracker.
+ * @method put
+ * @memberof! proton.Messenger#
+ * @param {proton.Message} message a Message to send.
+ * @returns {proton.Data.Long} a tracker.
  */
 _Messenger_['put'] = function(message) {
     message._preEncode();
@@ -416,8 +472,10 @@ _Messenger_['put'] = function(message) {
 
 /**
  * Gets the last known remote state of the delivery associated with the given tracker.
- * @param tracker the tracker whose status is to be retrieved.
- * @return one of None, PENDING, REJECTED, or ACCEPTED.
+ * @method status
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker whose status is to be retrieved.
+ * @returns {proton.Status} one of None, PENDING, REJECTED, or ACCEPTED.
  */
 _Messenger_['status'] = function(tracker) {
     return _pn_messenger_status(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits());
@@ -425,8 +483,10 @@ _Messenger_['status'] = function(tracker) {
 
 /**
  * Checks if the delivery associated with the given tracker is still waiting to be sent.
- * @param tracker the tracker identifying the delivery.
- * @return true if delivery is still buffered.
+ * @method isBuffered
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
+ * @returns {boolean} true if delivery is still buffered.
  */
 _Messenger_['isBuffered'] = function(tracker) {
     return (_pn_messenger_buffered(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits()) > 0);
@@ -436,7 +496,9 @@ _Messenger_['isBuffered'] = function(tracker) {
  * Frees a Messenger from tracking the status associated with a given tracker.
  * If you don't supply a tracker, all outgoing messages up to the most recent
  * will be settled.
- * @param tracker the tracker identifying the delivery.
+ * @method settle
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
  */
 _Messenger_['settle'] = function(tracker) {
 console.log("settle: not fully tested yet");
@@ -460,7 +522,9 @@ console.log("settle: not fully tested yet");
  * For JavaScript the only timeout that makes sense is 0 == do not block.
  * This method may also do I/O work other than sending and receiving messages.
  * For example, closing connections after messenger.stop() has been called.
- * @return 0 if no work to do, < 0 if error, or 1 if work was done.
+ * @method work
+ * @memberof! proton.Messenger#
+ * @returns {number} 0 if no work to do, < 0 if error, or 1 if work was done.
  */
 _Messenger_['work'] = function() {
     return _pn_messenger_work(this._messenger, 0);
@@ -469,7 +533,9 @@ _Messenger_['work'] = function() {
 /**
  * Receives up to limit messages into the incoming queue.  If no value for limit
  * is supplied, this call will receive as many messages as it can buffer internally.
- * @param limit the maximum number of messages to receive or -1 to to receive
+ * @method recv
+ * @memberof! proton.Messenger#
+ * @param {number} limit the maximum number of messages to receive or -1 to to receive
  *        as many messages as it can buffer internally.
  */
 _Messenger_['recv'] = function(limit) {
@@ -479,7 +545,9 @@ _Messenger_['recv'] = function(limit) {
 /**
  * Returns the capacity of the incoming message queue of messenger. Note this
  * count does not include those messages already available on the incoming queue.
- * @return the message queue capacity.
+ * @method receiving
+ * @memberof! proton.Messenger#
+ * @returns {number} the message queue capacity.
  */
 _Messenger_['receiving'] = function() {
     return _pn_messenger_receiving(this._messenger);
@@ -488,13 +556,14 @@ _Messenger_['receiving'] = function() {
 /**
  * Moves the message from the head of the incoming message queue into the
  * supplied message object. Any content in the message will be overwritten.
- *
+ * <p>
  * A tracker for the incoming Message is returned. The tracker can later be
  * used to communicate your acceptance or rejection of the Message.
- *
- * @param message the destination message object. If no Message object is
- *        passed, the Message popped from the head of the queue is discarded.
- * @return a tracker for the incoming Message.
+ * @method get
+ * @memberof! proton.Messenger#
+ * @param {proton.Message} message the destination message object. If no Message
+ *        object is supplied, the Message popped from the head of the queue is discarded.
+ * @returns {proton.Data.Long} a tracker for the incoming Message.
  */
 _Messenger_['get'] = function(message) {
     var impl = null;
@@ -516,15 +585,21 @@ _Messenger_['get'] = function(message) {
     var high = tempRet0;
 console.log("get low = " + low);
 console.log("get high = " + high);
+
+console.log("get asm = " + asm);
+console.log("get asm['tempRet0'] = " + asm['tempRet0']);
     return new Data.Long(low, high);
 };
 
 /**
  * Returns the Subscription of the Message returned by the most recent call
  * to get, or null if pn_messenger_get has not yet been called.
- * @return a Subscription or null if get has never been called for this Messenger.
+ * @method incomingSubscription
+ * @memberof! proton.Messenger#
+ * @returns {Subscription} a Subscription or null if get has never been called
+ *          for this Messenger.
  */
-_Messenger_['incomingSubscription'] = function() {row
+_Messenger_['incomingSubscription'] = function() {
 console.log("incomingSubscription: haven't yet proved this works yet");
 
     var subscription = _pn_messenger_incoming_subscription(this._messenger);
@@ -540,7 +615,9 @@ console.log("incomingSubscription: haven't yet proved this works yet");
  * If no tracker is supplied, then all messages that have been returned by the
  * get method are accepted, except those that have already been auto-settled
  * by passing beyond your incoming window size.
- * @param tracker the tracker identifying the delivery.
+ * @method accept
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
  */
 _Messenger_['accept'] = function(tracker) {
 console.log("accept: not fully tested yet");
@@ -563,7 +640,9 @@ console.log("accept: not fully tested yet");
  * Rejects the Message indicated by the tracker.  If no tracker is supplied,
  * all messages that have been returned by the get method are rejected, except
  * those already auto-settled by passing beyond your outgoing window size.
- * @param tracker the tracker identifying the delivery.
+ * @method reject
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
  */
 _Messenger_['reject'] = function(tracker) {
 console.log("reject: not fully tested yet");
@@ -584,7 +663,9 @@ console.log("reject: not fully tested yet");
 
 /**
  * Returns the number of messages in the outgoing message queue of a messenger.
- * @return the outgoing queue depth.
+ * @method outgoing
+ * @memberof! proton.Messenger#
+ * @returns {number} the outgoing queue depth.
  */
 _Messenger_['outgoing'] = function() {
     return _pn_messenger_outgoing(this._messenger);
@@ -592,7 +673,9 @@ _Messenger_['outgoing'] = function() {
 
 /**
  * Returns the number of messages in the incoming message queue of a messenger.
- * @return the incoming queue depth.
+ * @method incoming
+ * @memberof! proton.Messenger#
+ * @returns {number} the incoming queue depth.
  */
 _Messenger_['incoming'] = function() {
     return _pn_messenger_incoming(this._messenger);
@@ -602,8 +685,10 @@ _Messenger_['incoming'] = function() {
 
 /**
  * 
- * @param pattern a glob pattern to select messages.
- * @param address an address indicating outgoing address rewrite.
+ * @method route
+ * @memberof! proton.Messenger#
+ * @param {string} pattern a glob pattern to select messages.
+ * @param {string} address an address indicating outgoing address rewrite.
  */
 _Messenger_['route'] = function(pattern, address) {
 console.log("route: not fully tested yet");
@@ -617,17 +702,19 @@ console.log("route: not fully tested yet");
 /**
  * Similar to route(), except that the destination of the Message is determined
  * before the message address is rewritten.
- *
+ * <p>
  * The outgoing address is only rewritten after routing has been finalized. If
  * a message has an outgoing address of "amqp://0.0.0.0:5678", and a rewriting
  * rule that changes its outgoing address to "foo", it will still arrive at the
  * peer that is listening on "amqp://0.0.0.0:5678", but when it arrives there,
  * the receiver will see its outgoing address as "foo".
- *
+ * <p>
  * The default rewrite rule removes username and password from addresses
  * before they are transmitted.
- * @param pattern a glob pattern to select messages.
- * @param address an address indicating outgoing address rewrite.
+ * @method rewrite
+ * @memberof! proton.Messenger#
+ * @param {string} pattern a glob pattern to select messages.
+ * @param {string} address an address indicating outgoing address rewrite.
  */
 _Messenger_['rewrite'] = function(pattern, address) {
 console.log("rewrite: not fully tested yet");
@@ -683,10 +770,12 @@ _Messenger_['setNetworkCallback'] = function(callback) {
 /*****************************************************************************/
 
 /**
- * This class is a wrapper for Messenger's subscriptions.
+ * Constructs a Subscription instance.
+ * @classdesc This class is a wrapper for Messenger's subscriptions.
  * Subscriptions should never be *directly* instantiated by client code only via
  * Messenger.subscribe() or Messenger.incomingSubscription(), so we declare the
  * constructor in the scope of the package and don't export it via Module.
+ * @constructor Subscription                                                              
  */
 var Subscription = function(subscription) { // Subscription Constructor.
     this._subscription = subscription;
@@ -694,7 +783,9 @@ var Subscription = function(subscription) { // Subscription Constructor.
 
 /**
  * TODO Not sure exactly what pn_subscription_get_context does.
- * @return the Subscription's Context.
+ * @method getContext
+ * @memberof! Subscription#
+ * @returns the Subscription's Context.
  */
 Subscription.prototype['getContext'] = function() {
     return _pn_subscription_get_context(this._subscription);
@@ -702,6 +793,8 @@ Subscription.prototype['getContext'] = function() {
 
 /**
  * TODO Not sure exactly what pn_subscription_set_context does.
+ * @method setContext
+ * @memberof! Subscription#
  * @param context the Subscription's new Context.
  */
 Subscription.prototype['setContext'] = function(context) {
@@ -709,7 +802,9 @@ Subscription.prototype['setContext'] = function(context) {
 };
 
 /**
- * @return the Subscription's Address.
+ * @method getAddress
+ * @memberof! Subscription#
+ * @returns the Subscription's Address.
  */
 Subscription.prototype['getAddress'] = function() {
     return Pointer_stringify(_pn_subscription_address(this._subscription));
@@ -724,6 +819,11 @@ Subscription.prototype['getAddress'] = function() {
 /*                                                                           */
 /*****************************************************************************/
 
+/**
+ * Constructs a proton.Message instance.
+ * @classdesc This class is
+ * @constructor proton.Message
+ */
 Module['Message'] = function() { // Message Constructor.
     this._message = _pn_message();
 
@@ -857,29 +957,38 @@ _Message_._postDecode = function() {
 
 /**
  * Free the Message.
+ * <p>
  * N.B. This method has to be called explicitly in JavaScript as we can't
  * intercept finalisers, so we need to remember to free before removing refs.
+ * @method free
+ * @memberof! proton.Message#
  */
 _Message_['free'] = function() {
     _pn_message_free(this._message);
 };
 
 /**
- * @return the most recent error message code.
+ * @method getErrno
+ * @memberof! proton.Message#
+ * @returns {number the most recent error message code.
  */
 _Message_['getErrno'] = function() {
     return _pn_message_errno(this._message);
 };
 
 /**
- * @return the most recent error message as a String.
+ * @method getError
+ * @memberof! proton.Message#
+ * @returns {string} the most recent error message as a String.
  */
 _Message_['getError'] = function() {
     return Pointer_stringify(_pn_error_text(_pn_message_error(this._message)));
 };
 
 /**
- * @return the address of the Message.
+ * @method getAddress
+ * @memberof! proton.Message#
+ * @return {string} the address of the Message.
  */
 _Message_['getAddress'] = function() {
     return Pointer_stringify(_pn_message_get_address(this._message));
@@ -887,7 +996,9 @@ _Message_['getAddress'] = function() {
 
 /**
  * Set the address of the Message.
- * @param address the address we want to send the Message to.
+ * @method setAddress
+ * @memberof! proton.Message#
+ * @param {string} address the address we want to send the Message to.
  */
 _Message_['setAddress'] = function(address) {
     var sp = Runtime.stackSave();
@@ -896,7 +1007,9 @@ _Message_['setAddress'] = function(address) {
 };
 
 /**
- * @return the subject of the Message.
+ * @method getSubject
+ * @memberof! proton.Message#
+ * @returns {string} the subject of the Message.
  */
 _Message_['getSubject'] = function() {
     return Pointer_stringify(_pn_message_get_subject(this._message));
@@ -904,7 +1017,9 @@ _Message_['getSubject'] = function() {
 
 /**
  * Set the subject of the Message.
- * @param subject the subject we want to set for the Message.
+ * @method setSubject
+ * @memberof! proton.Message#
+ * @param {string} subject the subject we want to set for the Message.
  */
 _Message_['setSubject'] = function(subject) {
     var sp = Runtime.stackSave();
@@ -932,6 +1047,8 @@ _Message_['setSubject'] = function(subject) {
 /*****************************************************************************/
 
 /**
+ * Constructs a proton.Data instance.
+ * @classdesc
  * The Data class provides an interface for decoding, extracting, creating, and
  * encoding arbitrary AMQP data. A Data object contains a tree of AMQP values.
  * Leaf nodes in this tree correspond to scalars in the AMQP type system such as
@@ -939,19 +1056,20 @@ _Message_['setSubject'] = function(subject) {
  * values in the AMQP type system such as lists<LIST>, maps<MAP>, arrays<ARRAY>,
  * or described values<DESCRIBED>. The root node of the tree is the Data object
  * itself and can have an arbitrary number of children.
- *
+ * <p>
  * A Data object maintains the notion of the current sibling node and a current
  * parent node. Siblings are ordered within their parent. Values are accessed
  * and/or added by using the next, prev, enter, and exit methods to navigate to
  * the desired location in the tree and using the supplied variety of put* and
  * get* methods to access or add a value of the desired type.
- *
+ * <p>
  * The put* methods will always add a value after the current node in the tree.
  * If the current node has a next sibling the put* method will overwrite the value
  * on this node. If there is no current node or the current node has no next
  * sibling then one will be added. The put* methods always set the added/modified
  * node to the current node. The get* methods read the value of the current node
- * and do not change which node is current.                                                                         
+ * and do not change which node is current.
+ * @constructor proton.Data                                                                
  */
 Module['Data'] = function(data) { // Data Constructor.
     this._data = data;
@@ -971,6 +1089,8 @@ var _Data_ = Data.prototype;
  * Look-up table mapping proton-c types to the accessor method used to
  * deserialise the type. N.B. this is a simple Array and not a map because the
  * types that we get back from pn_data_type are integers from the pn_type_t enum.
+ * @property {Array<String>} GetMappings
+ * @memberof! proton.Data
  */
 Data.GetMappings = [
     'getNull',            // 0
@@ -1005,8 +1125,10 @@ Data.GetMappings = [
 
 /**
  * Test if a given Object is an Array.
- * @param o the Object that we wish to test.
- * @return true iff the Object is an Array.
+ * @method isArray
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is an Array.
  */
 Data.isArray = Array.isArray || function(o) {
 console.log("Data.isArray");
@@ -1015,8 +1137,10 @@ console.log("Data.isArray");
 
 /**
  * Test if a given Object is a Number.
- * @param o the Object that we wish to test.
- * @return true iff the Object is a Number.
+ * @method isNumber
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a Number.
  */
 Data.isNumber = function(o) {
     return typeof o === 'number' || 
@@ -1025,8 +1149,10 @@ Data.isNumber = function(o) {
 
 /**
  * Test if a given Object is a String.
- * @param o the Object that we wish to test.
- * @return true iff the Object is a String.
+ * @method isString
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a String.
  */
 Data.isString = function(o) {
     return typeof o === 'string' ||
@@ -1035,8 +1161,10 @@ Data.isString = function(o) {
 
 /**
  * Test if a given Object is a Boolean.
- * @param o the Object that we wish to test.
- * @return true iff the Object is a Boolean.
+ * @method isBoolean
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a Boolean.
  */
 Data.isBoolean = function(o) {
     return typeof o === 'boolean' ||
@@ -1048,11 +1176,15 @@ Data.isBoolean = function(o) {
 // --------------------------- proton.Data.UUID -------------------------------
 /**
  * Create a proton.Data.UUID which is a type 4 UUID.
+ * @classdesc
+ * This class represents a type 4 UUID, wich may use crypto libraries to generate
+ * the UUID if supported by the platform (e.g. node.js or a modern browser)
+ * @constructor proton.Data.UUID
  * @param u a UUID. If null a type 4 UUID is generated wich may use crypto if
  *        supported by the platform. If u is an emscripten "pointer" we copy the
  *        data from that. If u is a JavaScript Array we use it as-is. If u is a
  *        String then we try to parse that as a UUID.
- * @properties uuid is the compact array form of the UUID.
+ * @property {Array} uuid is the compact array form of the UUID.
  */
 Data['UUID'] = function(u) { // Data.UUID Constructor.
     // Helper to copy from emscriptem allocated storage into JavaScript Array.
@@ -1090,7 +1222,11 @@ Data['UUID'] = function(u) { // Data.UUID Constructor.
 };
 
 /**
- * @return the String form of a proton.Data.UUID.
+ * @method toString
+ * @memberof! proton.Data.UUID#
+ * @returns {string} the String
+ *          /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
+ *          form of a {@link proton.Data.UUID}.
  */
 Data['UUID'].prototype.toString = function() {
     if (!this.string) { // Check if we've cached the string version.
@@ -1109,8 +1245,10 @@ Data['UUID'].prototype.toString = function() {
 
 /**
  * Compare two instances of proton.Data.UUID for equality.
- * @param rhs the instance we wish to compare this instance with.
- * @return true iff the two compared instances are equal.
+ * @method equals
+ * @memberof! proton.Data.UUID#
+ * @param {proton.Data.UUID} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
  */
 Data['UUID'].prototype['equals'] = function(rhs) {
     return this.toString() === rhs.toString();
@@ -1120,7 +1258,12 @@ Data['UUID'].prototype['equals'] = function(rhs) {
 // ---------------------------- proton.Data.Symbol ---------------------------- 
 /**
  * Create a proton.Data.Symbol.
- * @param s a symbol
+ * @classdesc
+ * This class represents an AMQP Symbol. This class is necessary primarily as a
+ * way to enable us to distinguish between a native String and a Symbol in the
+ * JavaScript type system.
+ * @constructor proton.Data.Symbol
+ * @param {string} s a symbol.
  */
 Data['Symbol'] = function(s) { // Data.Symbol Constructor.
     this.value = s;
@@ -1128,7 +1271,9 @@ Data['Symbol'] = function(s) { // Data.Symbol Constructor.
 };
 
 /**
- * @return the String form of a proton.Data.Symbol.
+ * @method toString
+ * @memberof! proton.Data.Symbol#
+ * @returns {string} the String form of a {@link proton.Data.Symbol}.
  */
 Data['Symbol'].prototype.toString = Data['Symbol'].prototype.valueOf = function() {
     return this.value;
@@ -1136,8 +1281,10 @@ Data['Symbol'].prototype.toString = Data['Symbol'].prototype.valueOf = function(
 
 /**
  * Compare two instances of proton.Data.Symbol for equality.
- * @param rhs the instance we wish to compare this instance with.
- * @return true iff the two compared instances are equal.
+ * @method equals
+ * @memberof! proton.Data.Symbol#
+ * @param {proton.Data.Symbol} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
  */
 Data['Symbol'].prototype['equals'] = function(rhs) {
     return this.toString() === rhs.toString();
@@ -1146,7 +1293,15 @@ Data['Symbol'].prototype['equals'] = function(rhs) {
 
 // ----------------------------- proton.Data.Long ----------------------------- 
 /**
-
+ * Create a proton.Data.Long.
+ * @classdesc
+ * This class represents a 64 bit Integer value. It is used primarily to pass and
+ * return 64 bit Integer values to and from the emscripten compiled proton-c library.
+ * This class is needed because JavaScript cannot natively represent 64 bit
+ * Integers with sufficient accuracy.
+ * @constructor proton.Data.Long
+ * @param {number} low the least significant word.
+ * @param {number} high the most significant word.
  */
 Data.Long = function(low, high) { // Data.Long Constructor.
     this.low  = low  | 0;  // force into 32 signed bits.
@@ -1163,6 +1318,12 @@ Data.Long.MIN_VALUE = new Data.Long(0, 0x80000000 | 0);
 Data.Long.ZERO = new Data.Long(0, 0);
 Data.Long.ONE  = new Data.Long(1, 0);
 
+/**
+ * @method fromNumber
+ * @memberof! proton.Data.Long#
+ * @returns {proton.Data.Long} an instance of {@link proton.Data.Long} created
+ *          using a native JavaScript number.
+ */
 Data.Long.fromNumber = function(value) {
     if (isNaN(value) || !isFinite(value)) {
         return Data.Long.ZERO;
@@ -1179,6 +1340,12 @@ Data.Long.fromNumber = function(value) {
     }
 };
 
+/**
+ * Return the twos complement of this instance.
+ * @method negate
+ * @memberof! proton.Data.Long#
+ * @returns {proton.Data.Long} the twos complement of this instance.
+ */
 Data.Long.prototype.negate = function() {
     if (this.equals(Data.Long.MIN_VALUE)) {
         return Data.Long.MIN_VALUE;
@@ -1187,7 +1354,14 @@ Data.Long.prototype.negate = function() {
     }
 };
 
-Data.Long.prototype.add = function(other) {
+/**
+ * Add two instances of {@link proton.Data.Long}.
+ * @method add
+ * @memberof! proton.Data.Long#
+ * @param {proton.Data.Long} rhs the instance we wish to add to this instance.
+ * @returns {proton.Data.Long} the sum of this value and the rhs.
+ */
+Data.Long.prototype.add = function(rhs) {
     // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
 
     var a48 = this.high >>> 16;
@@ -1195,10 +1369,10 @@ Data.Long.prototype.add = function(other) {
     var a16 = this.low >>> 16;
     var a00 = this.low & 0xFFFF;
 
-    var b48 = other.high >>> 16;
-    var b32 = other.high & 0xFFFF;
-    var b16 = other.low >>> 16;
-    var b00 = other.low & 0xFFFF;
+    var b48 = rhs.high >>> 16;
+    var b32 = rhs.high & 0xFFFF;
+    var b16 = rhs.low >>> 16;
+    var b00 = rhs.low & 0xFFFF;
 
     var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
     c00 += a00 + b00;
@@ -1215,36 +1389,181 @@ Data.Long.prototype.add = function(other) {
     return new Data.Long((c16 << 16) | c00, (c48 << 16) | c32);
 };
 
+/**
+ * Return the complement of this instance.
+ * @method not
+ * @memberof! proton.Data.Long#
+ * @returns {proton.Data.Long} the complement of this instance.
+ */
 Data.Long.prototype.not = function() {
     return new Data.Long(~this.low, ~this.high);
 };
 
+/**
+ * Compare two instances of {@link proton.Data.Long} for equality.
+ * @method equals
+ * @memberof! proton.Data.Long#
+ * @param {proton.Data.Long} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
 Data.Long.prototype.equals = function(other) {
     return (this.high == other.high) && (this.low == other.low);
 };
 
+/**
+ * @method getHighBits
+ * @memberof! proton.Data.Long#
+ * @returns {number} the most significant word of a {@link proton.Data.Long}.
+ */
 Data.Long.prototype.getHighBits = function() {
     return this.high;
 };
 
+/**
+ * @method getLowBits
+ * @memberof! proton.Data.Long#
+ * @returns {number} the least significant word of a {@link proton.Data.Long}.
+ */
 Data.Long.prototype.getLowBits = function() {
     return this.low;
 };
 
+/**
+ * @method getLowBitsUnsigned
+ * @memberof! proton.Data.Long#
+ * @returns {number} the least significant word of a {@link proton.Data.Long}
+ *          as an unsigned value.
+ */
 Data.Long.prototype.getLowBitsUnsigned = function() {
     return (this.low >= 0) ? this.low : Data.Long.TWO_PWR_32_DBL_ + this.low;
 };
 
+/**
+ * @method toNumber
+ * @memberof! proton.Data.Long#
+ * @returns {number} a native JavaScript number (with possible loss of precision).
+ */
 Data.Long.prototype.toNumber = function() {
     return (this.high * Data.Long.TWO_PWR_32_DBL_) + this.getLowBitsUnsigned();
 };
 
+/**
+ * @method toString
+ * @memberof! proton.Data.Long#
+ * @returns {string} the String form of a {@link proton.Data.Long}.
+ */
 Data.Long.prototype.toString = function() {
     return this.high + ":" + this.getLowBitsUnsigned();
 };
 
 // ---------------------------- proton.Data.Binary ---------------------------- 
 
+/*
+    function freeBuffer() {
+        if (ptr !== 0) {
+            _free(ptr);
+        }
+    };
+
+    // Public methods
+    _public.destroy = function() {
+        freeBuffer();
+    };
+
+    _public.setSize = function(size) {
+        if (size > asize) {
+            freeBuffer();
+            ptr = _malloc(size); // Get output buffer from emscripten.
+            asize = size;
+        }
+        _public.size = size;
+    };
+
+    _public.getRaw = function() {
+        return ptr;
+    };
+
+    _public.getBuffer = function() {
+        // Get a Uint8Array view on the input buffer.
+        return new Uint8Array(HEAPU8.buffer, ptr, _public.size);
+*/
+
+/**
+ * Create a proton.Data.Binary. This constructor takes one or two parameters,
+ * size specifies the size in bytes of the Binary buffer, start is a pointer
+ * to the data in an internal data store. If start is not specified then size
+ * bytes will be allocated in the internal data store and start will point to
+ * the start of that block of data.
+ * @classdesc
+ * This class represents an AMQP Binary type. This class allows us to create and
+ * use raw binary data and map it efficiently between JavaScript client code and
+ * the underlying implementation, where all data is managed on a virtual heap.
+ * <p>
+ * Client applications should not have to care about memory management. A client
+ * should create a {@link proton.Data.Binary} specifying the required size then
+ * call getBuffer to access the underlying Uint8Array. When {@link proton.Data.putBinary}
+ * is called ownership of the bytes transfers from the Binary to the Data and
+ * putBinary can then safely call free. Conversely when receiving data a Binary
+ * may be created by {@link proton.Data.getBinary} in this case the Binary is
+ * simply a "view" onto the bytes owned by the Data instance. A client application
+ * can safely access the bytes from the view, but if it wishes to use the bytes
+ * beyond the scope of the Data instance (for example after the next
+ * {@link proton.Messenger.get} call then the client must explicitly *copy* the
+ * bytes into a new buffer via copyBuffer().
+ * @constructor proton.Data.Binary
+ * @param {number} size the size of the Binary data buffer.
+ * @param {number} start an optional data pointer to the start of the Binary data buffer.
+ */
+Data['Binary'] = function(size, start) { // Data.Binary Constructor.
+    if (start) {
+        this.free = function() {};
+    } else {
+        start = _malloc(size); // Allocate storage from emscripten heap.
+        this.free = function() {_free(start);};
+    }
+
+    this.size = size;
+    this.start = start;
+};
+
+/*
+ * Get a Uint8Array view of the data. N.B. this is just a *view* of the data,
+ * which will out of scope on the next call to {@link proton.Messenger.get}. If
+ * a client wants to retain the data then copyBuffer should be used to explicitly
+ * create a copy of the data which the client then owns to do with as it wishes.
+ * @method getBuffer
+ * @memberof! proton.Data.Binary#
+ */
+Data['Binary'].prototype['getBuffer'] = function() {
+    return new Uint8Array(HEAPU8.buffer, this.start, this.size);
+};
+
+/*
+ * Explicitly create a *copy* of the underlying binary data and present a Uint8Array
+ * view of that copy. This method should be used if a client application wishes to
+ * retain an interest in the binary data for longer than it wishes to retain an
+ * interest in say a {@link proton.Message}, if that's not the case getBuffer
+ * should be used as that avoids the need to copy the data.
+ * @method copyBuffer
+ * @memberof! proton.Data.Binary#
+ */
+Data['Binary'].prototype['copyBuffer'] = function() {
+    return new Uint8Array(new Uint8Array(HEAPU8.buffer, this.start, this.size));
+};
+
+/**
+ * Converts the {@link proton.Data.Binary} to a string. This is clearly most
+ * useful when the binary data is actually a binary representation of a string
+ * such as a C style ASCII string.
+ * @method toString
+ * @memberof! proton.Data.Binary#
+ * @returns {string} the String form of a {@link proton.Data.Binary}.
+ */
+Data['Binary'].prototype.toString = Data['Binary'].prototype.valueOf = function() {
+    // Create a native JavaScript String from the start/size information.
+    return Pointer_stringify(this.start, this.size);
+};
+
 
 // ************************* Protected methods ********************************
 
@@ -1279,14 +1598,18 @@ _Data_._check = function(code) {
 // *************************** Public methods *********************************
 
 /**
- * @return the most recent error message code.
+ * @method getErrno
+ * @memberof! proton.Data#
+ * @returns {number} the most recent error message code.
  */
 _Data_['getErrno'] = function() {
     return _pn_data_errno(this._data);
 };
 
 /**
- * @return the most recent error message as a String.
+ * @method getError
+ * @memberof! proton.Data#
+ * @returns {string} the most recent error message as a String.
  */
 _Data_['getError'] = function() {
     return Pointer_stringify(_pn_error_text(_pn_data_error(this._data)));
@@ -1294,6 +1617,8 @@ _Data_['getError'] = function() {
 
 /**
  * Clears the data object.
+ * @method clear
+ * @memberof! proton.Data#
  */
 _Data_['clear'] = function() {
     _pn_data_clear(this._data);
@@ -1303,6 +1628,8 @@ _Data_['clear'] = function() {
  * Clears current node and sets the parent to the root node.  Clearing the
  * current node sets it _before_ the first node, calling next() will advance
  * to the first node.
+ * @method rewind
+ * @memberof! proton.Data#
  */
 _Data_['rewind'] = function() {
     _pn_data_rewind(this._data);
@@ -1312,6 +1639,9 @@ _Data_['rewind'] = function() {
  * Advances the current node to its next sibling and returns its
  * type. If there is no next sibling the current node remains
  * unchanged and null is returned.
+ * @method next
+ * @memberof! proton.Data#
+ * @returns {number} the type of the next sibling or null.
  */
 _Data_['next'] = function() {
     var found = _pn_data_next(this._data);
@@ -1326,6 +1656,9 @@ _Data_['next'] = function() {
  * Advances the current node to its previous sibling and returns its
  * type. If there is no previous sibling the current node remains
  * unchanged and null is returned.
+ * @method prev
+ * @memberof! proton.Data#
+ * @returns {number} the type of the previous sibling or null.
  */
 _Data_['prev'] = function() {
     var found = _pn_data_prev(this._data);
@@ -1340,6 +1673,8 @@ _Data_['prev'] = function() {
  * Sets the parent node to the current node and clears the current node.
  * Clearing the current node sets it _before_ the first child,
  * call next() advances to the first child.
+ * @method enter
+ * @memberof! proton.Data#
  */
 _Data_['enter'] = function() {
     return (_pn_data_enter(this._data) > 0);
@@ -1348,13 +1683,18 @@ _Data_['enter'] = function() {
 /**
  * Sets the current node to the parent node and the parent node to
  * its own parent.
+ * @method exit
+ * @memberof! proton.Data#
  */
 _Data_['exit'] = function() {
     return (_pn_data_exit(this._data) > 0);
 };
 
 
-
+/**
+ * @method lookup
+ * @memberof! proton.Data#
+ */
 _Data_['lookup'] = function(name) {
     var sp = Runtime.stackSave();
     var lookup = _pn_data_lookup(this._data, allocate(intArrayFromString(name), 'i8', ALLOC_STACK));
@@ -1372,7 +1712,9 @@ _Data_['widen'] = function() {
 
 
 /**
- * @return the type of the current node.
+ * @method type
+ * @memberof! proton.Data#
+ * @returns the type of the current node or null if the type is unknown.
  */
 _Data_['type'] = function() {
     var dtype = _pn_data_type(this._data);
@@ -1388,7 +1730,7 @@ _Data_['type'] = function() {
 /**
  * Puts a list value. Elements may be filled by entering the list
  * node and putting element values.
- *
+ * <pre>
  *  data = new Data();
  *  data.putList();
  *  data.enter();
@@ -1396,6 +1738,9 @@ _Data_['type'] = function() {
  *  data.putInt(2);
  *  data.putInt(3);
  *  data.exit();
+ * </pre>
+ * @method putList
+ * @memberof! proton.Data#
  */
 _Data_['putList'] = function() {
     this._check(_pn_data_put_list(this._data));
@@ -1404,13 +1749,16 @@ _Data_['putList'] = function() {
 /**
  * Puts a map value. Elements may be filled by entering the map node
  * and putting alternating key value pairs.
- *
+ * <pre>
  *  data = new Data();
  *  data.putMap();
  *  data.enter();
  *  data.putString("key");
  *  data.putString("value");
  *  data.exit();
+ * </pre>
+ * @method putMap
+ * @memberof! proton.Data#
  */
 _Data_['putMap'] = function() {
     this._check(_pn_data_put_map(this._data));
@@ -1420,6 +1768,8 @@ _Data_['putMap'] = function() {
 
 /**
  * Puts a null value.
+ * @method putNull
+ * @memberof! proton.Data#
  */
 _Data_['putNull'] = function() {
     this._check(_pn_data_put_null(this._data));
@@ -1427,7 +1777,9 @@ _Data_['putNull'] = function() {
 
 /**
  * Puts a boolean value.
- * @param b a boolean value.
+ * @method putBoolean
+ * @memberof! proton.Data#
+ * @param {boolean} b a boolean value.
  */
 _Data_['putBoolean'] = function(b) {
     this._check(_pn_data_put_bool(this._data, b));
@@ -1435,7 +1787,9 @@ _Data_['putBoolean'] = function(b) {
 
 /**
  * Puts a unsigned byte value.
- * @param ub an integral value.
+ * @method putUnsignedByte
+ * @memberof! proton.Data#
+ * @param {number} ub an integral value.
  */
 _Data_['putUnsignedByte'] = function(ub) {
     this._check(_pn_data_put_ubyte(this._data, ub));
@@ -1443,7 +1797,9 @@ _Data_['putUnsignedByte'] = function(ub) {
 
 /**
  * Puts a signed byte value.
- * @param b an integral value.
+ * @method putByte
+ * @memberof! proton.Data#
+ * @param {number} b an integral value.
  */
 _Data_['putByte'] = function(b) {
     this._check(_pn_data_put_byte(this._data, b));
@@ -1451,7 +1807,9 @@ _Data_['putByte'] = function(b) {
 
 /**
  * Puts a unsigned short value.
- * @param us an integral value.
+ * @method putUnsignedShort
+ * @memberof! proton.Data#
+ * @param {number} us an integral value.
  */
 _Data_['putUnsignedShort'] = function(us) {
     this._check(_pn_data_put_ushort(this._data, us));
@@ -1459,7 +1817,9 @@ _Data_['putUnsignedShort'] = function(us) {
 
 /**
  * Puts a signed short value.
- * @param s an integral value.
+ * @method putShort
+ * @memberof! proton.Data#
+ * @param {number} s an integral value.
  */
 _Data_['putShort'] = function(s) {
     this._check(_pn_data_put_short(this._data, s));
@@ -1467,7 +1827,9 @@ _Data_['putShort'] = function(s) {
 
 /**
  * Puts a unsigned integer value.
- * @param ui an integral value.
+ * @method putUnsignedInteger
+ * @memberof! proton.Data#
+ * @param {number} ui an integral value.
  */
 _Data_['putUnsignedInteger'] = function(ui) {
     this._check(_pn_data_put_uint(this._data, ui));
@@ -1475,7 +1837,9 @@ _Data_['putUnsignedInteger'] = function(ui) {
 
 /**
  * Puts a signed integer value.
- * @param i an integral value.
+ * @method putInteger
+ * @memberof! proton.Data#
+ * @param {number} i an integral value.
  */
 _Data_['putInteger'] = function(i) {
     this._check(_pn_data_put_int(this._data, i));
@@ -1483,7 +1847,9 @@ _Data_['putInteger'] = function(i) {
 
 /**
  * Puts a signed char value.
- * @param c a single character.
+ * @method putChar
+ * @memberof! proton.Data#
+ * @param {number} c a single character.
  */
 _Data_['putChar'] = function(c) {
 console.log("putChar not properly implemented yet");
@@ -1492,7 +1858,9 @@ console.log("putChar not properly implemented yet");
 
 /**
  * Puts a unsigned long value.
- * @param ul an integral value.
+ * @method putUnsignedLong
+ * @memberof! proton.Data#
+ * @param {number} ul an integral value.
  */
 _Data_['putUnsignedLong'] = function(ul) {
     this._check(_pn_data_put_ulong(this._data, ul));
@@ -1500,7 +1868,9 @@ _Data_['putUnsignedLong'] = function(ul) {
 
 /**
  * Puts a signed long value.
- * @param i an integral value.
+ * @method putLong
+ * @memberof! proton.Data#
+ * @param {number} i an integral value.
  */
 _Data_['putLong'] = function(l) {
 console.log("putLong " + l);
@@ -1511,7 +1881,9 @@ console.log("putLong " + l);
 
 /**
  * Puts a timestamp.
- * @param t an integral value.
+ * @method putTimestamp
+ * @memberof! proton.Data#
+ * @param {number} t an integral value.
  */
 _Data_['putTimestamp'] = function(t) {
 console.log("putTimestamp not properly implemented yet");
@@ -1520,7 +1892,9 @@ console.log("putTimestamp not properly implemented yet");
 
 /**
  * Puts a float value.
- * @param f a floating point value.
+ * @method putFloat
+ * @memberof! proton.Data#
+ * @param {number} f a floating point value.
  */
 _Data_['putFloat'] = function(f) {
     this._check(_pn_data_put_float(this._data, f));
@@ -1528,7 +1902,9 @@ _Data_['putFloat'] = function(f) {
 
 /**
  * Puts a double value.
- * @param d a floating point value.
+ * @method putDouble
+ * @memberof! proton.Data#
+ * @param {number} d a floating point value.
  */
 _Data_['putDouble'] = function(d) {
     this._check(_pn_data_put_double(this._data, d));
@@ -1536,7 +1912,9 @@ _Data_['putDouble'] = function(d) {
 
 /**
  * Puts a decimal32 value.
- * @param d a decimal32 value.
+ * @method putDecimal32
+ * @memberof! proton.Data#
+ * @param {number} d a decimal32 value.
  */
 _Data_['putDecimal32'] = function(d) {
     this._check(_pn_data_put_decimal32(this._data, d));
@@ -1544,7 +1922,9 @@ _Data_['putDecimal32'] = function(d) {
 
 /**
  * Puts a decimal64 value.
- * @param d a decimal64 value.
+ * @method putDecimal64
+ * @memberof! proton.Data#
+ * @param {number} d a decimal64 value.
  */
 _Data_['putDecimal64'] = function(d) {
     this._check(_pn_data_put_decimal64(this._data, d));
@@ -1552,7 +1932,9 @@ _Data_['putDecimal64'] = function(d) {
 
 /**
  * Puts a decimal128 value.
- * @param d a decimal128 value.
+ * @method putDecimal128
+ * @memberof! proton.Data#
+ * @param {number} d a decimal128 value.
  */
 _Data_['putDecimal128'] = function(d) {
     this._check(_pn_data_put_decimal128(this._data, d));
@@ -1560,7 +1942,9 @@ _Data_['putDecimal128'] = function(d) {
 
 /**
  * Puts a UUID value.
- * @param u a uuid value
+ * @method putUUID
+ * @memberof! proton.Data#
+ * @param {proton.Data.UUID} u a uuid value
  */
 _Data_['putUUID'] = function(u) {
     var sp = Runtime.stackSave();
@@ -1570,6 +1954,8 @@ _Data_['putUUID'] = function(u) {
 
 /**
  * Puts a binary value.
+ * @method putBinary
+ * @memberof! proton.Data#
  * @param b a binary value.
  */
 _Data_['putBinary'] = function(d) {
@@ -1579,7 +1965,9 @@ console.log("putBinary not properly implemented yet");
 
 /**
  * Puts a unicode string value.
- * @param s a unicode string value.
+ * @method putString
+ * @memberof! proton.Data#
+ * @param {string} s a unicode string value.
  */
 _Data_['putString'] = function(s) {
     var sp = Runtime.stackSave();
@@ -1616,7 +2004,9 @@ _Data_['putString'] = function(s) {
  * open-ended, typically the both number and size of symbols in use for any
  * given application will be small, e.g. small enough that it is reasonable to
  * cache all the distinct values. Symbols are encoded as ASCII characters.
- * @param s the symbol name.
+ * @method putSymbol
+ * @memberof! proton.Data#
+ * @param {proton.Data.Symbol} s the symbol name.
  */
 _Data_['putSymbol'] = function(s) {
     var sp = Runtime.stackSave();
@@ -1679,6 +2069,8 @@ _Data_['putSymbol'] = function(s) {
 // TODO getArray and isDescribed
 
 /**
+ * @method getNull
+ * @memberof! proton.Data#
  * @return a null value.
  */
 _Data_['getNull'] = function() {
@@ -1687,27 +2079,37 @@ _Data_['getNull'] = function() {
 
 /**
  * Checks if the current node is a null.
+ * @method isNull
+ * @memberof! proton.Data#
+ * @returns {boolean} true iff the current node is null.
  */
 _Data_['isNull'] = function() {
-    return _pn_data_is_null(this._data);
+    return (_pn_data_is_null(this._data) > 0);
 };
 
 /**
- * @return value if the current node is a boolean, returns false otherwise.
+ * @method getBoolean
+ * @memberof! proton.Data#
+ * @returns {boolean} a boolean value if the current node is a boolean, returns
+ *          false otherwise.
  */
 _Data_['getBoolean'] = function() {
     return (_pn_data_get_bool(this._data) > 0);
 };
 
 /**
- * @return value if the current node is an unsigned byte, returns 0 otherwise.
+ * @method getUnsignedByte
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned byte, returns 0 otherwise.
  */
 _Data_['getUnsignedByte'] = function() {
     return _pn_data_get_ubyte(this._data);
 };
 
 /**
- * @return value if the current node is a signed byte, returns 0 otherwise.
+ * @method getByte
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed byte, returns 0 otherwise.
  */
 _Data_['getByte'] = function() {
     return _pn_data_get_byte(this._data);
@@ -1721,29 +2123,38 @@ _Data_['getUnsignedShort'] = function() {
 };
 
 /**
- * @return value if the current node is a signed short, returns 0 otherwise.
+ * @method getShort
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed short, returns 0 otherwise.
  */
 _Data_['getShort'] = function() {
     return _pn_data_get_short(this._data);
 };
 
 /**
- * @return value if the current node is an unsigned int, returns 0 otherwise.
+ * @method getUnsignedInteger
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned int, returns 0 otherwise.
  */
 _Data_['getUnsignedInteger'] = function() {
     return _pn_data_get_uint(this._data);
 };
 
 /**
- * @return value if the current node is a signed int, returns 0 otherwise.
+ * @method getInteger
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed int, returns 0 otherwise.
  */
 _Data_['getInteger'] = function() {
     return _pn_data_put_int(this._data);
 };
 
 /**
- * @return value if the current node is a character, returns 0 otherwise.
+ * @method getChar
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a character, returns 0 otherwise.
  */
+// TODO should this be dealing with strings not numbers?
 _Data_['getChar'] = function() {
 console.log("getChar not properly implemented yet");
 return "character";
@@ -1751,14 +2162,18 @@ return "character";
 };
 
 /**
- * @return value if the current node is an unsigned long, returns 0 otherwise.
+ * @method getUnsignedLong
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned long, returns 0 otherwise.
  */
 _Data_['getUnsignedLong'] = function() {
     return _pn_data_get_ulong(this._data);
 };
 
 /**
- * @return value if the current node is a signed long, returns 0 otherwise.
+ * @method getLong
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed long, returns 0 otherwise.
  */
 _Data_['getLong'] = function() {
 console.log("getLong");
@@ -1778,7 +2193,9 @@ console.log("Data.getLong() long = " + long);
 };
 
 /**
- * @return value if the current node is a timestamp, returns 0 otherwise.
+ * @method getTimestamp
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a timestamp, returns 0 otherwise.
  */
 _Data_['getTimestamp'] = function() {
 console.log("getTimestamp not properly implemented yet");
@@ -1787,21 +2204,27 @@ return 123456;
 };
 
 /**
- * @return value if the current node is a float, returns 0 otherwise.
+ * @method getFloat
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a float, returns 0 otherwise.
  */
 _Data_['getFloat'] = function() {
     return _pn_data_get_float(this._data);
 };
 
 /**
- * @return value if the current node is a double, returns 0 otherwise.
+ * @method getDouble
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a double, returns 0 otherwise.
  */
 _Data_['getDouble'] = function() {
     return _pn_data_get_double(this._data);
 };
 
 /**
- * @return value if the current node is a decimal32, returns 0 otherwise.
+ * @method getDecimal32
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a decimal32, returns 0 otherwise.
  */
 _Data_['getDecimal32'] = function() {
 console.log("getDecimal32 not properly implemented yet");
@@ -1809,7 +2232,9 @@ console.log("getDecimal32 not properly implemented yet");
 };
 
 /**
- * @return value if the current node is a decimal64, returns 0 otherwise.
+ * @method getDecimal64
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a decimal64, returns 0 otherwise.
  */
 _Data_['getDecimal64'] = function() {
 console.log("getDecimal64 not properly implemented yet");
@@ -1817,7 +2242,9 @@ console.log("getDecimal64 not properly implemented yet");
 };
 
 /**
- * @return value if the current node is a decimal128, returns 0 otherwise.
+ * @method getDecimal128
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a decimal128, returns 0 otherwise.
  */
 _Data_['getDecimal128'] = function() {
 console.log("getDecimal128 not properly implemented yet");
@@ -1825,7 +2252,9 @@ console.log("getDecimal128 not properly implemented yet");
 };
 
 /**
- * @return value if the current node is a UUID, returns null otherwise.
+ * @method getUUID
+ * @memberof! proton.Data#
+ * @return {proton.Data.UUID} value if the current node is a UUID, returns null otherwise.
  */
 _Data_['getUUID'] = function() {
     var sp = Runtime.stackSave();
@@ -1848,7 +2277,9 @@ _Data_['getUUID'] = function() {
 };
 
 /**
- * @return value if the current node is a Binary, returns null otherwise.
+ * @method getBinary
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise.
  */
 _Data_['getBinary'] = function() {
 console.log("getBinary not properly implemented yet");
@@ -1856,7 +2287,10 @@ console.log("getBinary not properly implemented yet");
 };
 
 /**
- * @return value if the current node is a String, returns "" otherwise.
+ * Gets a unicode String value from the current node.
+ * @method getString
+ * @memberof! proton.Data#
+ * @return {string} value if the current node is a String, returns "" otherwise.
  */
 _Data_['getString'] = function() {
     var sp = Runtime.stackSave();
@@ -1894,9 +2328,9 @@ _Data_['getString'] = function() {
  * open-ended, typically the both number and size of symbols in use for any
  * given application will be small, e.g. small enough that it is reasonable to
  * cache all the distinct values. Symbols are encoded as ASCII characters.
-
-
- * @return value if the current node is a Symbol, returns "" otherwise.
+ * @method getSymbol
+ * @memberof! proton.Data#
+ * @return {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
  */
 _Data_['getSymbol'] = function() {
     var sp = Runtime.stackSave();
@@ -1936,7 +2370,9 @@ _Data_['getSymbol'] = function() {
 
 /**
  * Serialise a Native JavaScript Object into an AMQP Map.
- * @param object the Native JavaScript Object that we wish to serialise.
+ * @method putDictionary
+ * @memberof! proton.Data#
+ * @param {object} object the Native JavaScript Object that we wish to serialise.
  */
 _Data_['putDictionary'] = function(object) {
     this['putMap']();
@@ -1952,7 +2388,9 @@ _Data_['putDictionary'] = function(object) {
 
 /**
  * Deserialise from an AMQP Map into a Native JavaScript Object.
- * @return the deserialised Native JavaScript Object.
+ * @method getDictionary
+ * @memberof! proton.Data#
+ * @returns {object} the deserialised Native JavaScript Object.
  */
 _Data_['getDictionary'] = function() {
     if (this['enter']()) {
@@ -1973,7 +2411,9 @@ _Data_['getDictionary'] = function() {
 
 /**
  * Serialise a Native JavaScript Array into an AMQP List.
- * @param array the Native JavaScript Array that we wish to serialise.
+ * @method putJSArray
+ * @memberof! proton.Data#
+ * @param {Array} array the Native JavaScript Array that we wish to serialise.
  */
 _Data_['putJSArray'] = function(array) {
     this['putList']();
@@ -1986,7 +2426,9 @@ _Data_['putJSArray'] = function(array) {
 
 /**
  * Deserialise from an AMQP List into a Native JavaScript Array.
- * @return the deserialised Native JavaScript Array.
+ * @method getJSArray
+ * @memberof! proton.Data#
+ * @returns {array} the deserialised Native JavaScript Array.
  */
 _Data_['getJSArray'] = function() {
     if (this['enter']()) {
@@ -2013,7 +2455,9 @@ _Data_['getJSArray'] = function() {
  * and we could employ a look-up table but in practice the JavaScript type system
  * doesn't really lend itself to that and we have to employ extra checks,
  * heuristics and inferences.
- * @param obj the JavaScript Object or primitive to be serialised.
+ * @method putObject
+ * @memberof! proton.Data#
+ * @param {object} obj the JavaScript Object or primitive to be serialised.
  */
 _Data_['putObject'] = function(obj) {
 console.log("Data.putObject");
@@ -2083,8 +2527,12 @@ console.log(obj + " is Float Type");
 _Data_.putObject = _Data_['putObject'];
 
 
-// TODO
-_Data_['getObject'] = function(obj) {
+/**
+ * @method getObject
+ * @memberof! proton.Data#
+ * @returns {object} the JavaScript Object or primitive being deserialised.
+ */
+_Data_['getObject'] = function() {
 console.log("Data.getObject: not fully implemented yet");
 
     var type = this.type();
@@ -2152,3 +2600,4 @@ Module['Inflate'] = function(size) {
 */
 
 
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24481358/tools/cmake/Modules/FindEmscripten.cmake
----------------------------------------------------------------------
diff --git a/tools/cmake/Modules/FindEmscripten.cmake b/tools/cmake/Modules/FindEmscripten.cmake
index f813b7a..7289731 100644
--- a/tools/cmake/Modules/FindEmscripten.cmake
+++ b/tools/cmake/Modules/FindEmscripten.cmake
@@ -18,9 +18,9 @@
 #
 
 # FindEmscripten
-# This module check if Emscripten and its prerequisites are installed and if so sets EMSCRIPTEN_FOUND
-# Emscripten (https://github.com/kripken/emscripten) is a C/C++ to JavaScript cross-compiler used to
-# generate the JavaScript bindings.
+# This module checks if Emscripten and its prerequisites are installed and if so
+# sets EMSCRIPTEN_FOUND Emscripten (https://github.com/kripken/emscripten) is a
+# C/C++ to JavaScript cross-compiler used to generate the JavaScript bindings.
 
 if (NOT EMSCRIPTEN_FOUND)
     # First check that Node.js is installed as that is needed by Emscripten.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24481358/tools/cmake/Modules/FindNodePackages.cmake
----------------------------------------------------------------------
diff --git a/tools/cmake/Modules/FindNodePackages.cmake b/tools/cmake/Modules/FindNodePackages.cmake
new file mode 100644
index 0000000..31c5551
--- /dev/null
+++ b/tools/cmake/Modules/FindNodePackages.cmake
@@ -0,0 +1,61 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# FindNodePackages
+# This module finds and installs (optionally) required node.js packages using npm
+# * The ws package is the WebSocket library used by emscripten when the target is
+#   node.js, it isn't needed for applications hosted on a browser where native 
+#   WebSockets will be used.
+#
+# * The jsdoc package is a JavaScript API document generator analogous to Doxygen
+#   or JavaDoc, it is used by the docs target in the JavaScript binding.
+
+if (NOT NODE_PACKAGES_FOUND)
+    # Install ws node.js WebSocket library https://github.com/einaros/ws
+    message(STATUS "Installing node.js ws package")
+
+    execute_process(
+        COMMAND npm install ws
+        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+        OUTPUT_VARIABLE var
+    )
+
+    if (var)
+        message(STATUS "Node.js ws package has been installed")
+        set(NODE_WS_FOUND ON)
+    endif (var)
+
+    # Install jsdoc3 API documentation generator for JavaScript https://github.com/jsdoc3/jsdoc
+    message(STATUS "Installing node.js jsdoc package")
+
+    execute_process(
+        COMMAND npm install jsdoc
+        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+        OUTPUT_VARIABLE var
+    )
+
+    if (var)
+        message(STATUS "Node.js jsdoc package has been installed")
+        set(NODE_JSDOC_FOUND ON)
+        set(JSDOC_EXE ${PROJECT_SOURCE_DIR}/node_modules/.bin/jsdoc)
+    endif (var)
+
+    set(NODE_PACKAGES_FOUND ON)
+endif (NOT NODE_PACKAGES_FOUND)
+


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


[44/51] [abbrv] qpid-proton git commit: Sync with proton trunk revision 1627945 and update CMakeLists.txt

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/object/object.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/object.c b/proton-c/src/object/object.c
index d1b0e43..b0cfcc7 100644
--- a/proton-c/src/object/object.c
+++ b/proton-c/src/object/object.c
@@ -19,1031 +19,294 @@
  *
  */
 
-#include "../platform.h"
-#include <proton/error.h>
 #include <proton/object.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <assert.h>
-#include <ctype.h>
 
-typedef struct {
-  const pn_class_t *clazz;
-  int refcount;
-} pni_head_t;
+#define pn_object_initialize NULL
+#define pn_object_finalize NULL
+#define pn_object_inspect NULL
+uintptr_t pn_object_hashcode(void *object) { return (uintptr_t) object; }
+intptr_t pn_object_compare(void *a, void *b) { return (intptr_t) b - (intptr_t) a; }
 
-#define pni_head(PTR) \
-  (((pni_head_t *) (PTR)) - 1)
+const pn_class_t PNI_OBJECT = PN_CLASS(pn_object);
+const pn_class_t *PN_OBJECT = &PNI_OBJECT;
 
-void *pn_new(size_t size, const pn_class_t *clazz)
+#define pn_void_initialize NULL
+static void *pn_void_new(const pn_class_t *clazz, size_t size) { return malloc(size); }
+static void pn_void_incref(void *object) {}
+static void pn_void_decref(void *object) {}
+static int pn_void_refcount(void *object) { return -1; }
+#define pn_void_finalize NULL
+static void pn_void_free(void *object) { free(object); }
+static const pn_class_t *pn_void_reify(void *object) { return PN_VOID; }
+uintptr_t pn_void_hashcode(void *object) { return (uintptr_t) object; }
+intptr_t pn_void_compare(void *a, void *b) { return (intptr_t) b - (intptr_t) a; }
+int pn_void_inspect(void *object, pn_string_t *dst) { return pn_string_addf(dst, "%p", object); }
+
+const pn_class_t PNI_VOID = PN_METACLASS(pn_void);
+const pn_class_t *PN_VOID = &PNI_VOID;
+
+const char *pn_class_name(const pn_class_t *clazz)
 {
-  return pn_new2(size, clazz, NULL);
+  return clazz->name;
 }
 
-void *pn_new2(size_t size, const pn_class_t *clazz, void *from)
+pn_cid_t pn_class_id(const pn_class_t *clazz)
 {
-  pni_head_t *head = (pni_head_t *) malloc(sizeof(pni_head_t) + size);
-  void *object = head + 1;
-  pn_initialize(object, clazz);
-  return object;
+  return clazz->cid;
 }
 
-void pn_initialize(void *object, const pn_class_t *clazz)
+void *pn_class_new(const pn_class_t *clazz, size_t size)
 {
-  pni_head_t *head = pni_head(object);
-  head->clazz = clazz;
-  head->refcount = 1;
-  if (clazz && clazz->initialize) {
+  assert(clazz);
+  void *object = clazz->newinst(clazz, size);
+  if (clazz->initialize) {
     clazz->initialize(object);
   }
-}
-
-void *pn_incref(void *object) {
-  return pn_incref2(object, NULL);
-}
-
-void *pn_incref2(void *object, void *from) {
-  if (object) {
-    pni_head(object)->refcount++;
-  }
   return object;
 }
 
-void pn_decref(void *object) {
-  pn_decref2(object, NULL);
-}
-
-void pn_decref2(void *object, void *from)
+void *pn_class_incref(const pn_class_t *clazz, void *object)
 {
+  assert(clazz);
   if (object) {
-    pni_head_t *head = pni_head(object);
-    assert(head->refcount > 0);
-    head->refcount--;
-    if (!head->refcount) {
-      pn_finalize(object);
-      // Check the refcount again in case finalize created a new
-      // reference.
-      if (!head->refcount) {
-        free(head);
-      }
-    }
+    clazz = clazz->reify(object);
+    clazz->incref(object);
   }
+  return object;
 }
 
-void pn_finalize(void *object)
+int pn_class_refcount(const pn_class_t *clazz, void *object)
 {
-  if (object) {
-    pni_head_t *head = pni_head(object);
-    assert(head->refcount == 0);
-    if (head->clazz && head->clazz->finalize) {
-      head->clazz->finalize(object);
-    }
-  }
+  assert(clazz);
+  clazz = clazz->reify(object);
+  return clazz->refcount(object);
 }
 
-int pn_refcount(void *object)
+int pn_class_decref(const pn_class_t *clazz, void *object)
 {
-  assert(object);
-  return pni_head(object)->refcount;
-}
+  assert(clazz);
 
-void pn_free(void *object)
-{
   if (object) {
-    assert(pn_refcount(object) == 1);
-    pn_decref(object);
-  }
-}
-
-const pn_class_t *pn_class(void *object)
-{
-  assert(object);
-  return pni_head(object)->clazz;
-}
-
-uintptr_t pn_hashcode(void *object)
-{
-  if (!object) return 0;
-
-  pni_head_t *head = pni_head(object);
-  if (head->clazz && head->clazz->hashcode) {
-    return head->clazz->hashcode(object);
-  } else {
-    return (uintptr_t) head;
-  }
-}
-
-intptr_t pn_compare(void *a, void *b)
-{
-  if (a == b) return 0;
-  if (a && b) {
-    pni_head_t *ha = pni_head(a);
-    pni_head_t *hb = pni_head(b);
-
-    if (ha->clazz && hb->clazz && ha->clazz == hb->clazz) {
-      const pn_class_t *clazz = ha->clazz;
-      if (clazz->compare) {
-        return clazz->compare(a, b);
+    clazz = clazz->reify(object);
+    clazz->decref(object);
+    int rc = clazz->refcount(object);
+    if (rc == 0) {
+      if (clazz->finalize) {
+        clazz->finalize(object);
+        // check the refcount again in case the finalizer created a
+        // new reference
+        rc = clazz->refcount(object);
       }
-    }
-  }
-
-  return (intptr_t) b - (intptr_t) a;
-}
-
-bool pn_equals(void *a, void *b)
-{
-  return !pn_compare(a, b);
-}
-
-int pn_inspect(void *object, pn_string_t *dst)
-{
-  if (!pn_string_get(dst)) {
-    pn_string_set(dst, "");
-  }
-
-  if (object) {
-    pni_head_t *head = pni_head(object);
-    const char *name;
-    if (head->clazz) {
-      const pn_class_t *clazz = head->clazz;
-      if (clazz->inspect) {
-        return clazz->inspect(object, dst);
-      } else if (clazz->name) {
-        name = clazz->name;
-      } else {
-        name = "object";
+      if (rc == 0) {
+        clazz->free(object);
+        return 0;
       }
     } else {
-      name = "object";
-    }
-    return pn_string_addf(dst, "%s<%p>", name, object);
-  } else {
-    return pn_string_addf(dst, "(null)");
-  }
-}
-
-struct pn_list_t {
-  size_t capacity;
-  size_t size;
-  void **elements;
-  int options;
-};
-
-size_t pn_list_size(pn_list_t *list)
-{
-  assert(list);
-  return list->size;
-}
-
-void *pn_list_get(pn_list_t *list, int index)
-{
-  assert(list); assert(list->size);
-  return list->elements[index % list->size];
-}
-
-void pn_list_set(pn_list_t *list, int index, void *value)
-{
-  assert(list); assert(list->size);
-  void *old = list->elements[index % list->size];
-  if (list->options & PN_REFCOUNT) pn_decref2(old, list);
-  list->elements[index % list->size] = value;
-  if (list->options & PN_REFCOUNT) pn_incref2(value, list);
-}
-
-void pn_list_ensure(pn_list_t *list, size_t capacity)
-{
-  assert(list);
-  if (list->capacity < capacity) {
-    size_t newcap = list->capacity;
-    while (newcap < capacity) { newcap *= 2; }
-    list->elements = (void **) realloc(list->elements, newcap * sizeof(void *));
-    assert(list->elements);
-    list->capacity = newcap;
-  }
-}
-
-int pn_list_add(pn_list_t *list, void *value)
-{
-  assert(list);
-  pn_list_ensure(list, list->size + 1);
-  list->elements[list->size++] = value;
-  if (list->options & PN_REFCOUNT) pn_incref2(value, list);
-  return 0;
-}
-
-ssize_t pn_list_index(pn_list_t *list, void *value)
-{
-  for (size_t i = 0; i < list->size; i++) {
-    if (pn_equals(list->elements[i], value)) {
-      return i;
-    }
-  }
-
-  return -1;
-}
-
-bool pn_list_remove(pn_list_t *list, void *value)
-{
-  assert(list);
-  ssize_t idx = pn_list_index(list, value);
-  if (idx < 0) {
-    return false;
-  } else {
-    pn_list_del(list, idx, 1);
-  }
-
-  return true;
-}
-
-void pn_list_del(pn_list_t *list, int index, int n)
-{
-  assert(list);
-  index %= list->size;
-
-  if (list->options & PN_REFCOUNT) {
-    for (int i = 0; i < n; i++) {
-      pn_decref2(list->elements[index + i], list);
-    }
-  }
-
-  size_t slide = list->size - (index + n);
-  for (size_t i = 0; i < slide; i++) {
-    list->elements[index + i] = list->elements[index + n + i];
-  }
-
-  list->size -= n;
-}
-
-void pn_list_clear(pn_list_t *list)
-{
-  assert(list);
-  pn_list_del(list, 0, list->size);
-}
-
-void pn_list_fill(pn_list_t *list, void *value, int n)
-{
-  for (int i = 0; i < n; i++) {
-    pn_list_add(list, value);
-  }
-}
-
-typedef struct {
-  pn_list_t *list;
-  size_t index;
-} pni_list_iter_t;
-
-static void *pni_list_next(void *ctx)
-{
-  pni_list_iter_t *iter = (pni_list_iter_t *) ctx;
-  if (iter->index < pn_list_size(iter->list)) {
-    return pn_list_get(iter->list, iter->index++);
-  } else {
-    return NULL;
-  }
-}
-
-void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter)
-{
-  pni_list_iter_t *liter = (pni_list_iter_t *) pn_iterator_start(iter, pni_list_next, sizeof(pni_list_iter_t));
-  liter->list = list;
-  liter->index = 0;
-}
-
-static void pn_list_finalize(void *object)
-{
-  assert(object);
-  pn_list_t *list = (pn_list_t *) object;
-  for (size_t i = 0; i < list->size; i++) {
-    if (list->options & PN_REFCOUNT) pn_decref2(pn_list_get(list, i), list);
-  }
-  free(list->elements);
-}
-
-static uintptr_t pn_list_hashcode(void *object)
-{
-  assert(object);
-  pn_list_t *list = (pn_list_t *) object;
-  uintptr_t hash = 1;
-
-  for (size_t i = 0; i < list->size; i++) {
-    hash = hash * 31 + pn_hashcode(pn_list_get(list, i));
-  }
-
-  return hash;
-}
-
-static intptr_t pn_list_compare(void *oa, void *ob)
-{
-  assert(oa); assert(ob);
-  pn_list_t *a = (pn_list_t *) oa;
-  pn_list_t *b = (pn_list_t *) ob;
-
-  size_t na = pn_list_size(a);
-  size_t nb = pn_list_size(b);
-  if (na != nb) {
-    return nb - na;
-  } else {
-    for (size_t i = 0; i < na; i++) {
-      intptr_t delta = pn_compare(pn_list_get(a, i), pn_list_get(b, i));
-      if (delta) return delta;
+      return rc;
     }
   }
 
   return 0;
 }
 
-static int pn_list_inspect(void *obj, pn_string_t *dst)
-{
-  assert(obj);
-  pn_list_t *list = (pn_list_t *) obj;
-  int err = pn_string_addf(dst, "[");
-  if (err) return err;
-  size_t n = pn_list_size(list);
-  for (size_t i = 0; i < n; i++) {
-    if (i > 0) {
-      err = pn_string_addf(dst, ", ");
-      if (err) return err;
-    }
-    err = pn_inspect(pn_list_get(list, i), dst);
-    if (err) return err;
-  }
-  return pn_string_addf(dst, "]");
-}
-
-#define pn_list_initialize NULL
-
-pn_list_t *pn_list(size_t capacity, int options)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_list);
-
-  pn_list_t *list = (pn_list_t *) pn_new(sizeof(pn_list_t), &clazz);
-  list->capacity = capacity ? capacity : 16;
-  list->elements = (void **) malloc(list->capacity * sizeof(void *));
-  list->size = 0;
-  list->options = options;
-  return list;
-}
-
-#define PNI_ENTRY_FREE (0)
-#define PNI_ENTRY_LINK (1)
-#define PNI_ENTRY_TAIL (2)
-
-typedef struct {
-  void *key;
-  void *value;
-  size_t next;
-  uint8_t state;
-} pni_entry_t;
-
-struct pn_map_t {
-  pni_entry_t *entries;
-  size_t capacity;
-  size_t addressable;
-  size_t size;
-  uintptr_t (*hashcode)(void *key);
-  bool (*equals)(void *a, void *b);
-  float load_factor;
-  bool count_keys;
-  bool count_values;
-  bool inspect_keys;
-};
-
-static void pn_map_finalize(void *object)
-{
-  pn_map_t *map = (pn_map_t *) object;
-
-  if (map->count_keys || map->count_values) {
-    for (size_t i = 0; i < map->capacity; i++) {
-      if (map->entries[i].state != PNI_ENTRY_FREE) {
-        if (map->count_keys) pn_decref2(map->entries[i].key, map);
-        if (map->count_values) pn_decref2(map->entries[i].value, map);
-      }
-    }
-  }
-
-  free(map->entries);
-}
-
-static uintptr_t pn_map_hashcode(void *object)
+void pn_class_free(const pn_class_t *clazz, void *object)
 {
-  pn_map_t *map = (pn_map_t *) object;
-
-  uintptr_t hashcode = 0;
-
-  for (size_t i = 0; i < map->capacity; i++) {
-    if (map->entries[i].state != PNI_ENTRY_FREE) {
-      void *key = map->entries[i].key;
-      void *value = map->entries[i].value;
-      hashcode += pn_hashcode(key) ^ pn_hashcode(value);
-    }
-  }
-
-  return hashcode;
-}
-
-static void pni_map_allocate(pn_map_t *map)
-{
-  map->entries = (pni_entry_t *) malloc(map->capacity * sizeof (pni_entry_t));
-  for (size_t i = 0; i < map->capacity; i++) {
-    map->entries[i].key = NULL;
-    map->entries[i].value = NULL;
-    map->entries[i].next = 0;
-    map->entries[i].state = PNI_ENTRY_FREE;
-  }
-  map->size = 0;
-}
-
-static int pn_map_inspect(void *obj, pn_string_t *dst)
-{
-  assert(obj);
-  pn_map_t *map = (pn_map_t *) obj;
-  int err = pn_string_addf(dst, "{");
-  if (err) return err;
-  pn_handle_t entry = pn_map_head(map);
-  bool first = true;
-  while (entry) {
-    if (first) {
-      first = false;
-    } else {
-      err = pn_string_addf(dst, ", ");
-      if (err) return err;
-    }
-    if (map->inspect_keys) {
-      err = pn_inspect(pn_map_key(map, entry), dst);
+  assert(clazz);
+  if (object) {
+    clazz = clazz->reify(object);
+    int rc = clazz->refcount(object);
+    assert(rc == 1 || rc == -1);
+    if (rc == 1) {
+      rc = pn_class_decref(clazz, object);
+      assert(rc == 0);
     } else {
-      err = pn_string_addf(dst, "%p", pn_map_key(map, entry));
+      if (clazz->finalize) {
+        clazz->finalize(object);
+      }
+      clazz->free(object);
     }
-    if (err) return err;
-    err = pn_string_addf(dst, ": ");
-    if (err) return err;
-    err = pn_inspect(pn_map_value(map, entry), dst);
-    if (err) return err;
-    entry = pn_map_next(map, entry);
   }
-  return pn_string_addf(dst, "}");
-}
-
-#define pn_map_initialize NULL
-#define pn_map_compare NULL
-
-pn_map_t *pn_map(size_t capacity, float load_factor, int options)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_map);
-
-  pn_map_t *map = (pn_map_t *) pn_new(sizeof(pn_map_t), &clazz);
-  map->capacity = capacity ? capacity : 16;
-  map->addressable = (size_t) (map->capacity * 0.86);
-  if (!map->addressable) map->addressable = map->capacity;
-  map->load_factor = load_factor;
-  map->hashcode = pn_hashcode;
-  map->equals = pn_equals;
-  map->count_keys = (options & PN_REFCOUNT) || (options & PN_REFCOUNT_KEY);
-  map->count_values = (options & PN_REFCOUNT) || (options & PN_REFCOUNT_VALUE);
-  map->inspect_keys = true;
-  pni_map_allocate(map);
-  return map;
-}
-
-size_t pn_map_size(pn_map_t *map)
-{
-  assert(map);
-  return map->size;
 }
 
-static float pni_map_load(pn_map_t *map)
+const pn_class_t *pn_class_reify(const pn_class_t *clazz, void *object)
 {
-  return ((float) map->size) / ((float) map->addressable);
-}
-
-static bool pni_map_ensure(pn_map_t *map, size_t capacity)
-{
-  float load = pni_map_load(map);
-  if (capacity <= map->capacity && load <= map->load_factor) {
-    return false;
-  }
-
-  size_t oldcap = map->capacity;
-
-  while (map->capacity < capacity || pni_map_load(map) > map->load_factor) {
-    map->capacity *= 2;
-    map->addressable = (size_t) (0.86 * map->capacity);
-  }
-
-  pni_entry_t *entries = map->entries;
-  pni_map_allocate(map);
-
-  for (size_t i = 0; i < oldcap; i++) {
-    if (entries[i].state != PNI_ENTRY_FREE) {
-      void *key = entries[i].key;
-      void *value = entries[i].value;
-      pn_map_put(map, key, value);
-      if (map->count_keys) pn_decref2(key, map);
-      if (map->count_values) pn_decref2(value, map);
-    }
-  }
-
-  free(entries);
-  return true;
+  assert(clazz);
+  return clazz->reify(object);
 }
 
-static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev, bool create)
+uintptr_t pn_class_hashcode(const pn_class_t *clazz, void *object)
 {
-  uintptr_t hashcode = map->hashcode(key);
+  assert(clazz);
 
-  pni_entry_t *entry = &map->entries[hashcode % map->addressable];
-  pni_entry_t *prev = NULL;
-
-  if (entry->state == PNI_ENTRY_FREE) {
-    if (create) {
-      entry->state = PNI_ENTRY_TAIL;
-      entry->key = key;
-      if (map->count_keys) pn_incref2(key, map);
-      map->size++;
-      return entry;
-    } else {
-      return NULL;
-    }
-  }
-
-  while (true) {
-    if (map->equals(entry->key, key)) {
-      if (pprev) *pprev = prev;
-      return entry;
-    }
-
-    if (entry->state == PNI_ENTRY_TAIL) {
-      break;
-    } else {
-      prev = entry;
-      entry = &map->entries[entry->next];
-    }
-  }
+  if (!object) return 0;
 
-  if (create) {
-    if (pni_map_ensure(map, map->size + 1)) {
-      // if we had to grow the table we need to start over
-      return pni_map_entry(map, key, pprev, create);
-    }
+  clazz = clazz->reify(object);
 
-    size_t empty = 0;
-    for (size_t i = 0; i < map->capacity; i++) {
-      size_t idx = map->capacity - i - 1;
-      if (map->entries[idx].state == PNI_ENTRY_FREE) {
-        empty = idx;
-        break;
-      }
-    }
-    entry->next = empty;
-    entry->state = PNI_ENTRY_LINK;
-    map->entries[empty].state = PNI_ENTRY_TAIL;
-    map->entries[empty].key = key;
-    if (map->count_keys) pn_incref2(key, map);
-    if (pprev) *pprev = entry;
-    map->size++;
-    return &map->entries[empty];
+  if (clazz->hashcode) {
+    return clazz->hashcode(object);
   } else {
-    return NULL;
+    return (uintptr_t) object;
   }
 }
 
-int pn_map_put(pn_map_t *map, void *key, void *value)
-{
-  assert(map);
-  pni_entry_t *entry = pni_map_entry(map, key, NULL, true);
-  if (map->count_values) pn_decref2(entry->value, map);
-  entry->value = value;
-  if (map->count_values) pn_incref2(value, map);
-  return 0;
-}
-
-void *pn_map_get(pn_map_t *map, void *key)
+intptr_t pn_class_compare(const pn_class_t *clazz, void *a, void *b)
 {
-  assert(map);
-  pni_entry_t *entry = pni_map_entry(map, key, NULL, false);
-  return entry ? entry->value : NULL;
-}
-
-void pn_map_del(pn_map_t *map, void *key)
-{
-  assert(map);
-  pni_entry_t *prev = NULL;
-  pni_entry_t *entry = pni_map_entry(map, key, &prev, false);
-  if (entry) {
-    void *dref_key = (map->count_keys) ? entry->key : NULL;
-    void *dref_value = (map->count_values) ? entry->value : NULL;
-    if (prev) {
-      prev->next = entry->next;
-      prev->state = entry->state;
-    } else if (entry->next) {
-      assert(entry->state == PNI_ENTRY_LINK);
-      pni_entry_t *next = &map->entries[entry->next];
-      *entry = *next;
-      entry = next;
-    }
-    entry->state = PNI_ENTRY_FREE;
-    entry->next = 0;
-    entry->key = NULL;
-    entry->value = NULL;
-    map->size--;
-    if (dref_key) pn_decref2(dref_key, map);
-    if (dref_value) pn_decref2(dref_value, map);
-  }
-}
+  assert(clazz);
 
-pn_handle_t pn_map_head(pn_map_t *map)
-{
-  assert(map);
-  for (size_t i = 0; i < map->capacity; i++)
-  {
-    if (map->entries[i].state != PNI_ENTRY_FREE) {
-      return i + 1;
-    }
-  }
+  if (a == b) return 0;
 
-  return 0;
-}
+  clazz = clazz->reify(a);
 
-pn_handle_t pn_map_next(pn_map_t *map, pn_handle_t entry)
-{
-  for (size_t i = entry; i < map->capacity; i++) {
-    if (map->entries[i].state != PNI_ENTRY_FREE) {
-      return i + 1;
-    }
+  if (a && b && clazz->compare) {
+    return clazz->compare(a, b);
+  } else {
+    return (intptr_t) b - (intptr_t) a;
   }
-
-  return 0;
-}
-
-void *pn_map_key(pn_map_t *map, pn_handle_t entry)
-{
-  assert(map);
-  assert(entry);
-  return map->entries[entry - 1].key;
-}
-
-void *pn_map_value(pn_map_t *map, pn_handle_t entry)
-{
-  assert(map);
-  assert(entry);
-  return map->entries[entry - 1].value;
-}
-
-struct pn_hash_t {
-  pn_map_t map;
-};
-
-static uintptr_t pni_identity_hashcode(void *obj)
-{
-  return (uintptr_t ) obj;
-}
-
-static bool pni_identity_equals(void *a, void *b)
-{
-  return a == b;
-}
-
-pn_hash_t *pn_hash(size_t capacity, float load_factor, int options)
-{
-  pn_hash_t *hash = (pn_hash_t *) pn_map(capacity, load_factor, 0);
-  hash->map.hashcode = pni_identity_hashcode;
-  hash->map.equals = pni_identity_equals;
-  hash->map.count_keys = false;
-  hash->map.count_values = options & PN_REFCOUNT;
-  hash->map.inspect_keys = false;
-  return hash;
-}
-
-size_t pn_hash_size(pn_hash_t *hash)
-{
-  return pn_map_size(&hash->map);
-}
-
-int pn_hash_put(pn_hash_t *hash, uintptr_t key, void *value)
-{
-  return pn_map_put(&hash->map, (void *) key, value);
-}
-
-void *pn_hash_get(pn_hash_t *hash, uintptr_t key)
-{
-  return pn_map_get(&hash->map, (void *) key);
-}
-
-void pn_hash_del(pn_hash_t *hash, uintptr_t key)
-{
-  pn_map_del(&hash->map, (void *) key);
-}
-
-pn_handle_t pn_hash_head(pn_hash_t *hash)
-{
-  return pn_map_head(&hash->map);
-}
-
-pn_handle_t pn_hash_next(pn_hash_t *hash, pn_handle_t entry)
-{
-  return pn_map_next(&hash->map, entry);
 }
 
-uintptr_t pn_hash_key(pn_hash_t *hash, pn_handle_t entry)
+bool pn_class_equals(const pn_class_t *clazz, void *a, void *b)
 {
-  return (uintptr_t) pn_map_key(&hash->map, entry);
+  return pn_class_compare(clazz, a, b) == 0;
 }
 
-void *pn_hash_value(pn_hash_t *hash, pn_handle_t entry)
+int pn_class_inspect(const pn_class_t *clazz, void *object, pn_string_t *dst)
 {
-  return pn_map_value(&hash->map, entry);
-}
-
-
-#define PNI_NULL_SIZE (-1)
-
-struct pn_string_t {
-  char *bytes;
-  ssize_t size;       // PNI_NULL_SIZE (-1) means null
-  size_t capacity;
-};
-
-static void pn_string_finalize(void *object)
-{
-  pn_string_t *string = (pn_string_t *) object;
-  free(string->bytes);
-}
-
-static uintptr_t pn_string_hashcode(void *object)
-{
-  pn_string_t *string = (pn_string_t *) object;
-  if (string->size == PNI_NULL_SIZE) {
-    return 0;
-  }
+  assert(clazz);
 
-  uintptr_t hashcode = 1;
-  for (ssize_t i = 0; i < string->size; i++) {
-    hashcode = hashcode * 31 + string->bytes[i];
-  }
-  return hashcode;
-}
+  clazz = clazz->reify(object);
 
-static intptr_t pn_string_compare(void *oa, void *ob)
-{
-  pn_string_t *a = (pn_string_t *) oa;
-  pn_string_t *b = (pn_string_t *) ob;
-  if (a->size != b->size) {
-    return b->size - a->size;
-  }
-
-  if (a->size == PNI_NULL_SIZE) {
-    return 0;
-  } else {
-    return memcmp(a->bytes, b->bytes, a->size);
-  }
-}
-
-static int pn_string_inspect(void *obj, pn_string_t *dst)
-{
-  pn_string_t *str = (pn_string_t *) obj;
-  if (str->size == PNI_NULL_SIZE) {
-    return pn_string_addf(dst, "null");
+  if (!pn_string_get(dst)) {
+    pn_string_set(dst, "");
   }
 
-  int err = pn_string_addf(dst, "\"");
-
-  for (int i = 0; i < str->size; i++) {
-    uint8_t c = str->bytes[i];
-    if (isprint(c)) {
-      err = pn_string_addf(dst, "%c", c);
-      if (err) return err;
-    } else {
-      err = pn_string_addf(dst, "\\x%.2x", c);
-      if (err) return err;
-    }
+  if (object && clazz->inspect) {
+    return clazz->inspect(object, dst);
   }
 
-  return pn_string_addf(dst, "\"");
-}
+  const char *name = clazz->name ? clazz->name : "<anon>";
 
-pn_string_t *pn_string(const char *bytes)
-{
-  return pn_stringn(bytes, bytes ? strlen(bytes) : 0);
+  return pn_string_addf(dst, "%s<%p>", name, object);
 }
 
-#define pn_string_initialize NULL
+typedef struct {
+  const pn_class_t *clazz;
+  int refcount;
+} pni_head_t;
 
+#define pni_head(PTR) \
+  (((pni_head_t *) (PTR)) - 1)
 
-pn_string_t *pn_stringn(const char *bytes, size_t n)
+void *pn_object_new(const pn_class_t *clazz, size_t size)
 {
-  static const pn_class_t clazz = PN_CLASS(pn_string);
-  pn_string_t *string = (pn_string_t *) pn_new(sizeof(pn_string_t), &clazz);
-  string->capacity = n ? n * sizeof(char) : 16;
-  string->bytes = (char *) malloc(string->capacity);
-  pn_string_setn(string, bytes, n);
-  return string;
+  pni_head_t *head = (pni_head_t *) malloc(sizeof(pni_head_t) + size);
+  void *object = head + 1;
+  head->clazz = clazz;
+  head->refcount = 1;
+  return object;
 }
 
-const char *pn_string_get(pn_string_t *string)
+const pn_class_t *pn_object_reify(void *object)
 {
-  assert(string);
-  if (string->size == PNI_NULL_SIZE) {
-    return NULL;
+  if (object) {
+    return pni_head(object)->clazz;
   } else {
-    return string->bytes;
+    return PN_OBJECT;
   }
 }
 
-size_t pn_string_size(pn_string_t *string)
+void pn_object_incref(void *object)
 {
-  assert(string);
-  if (string->size == PNI_NULL_SIZE) {
-    return 0;
-  } else {
-    return string->size;
+  if (object) {
+    pni_head(object)->refcount++;
   }
 }
 
-int pn_string_set(pn_string_t *string, const char *bytes)
+int pn_object_refcount(void *object)
 {
-  return pn_string_setn(string, bytes, bytes ? strlen(bytes) : 0);
-}
-
-int pn_string_grow(pn_string_t *string, size_t capacity)
-{
-  bool grow = false;
-  while (string->capacity < (capacity*sizeof(char) + 1)) {
-    string->capacity *= 2;
-    grow = true;
-  }
-
-  if (grow) {
-    char *growed = (char *) realloc(string->bytes, string->capacity);
-    if (growed) {
-      string->bytes = growed;
-    } else {
-      return PN_ERR;
-    }
-  }
-
-  return 0;
+  assert(object);
+  return pni_head(object)->refcount;
 }
 
-int pn_string_setn(pn_string_t *string, const char *bytes, size_t n)
+void pn_object_decref(void *object)
 {
-  int err = pn_string_grow(string, n);
-  if (err) return err;
-
-  if (bytes) {
-    memcpy(string->bytes, bytes, n*sizeof(char));
-    string->bytes[n] = '\0';
-    string->size = n;
-  } else {
-    string->size = PNI_NULL_SIZE;
-  }
-
-  return 0;
+  pni_head_t *head = pni_head(object);
+  assert(head->refcount > 0);
+  head->refcount--;
 }
 
-ssize_t pn_string_put(pn_string_t *string, char *dst)
+void pn_object_free(void *object)
 {
-  assert(string);
-  assert(dst);
-
-  if (string->size != PNI_NULL_SIZE) {
-    memcpy(dst, string->bytes, string->size + 1);
-  }
-
-  return string->size;
+  pni_head_t *head = pni_head(object);
+  free(head);
 }
 
-void pn_string_clear(pn_string_t *string)
+void *pn_incref(void *object)
 {
-  pn_string_set(string, NULL);
+  return pn_class_incref(PN_OBJECT, object);
 }
 
-int pn_string_format(pn_string_t *string, const char *format, ...)
+int pn_decref(void *object)
 {
-  va_list ap;
-
-  va_start(ap, format);
-  int err = pn_string_vformat(string, format, ap);
-  va_end(ap);
-  return err;
+  return pn_class_decref(PN_OBJECT, object);
 }
 
-int pn_string_vformat(pn_string_t *string, const char *format, va_list ap)
+int pn_refcount(void *object)
 {
-  pn_string_set(string, "");
-  return pn_string_vaddf(string, format, ap);
+  return pn_class_refcount(PN_OBJECT, object);
 }
 
-int pn_string_addf(pn_string_t *string, const char *format, ...)
+void pn_free(void *object)
 {
-  va_list ap;
-
-  va_start(ap, format);
-  int err = pn_string_vaddf(string, format, ap);
-  va_end(ap);
-  return err;
+  pn_class_free(PN_OBJECT, object);
 }
 
-int pn_string_vaddf(pn_string_t *string, const char *format, va_list ap)
+const pn_class_t *pn_class(void *object)
 {
-  va_list copy;
-
-  if (string->size == PNI_NULL_SIZE) {
-    return PN_ERR;
-  }
-
-  while (true) {
-    va_copy(copy, ap);
-    int err = vsnprintf(string->bytes + string->size, string->capacity - string->size, format, copy);
-    va_end(copy);
-    if (err < 0) {
-      return err;
-    } else if ((size_t) err >= string->capacity - string->size) {
-      pn_string_grow(string, string->size + err);
-    } else {
-      string->size += err;
-      return 0;
-    }
-  }
+  return pn_class_reify(PN_OBJECT, object);
 }
 
-char *pn_string_buffer(pn_string_t *string)
+uintptr_t pn_hashcode(void *object)
 {
-  assert(string);
-  return string->bytes;
+  return pn_class_hashcode(PN_OBJECT, object);
 }
 
-size_t pn_string_capacity(pn_string_t *string)
+intptr_t pn_compare(void *a, void *b)
 {
-  assert(string);
-  return string->capacity - 1;
+  return pn_class_compare(PN_OBJECT, a, b);
 }
 
-int pn_string_resize(pn_string_t *string, size_t size)
+bool pn_equals(void *a, void *b)
 {
-  assert(string);
-  int err = pn_string_grow(string, size);
-  if (err) return err;
-  string->size = size;
-  string->bytes[size] = '\0';
-  return 0;
+  return !pn_compare(a, b);
 }
 
-int pn_string_copy(pn_string_t *string, pn_string_t *src)
+int pn_inspect(void *object, pn_string_t *dst)
 {
-  assert(string);
-  return pn_string_setn(string, pn_string_get(src), pn_string_size(src));
+  return pn_class_inspect(PN_OBJECT, object, dst);
 }
 
-struct pn_iterator_t {
-  pn_iterator_next_t next;
-  size_t size;
-  void *state;
-};
+#define pn_weakref_new NULL
+#define pn_weakref_initialize NULL
+#define pn_weakref_finalize NULL
+#define pn_weakref_free NULL
 
-static void pn_iterator_initialize(void *object)
-{
-  pn_iterator_t *it = (pn_iterator_t *) object;
-  it->next = NULL;
-  it->size = 0;
-  it->state = NULL;
+static void pn_weakref_incref(void *object) {}
+static void pn_weakref_decref(void *object) {}
+static int pn_weakref_refcount(void *object) { return -1; }
+static const pn_class_t *pn_weakref_reify(void *object) {
+  return PN_WEAKREF;
 }
-
-static void pn_iterator_finalize(void *object)
-{
-  pn_iterator_t *it = (pn_iterator_t *) object;
-  free(it->state);
+static uintptr_t pn_weakref_hashcode(void *object) {
+  return pn_hashcode(object);
 }
-
-#define pn_iterator_hashcode NULL
-#define pn_iterator_compare NULL
-#define pn_iterator_inspect NULL
-
-pn_iterator_t *pn_iterator()
-{
-  static const pn_class_t clazz = PN_CLASS(pn_iterator);
-  pn_iterator_t *it = (pn_iterator_t *) pn_new(sizeof(pn_iterator_t), &clazz);
-  return it;
+static intptr_t pn_weakref_compare(void *a, void *b) {
+  return pn_compare(a, b);
 }
-
-void  *pn_iterator_start(pn_iterator_t *iterator, pn_iterator_next_t next,
-                         size_t size) {
-  assert(iterator);
-  assert(next);
-  iterator->next = next;
-  if (iterator->size < size) {
-    iterator->state = realloc(iterator->state, size);
-  }
-  return iterator->state;
+static int pn_weakref_inspect(void *object, pn_string_t *dst) {
+  return pn_inspect(object, dst);
 }
 
-void *pn_iterator_next(pn_iterator_t *iterator) {
-  assert(iterator);
-  if (iterator->next) {
-    void *result = iterator->next(iterator->state);
-    if (!result) iterator->next = NULL;
-    return result;
-  } else {
-    return NULL;
-  }
-}
+const pn_class_t PNI_WEAKREF = PN_METACLASS(pn_weakref);
+const pn_class_t *PN_WEAKREF = &PNI_WEAKREF;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/object/string.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/string.c b/proton-c/src/object/string.c
new file mode 100644
index 0000000..7b900ca
--- /dev/null
+++ b/proton-c/src/object/string.c
@@ -0,0 +1,270 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "platform.h"
+
+#include <proton/error.h>
+#include <proton/object.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#define PNI_NULL_SIZE (-1)
+
+struct pn_string_t {
+  char *bytes;
+  ssize_t size;       // PNI_NULL_SIZE (-1) means null
+  size_t capacity;
+};
+
+static void pn_string_finalize(void *object)
+{
+  pn_string_t *string = (pn_string_t *) object;
+  free(string->bytes);
+}
+
+static uintptr_t pn_string_hashcode(void *object)
+{
+  pn_string_t *string = (pn_string_t *) object;
+  if (string->size == PNI_NULL_SIZE) {
+    return 0;
+  }
+
+  uintptr_t hashcode = 1;
+  for (ssize_t i = 0; i < string->size; i++) {
+    hashcode = hashcode * 31 + string->bytes[i];
+  }
+  return hashcode;
+}
+
+static intptr_t pn_string_compare(void *oa, void *ob)
+{
+  pn_string_t *a = (pn_string_t *) oa;
+  pn_string_t *b = (pn_string_t *) ob;
+  if (a->size != b->size) {
+    return b->size - a->size;
+  }
+
+  if (a->size == PNI_NULL_SIZE) {
+    return 0;
+  } else {
+    return memcmp(a->bytes, b->bytes, a->size);
+  }
+}
+
+static int pn_string_inspect(void *obj, pn_string_t *dst)
+{
+  pn_string_t *str = (pn_string_t *) obj;
+  if (str->size == PNI_NULL_SIZE) {
+    return pn_string_addf(dst, "null");
+  }
+
+  int err = pn_string_addf(dst, "\"");
+
+  for (int i = 0; i < str->size; i++) {
+    uint8_t c = str->bytes[i];
+    if (isprint(c)) {
+      err = pn_string_addf(dst, "%c", c);
+      if (err) return err;
+    } else {
+      err = pn_string_addf(dst, "\\x%.2x", c);
+      if (err) return err;
+    }
+  }
+
+  return pn_string_addf(dst, "\"");
+}
+
+pn_string_t *pn_string(const char *bytes)
+{
+  return pn_stringn(bytes, bytes ? strlen(bytes) : 0);
+}
+
+#define pn_string_initialize NULL
+
+
+pn_string_t *pn_stringn(const char *bytes, size_t n)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_string);
+  pn_string_t *string = (pn_string_t *) pn_class_new(&clazz, sizeof(pn_string_t));
+  string->capacity = n ? n * sizeof(char) : 16;
+  string->bytes = (char *) malloc(string->capacity);
+  pn_string_setn(string, bytes, n);
+  return string;
+}
+
+const char *pn_string_get(pn_string_t *string)
+{
+  assert(string);
+  if (string->size == PNI_NULL_SIZE) {
+    return NULL;
+  } else {
+    return string->bytes;
+  }
+}
+
+size_t pn_string_size(pn_string_t *string)
+{
+  assert(string);
+  if (string->size == PNI_NULL_SIZE) {
+    return 0;
+  } else {
+    return string->size;
+  }
+}
+
+int pn_string_set(pn_string_t *string, const char *bytes)
+{
+  return pn_string_setn(string, bytes, bytes ? strlen(bytes) : 0);
+}
+
+int pn_string_grow(pn_string_t *string, size_t capacity)
+{
+  bool grow = false;
+  while (string->capacity < (capacity*sizeof(char) + 1)) {
+    string->capacity *= 2;
+    grow = true;
+  }
+
+  if (grow) {
+    char *growed = (char *) realloc(string->bytes, string->capacity);
+    if (growed) {
+      string->bytes = growed;
+    } else {
+      return PN_ERR;
+    }
+  }
+
+  return 0;
+}
+
+int pn_string_setn(pn_string_t *string, const char *bytes, size_t n)
+{
+  int err = pn_string_grow(string, n);
+  if (err) return err;
+
+  if (bytes) {
+    memcpy(string->bytes, bytes, n*sizeof(char));
+    string->bytes[n] = '\0';
+    string->size = n;
+  } else {
+    string->size = PNI_NULL_SIZE;
+  }
+
+  return 0;
+}
+
+ssize_t pn_string_put(pn_string_t *string, char *dst)
+{
+  assert(string);
+  assert(dst);
+
+  if (string->size != PNI_NULL_SIZE) {
+    memcpy(dst, string->bytes, string->size + 1);
+  }
+
+  return string->size;
+}
+
+void pn_string_clear(pn_string_t *string)
+{
+  pn_string_set(string, NULL);
+}
+
+int pn_string_format(pn_string_t *string, const char *format, ...)
+{
+  va_list ap;
+
+  va_start(ap, format);
+  int err = pn_string_vformat(string, format, ap);
+  va_end(ap);
+  return err;
+}
+
+int pn_string_vformat(pn_string_t *string, const char *format, va_list ap)
+{
+  pn_string_set(string, "");
+  return pn_string_vaddf(string, format, ap);
+}
+
+int pn_string_addf(pn_string_t *string, const char *format, ...)
+{
+  va_list ap;
+
+  va_start(ap, format);
+  int err = pn_string_vaddf(string, format, ap);
+  va_end(ap);
+  return err;
+}
+
+int pn_string_vaddf(pn_string_t *string, const char *format, va_list ap)
+{
+  va_list copy;
+
+  if (string->size == PNI_NULL_SIZE) {
+    return PN_ERR;
+  }
+
+  while (true) {
+    va_copy(copy, ap);
+    int err = vsnprintf(string->bytes + string->size, string->capacity - string->size, format, copy);
+    va_end(copy);
+    if (err < 0) {
+      return err;
+    } else if ((size_t) err >= string->capacity - string->size) {
+      pn_string_grow(string, string->size + err);
+    } else {
+      string->size += err;
+      return 0;
+    }
+  }
+}
+
+char *pn_string_buffer(pn_string_t *string)
+{
+  assert(string);
+  return string->bytes;
+}
+
+size_t pn_string_capacity(pn_string_t *string)
+{
+  assert(string);
+  return string->capacity - 1;
+}
+
+int pn_string_resize(pn_string_t *string, size_t size)
+{
+  assert(string);
+  int err = pn_string_grow(string, size);
+  if (err) return err;
+  string->size = size;
+  string->bytes[size] = '\0';
+  return 0;
+}
+
+int pn_string_copy(pn_string_t *string, pn_string_t *src)
+{
+  assert(string);
+  return pn_string_setn(string, pn_string_get(src), pn_string_size(src));
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/platform.c
----------------------------------------------------------------------
diff --git a/proton-c/src/platform.c b/proton-c/src/platform.c
index 1f2cac7..8f8ac5f 100644
--- a/proton-c/src/platform.c
+++ b/proton-c/src/platform.c
@@ -21,7 +21,6 @@
 
 #include "platform.h"
 #include "util.h"
-#include "proton/util.h" // for pn_fatal() ?should pn_fatal() be public?
 
 /* Allow for systems that do not implement clock_gettime()*/
 #ifdef USE_CLOCK_GETTIME
@@ -29,7 +28,7 @@
 pn_timestamp_t pn_i_now(void)
 {
   struct timespec now;
-  if (clock_gettime(CLOCK_REALTIME, &now)) pn_fatal("clock_gettime() failed\n");
+  if (clock_gettime(CLOCK_REALTIME, &now)) pni_fatal("clock_gettime() failed\n");
   return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_nsec / 1000000);
 }
 #elif defined(USE_WIN_FILETIME)
@@ -49,7 +48,7 @@ pn_timestamp_t pn_i_now(void)
 pn_timestamp_t pn_i_now(void)
 {
   struct timeval now;
-  if (gettimeofday(&now, NULL)) pn_fatal("gettimeofday failed\n");
+  if (gettimeofday(&now, NULL)) pni_fatal("gettimeofday failed\n");
   return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_usec / 1000);
 }
 #endif
@@ -93,12 +92,12 @@ char* pn_i_genuuid(void) {
 #ifdef USE_STRERROR_R
 #include <string.h>
 static void pn_i_strerror(int errnum, char *buf, size_t buflen) {
-  if (strerror_r(errnum, buf, buflen) != 0) pn_fatal("strerror_r() failed\n");
+  if (strerror_r(errnum, buf, buflen) != 0) pni_fatal("strerror_r() failed\n");
 }
 #elif USE_STRERROR_S
 #include <string.h>
 static void pn_i_strerror(int errnum, char *buf, size_t buflen) {
-  if (strerror_s(buf, buflen, errnum) != 0) pn_fatal("strerror_s() failed\n");
+  if (strerror_s(buf, buflen, errnum) != 0) pni_fatal("strerror_s() failed\n");
 }
 #elif USE_OLD_STRERROR
 // This is thread safe on some platforms, and the only option on others

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/posix/driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/driver.c b/proton-c/src/posix/driver.c
index b128cb2..d71ca7d 100644
--- a/proton-c/src/posix/driver.c
+++ b/proton-c/src/posix/driver.c
@@ -37,11 +37,9 @@
 #include <proton/io.h>
 #include <proton/sasl.h>
 #include <proton/ssl.h>
-#include <proton/util.h>
 #include <proton/object.h>
-#include "../util.h"
-#include "../platform.h"
-#include "../ssl/ssl-internal.h"
+#include "util.h"
+#include "platform.h"
 
 /* Decls */
 
@@ -342,12 +340,12 @@ void pn_connector_set_connection(pn_connector_t *ctor, pn_connection_t *connecti
 {
   if (!ctor) return;
   if (ctor->connection) {
-    pn_decref(ctor->connection);
+    pn_class_decref(PN_OBJECT, ctor->connection);
     pn_transport_unbind(ctor->transport);
   }
   ctor->connection = connection;
   if (ctor->connection) {
-    pn_incref(ctor->connection);
+    pn_class_incref(PN_OBJECT, ctor->connection);
     pn_transport_bind(ctor->transport, connection);
   }
   if (ctor->transport) pn_transport_trace(ctor->transport, ctor->trace);
@@ -404,7 +402,7 @@ void pn_connector_free(pn_connector_t *ctor)
   if (ctor->driver) pn_driver_remove_connector(ctor->driver, ctor);
   pn_transport_free(ctor->transport);
   ctor->transport = NULL;
-  if (ctor->connection) pn_decref(ctor->connection);
+  if (ctor->connection) pn_class_decref(PN_OBJECT, ctor->connection);
   ctor->connection = NULL;
   free(ctor);
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/posix/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/io.c b/proton-c/src/posix/io.c
index 4fa223f..8fbbb0b 100644
--- a/proton-c/src/posix/io.c
+++ b/proton-c/src/posix/io.c
@@ -35,7 +35,7 @@
 #include <fcntl.h>
 #include <assert.h>
 
-#include "../platform.h"
+#include "platform.h"
 
 #define MAX_HOST (1024)
 #define MAX_SERV (64)
@@ -69,7 +69,7 @@ void pn_io_finalize(void *obj)
 pn_io_t *pn_io(void)
 {
   static const pn_class_t clazz = PN_CLASS(pn_io);
-  pn_io_t *io = (pn_io_t *) pn_new(sizeof(pn_io_t), &clazz);
+  pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
   return io;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/posix/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/selector.c b/proton-c/src/posix/selector.c
index 14a97ee..9c870a7 100644
--- a/proton-c/src/posix/selector.c
+++ b/proton-c/src/posix/selector.c
@@ -24,9 +24,9 @@
 #include <poll.h>
 #include <stdlib.h>
 #include <assert.h>
-#include "../platform.h"
-#include "../selectable.h"
-#include "../util.h"
+#include "platform.h"
+#include "selectable.h"
+#include "util.h"
 
 struct pn_selector_t {
   struct pollfd *fds;
@@ -45,7 +45,7 @@ void pn_selector_initialize(void *obj)
   selector->fds = NULL;
   selector->deadlines = NULL;
   selector->capacity = 0;
-  selector->selectables = pn_list(0, 0);
+  selector->selectables = pn_list(PN_WEAKREF, 0);
   selector->deadline = 0;
   selector->current = 0;
   selector->awoken = 0;
@@ -68,7 +68,7 @@ void pn_selector_finalize(void *obj)
 pn_selector_t *pni_selector(void)
 {
   static const pn_class_t clazz = PN_CLASS(pn_selector);
-  pn_selector_t *selector = (pn_selector_t *) pn_new(sizeof(pn_selector_t), &clazz);
+  pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
   return selector;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/proton.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proton.c b/proton-c/src/proton.c
index 2b7d313..495659a 100644
--- a/proton-c/src/proton.c
+++ b/proton-c/src/proton.c
@@ -29,16 +29,18 @@
 #include "pncompat/misc_funcs.inc"
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <proton/driver.h>
-#include <proton/message.h>
-#include <proton/util.h>
+
+#include "proton/buffer.h"
+#include "proton/codec.h"
+#include "proton/driver.h"
+#include "proton/engine.h"
+#include "proton/message.h"
+#include "proton/version.h"
 #include "util.h"
-#include <proton/version.h>
-#include <proton/codec.h>
-#include <proton/buffer.h>
-#include <proton/parser.h>
 #include "platform_fmt.h"
+
 #include "protocol.h"
 
 void error_exit(const char* fmt, ...)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 9c7ba1e..f926b1b 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -25,13 +25,13 @@
 #include <string.h>
 #include <proton/buffer.h>
 #include <proton/framing.h>
-#include <proton/engine.h> // XXX: just needed for PN_EOS
+#include <proton/error.h>
 #include <proton/sasl.h>
 #include "protocol.h"
 #include "dispatch_actions.h"
-#include "../dispatcher/dispatcher.h"
-#include "../engine/engine-internal.h"
-#include "../util.h"
+#include "engine/engine-internal.h"
+#include "dispatcher/dispatcher.h"
+#include "util.h"
 
 
 struct pn_sasl_t {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/selectable.c
----------------------------------------------------------------------
diff --git a/proton-c/src/selectable.c b/proton-c/src/selectable.c
index 1f39a38..d3adee4 100644
--- a/proton-c/src/selectable.c
+++ b/proton-c/src/selectable.c
@@ -91,7 +91,7 @@ pn_selectable_t *pni_selectable(ssize_t (*capacity)(pn_selectable_t *),
                                 void (*finalize)(pn_selectable_t *))
 {
   static const pn_class_t clazz = PN_CLASS(pn_selectable);
-  pn_selectable_t *selectable = (pn_selectable_t *) pn_new(sizeof(pn_selectable_t), &clazz);
+  pn_selectable_t *selectable = (pn_selectable_t *) pn_class_new(&clazz, sizeof(pn_selectable_t));
   selectable->capacity = capacity;
   selectable->pending = pending;
   selectable->readable = readable;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index db3af4c..62556fa 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -20,11 +20,10 @@
  */
 
 #include <proton/ssl.h>
-#include "./ssl-internal.h"
 #include <proton/engine.h>
-#include "../engine/engine-internal.h"
-#include "../platform.h"
-#include "../util.h"
+#include "engine/engine-internal.h"
+#include "platform.h"
+#include "util.h"
 
 #include <openssl/ssl.h>
 #include <openssl/dh.h>
@@ -197,7 +196,7 @@ static int ssl_failed(pn_ssl_t *ssl)
     ERR_error_string_n( ssl_err, buf, sizeof(buf) );
   }
   _log_ssl_error(NULL);    // spit out any remaining errors to the log file
-  ssl->transport->tail_closed = true;
+  pni_close_tail(ssl->transport);
   pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: %s", buf);
   return PN_EOS;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/ssl/ssl_stub.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/ssl_stub.c b/proton-c/src/ssl/ssl_stub.c
index 435f1e4..300215a 100644
--- a/proton-c/src/ssl/ssl_stub.c
+++ b/proton-c/src/ssl/ssl_stub.c
@@ -20,6 +20,8 @@
  */
 
 #include <proton/ssl.h>
+#include <proton/error.h>
+#include <proton/transport.h>
 
 
 /** @file

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/tests/object.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/object.c b/proton-c/src/tests/object.c
index f6d11cf..ad83006 100644
--- a/proton-c/src/tests/object.c
+++ b/proton-c/src/tests/object.c
@@ -30,12 +30,12 @@
 static char mem;
 static void *END = &mem;
 
-static pn_list_t *build_list(size_t capacity, int options, ...)
+static pn_list_t *build_list(size_t capacity, ...)
 {
-  pn_list_t *result = pn_list(capacity, options);
+  pn_list_t *result = pn_list(PN_OBJECT, capacity);
   va_list ap;
 
-  va_start(ap, options);
+  va_start(ap, capacity);
   while (true) {
     void *arg = va_arg(ap, void *);
     if (arg == END) {
@@ -43,23 +43,21 @@ static pn_list_t *build_list(size_t capacity, int options, ...)
     }
 
     pn_list_add(result, arg);
-    if (PN_REFCOUNT & options) {
-      pn_decref(arg);
-    }
+    pn_class_decref(PN_OBJECT, arg);
   }
   va_end(ap);
 
   return result;
 }
 
-static pn_map_t *build_map(size_t capacity, float load_factor, int options, ...)
+static pn_map_t *build_map(size_t capacity, float load_factor, ...)
 {
-  pn_map_t *result = pn_map(capacity, load_factor, options);
+  pn_map_t *result = pn_map(PN_OBJECT, PN_OBJECT, capacity, load_factor);
   va_list ap;
 
   void *prev = NULL;
 
-  va_start(ap, options);
+  va_start(ap, load_factor);
   int count = 0;
   while (true) {
     void *arg = va_arg(ap, void *);
@@ -70,10 +68,8 @@ static pn_map_t *build_map(size_t capacity, float load_factor, int options, ...)
 
     if (count % 2) {
       pn_map_put(result, prev, arg);
-      if (PN_REFCOUNT & options) {
-        pn_decref(prev);
-        pn_decref(arg);
-      }
+      pn_class_decref(PN_OBJECT, prev);
+      pn_class_decref(PN_OBJECT, arg);
     } else {
       prev = arg;
     }
@@ -93,15 +89,51 @@ static void noop(void *o) {}
 static uintptr_t zero(void *o) { return 0; }
 static intptr_t delta(void *a, void *b) { return (uintptr_t) b - (uintptr_t) a; }
 
-static pn_class_t null_class = {0};
+#define CID_noop CID_pn_object
+#define noop_initialize noop
+#define noop_finalize noop
+#define noop_hashcode zero
+#define noop_compare delta
+#define noop_inspect NULL
 
-static pn_class_t noop_class = {NULL, noop, noop, zero, delta};
+static const pn_class_t noop_class = PN_CLASS(noop);
 
-static void test_new(size_t size, pn_class_t *clazz)
+static void test_class(const pn_class_t *clazz, size_t size)
 {
-  void *obj = pn_new(size, clazz);
+  void *a = pn_class_new(clazz, size);
+  void *b = pn_class_new(clazz, size);
+
+  assert(!pn_class_equals(clazz, a, b));
+  assert(pn_class_equals(clazz, a, a));
+  assert(pn_class_equals(clazz, b, b));
+  assert(!pn_class_equals(clazz, a, NULL));
+  assert(!pn_class_equals(clazz, NULL, a));
+
+  int rca = pn_class_refcount(clazz, a);
+  int rcb = pn_class_refcount(clazz, b);
+
+  assert(rca == -1 || rca == 1);
+  assert(rcb == -1 || rcb == 1);
+
+  pn_class_incref(clazz, a);
+
+  rca = pn_class_refcount(clazz, a);
+  assert(rca == -1 || rca == 2);
+
+  pn_class_decref(clazz, a);
+
+  rca = pn_class_refcount(clazz, a);
+  assert(rca == -1 || rca == 1);
+
+  pn_class_free(clazz, a);
+  pn_class_free(clazz, b);
+}
+
+static void test_new(size_t size, const pn_class_t *clazz)
+{
+  void *obj = pn_class_new(clazz, size);
   assert(obj);
-  assert(pn_refcount(obj) == 1);
+  assert(pn_class_refcount(PN_OBJECT, obj) == 1);
   assert(pn_class(obj) == clazz);
   char *bytes = (char *) obj;
   for (size_t i = 0; i < size; i++) {
@@ -117,11 +149,18 @@ static void finalizer(void *object)
   (**called)++;
 }
 
+#define CID_finalizer CID_pn_object
+#define finalizer_initialize NULL
+#define finalizer_finalize finalizer
+#define finalizer_hashcode NULL
+#define finalizer_compare NULL
+#define finalizer_inspect NULL
+
 static void test_finalize(void)
 {
-  static pn_class_t clazz = {NULL, NULL, finalizer};
+  static pn_class_t clazz = PN_CLASS(finalizer);
 
-  int **obj = (int **) pn_new(sizeof(int **), &clazz);
+  int **obj = (int **) pn_class_new(&clazz, sizeof(int **));
   assert(obj);
 
   int called = 0;
@@ -139,23 +178,37 @@ static void test_free(void)
 
 static uintptr_t hashcode(void *obj) { return (uintptr_t) obj; }
 
+#define CID_hashcode CID_pn_object
+#define hashcode_initialize NULL
+#define hashcode_finalize NULL
+#define hashcode_compare NULL
+#define hashcode_hashcode hashcode
+#define hashcode_inspect NULL
+
 static void test_hashcode(void)
 {
-  static pn_class_t clazz = {NULL, NULL, NULL, hashcode};
-  void *obj = pn_new(0, &clazz);
+  static pn_class_t clazz = PN_CLASS(hashcode);
+  void *obj = pn_class_new(&clazz, 0);
   assert(obj);
   assert(pn_hashcode(obj) == (uintptr_t) obj);
   assert(pn_hashcode(NULL) == 0);
   pn_free(obj);
 }
 
+#define CID_compare CID_pn_object
+#define compare_initialize NULL
+#define compare_finalize NULL
+#define compare_compare delta
+#define compare_hashcode NULL
+#define compare_inspect NULL
+
 static void test_compare(void)
 {
-  static pn_class_t clazz = {NULL, NULL, NULL, NULL, delta};
+  static pn_class_t clazz = PN_CLASS(compare);
 
-  void *a = pn_new(0, &clazz);
+  void *a = pn_class_new(&clazz, 0);
   assert(a);
-  void *b = pn_new(0, &clazz);
+  void *b = pn_class_new(&clazz, 0);
   assert(b);
 
   assert(pn_compare(a, b));
@@ -181,7 +234,7 @@ static void test_compare(void)
 
 static void test_refcounting(int refs)
 {
-  void *obj = pn_new(0, NULL);
+  void *obj = pn_class_new(PN_OBJECT, 0);
 
   assert(pn_refcount(obj) == 1);
 
@@ -204,7 +257,7 @@ static void test_refcounting(int refs)
 
 static void test_list(size_t capacity)
 {
-  pn_list_t *list = pn_list(0, 0);
+  pn_list_t *list = pn_list(PN_WEAKREF, 0);
   assert(pn_list_size(list) == 0);
   assert(!pn_list_add(list, (void *) 0));
   assert(!pn_list_add(list, (void *) 1));
@@ -224,12 +277,12 @@ static void test_list(size_t capacity)
 
 static void test_list_refcount(size_t capacity)
 {
-  void *one = pn_new(0, NULL);
-  void *two = pn_new(0, NULL);
-  void *three = pn_new(0, NULL);
-  void *four = pn_new(0, NULL);
+  void *one = pn_class_new(PN_OBJECT, 0);
+  void *two = pn_class_new(PN_OBJECT, 0);
+  void *three = pn_class_new(PN_OBJECT, 0);
+  void *four = pn_class_new(PN_OBJECT, 0);
 
-  pn_list_t *list = pn_list(0, PN_REFCOUNT);
+  pn_list_t *list = pn_list(PN_OBJECT, 0);
   assert(!pn_list_add(list, one));
   assert(!pn_list_add(list, two));
   assert(!pn_list_add(list, three));
@@ -281,7 +334,7 @@ static void check_list_index(pn_list_t *list, void *value, ssize_t idx)
 
 static void test_list_index(void)
 {
-  pn_list_t *l = pn_list(0, 0);
+  pn_list_t *l = pn_list(PN_WEAKREF, 0);
   void *one = pn_string("one");
   void *two = pn_string("two");
   void *three = pn_string("three");
@@ -324,7 +377,7 @@ static bool pn_strequals(const char *a, const char *b)
 
 static void test_build_list(void)
 {
-  pn_list_t *l = build_list(0, PN_REFCOUNT,
+  pn_list_t *l = build_list(0,
                             pn_string("one"),
                             pn_string("two"),
                             pn_string("three"),
@@ -344,7 +397,7 @@ static void test_build_list(void)
 
 static void test_build_map(void)
 {
-  pn_map_t *m = build_map(0, 0.75, PN_REFCOUNT,
+  pn_map_t *m = build_map(0, 0.75,
                           pn_string("key"),
                           pn_string("value"),
                           pn_string("key2"),
@@ -368,7 +421,7 @@ static void test_build_map(void)
 
 static void test_build_map_odd(void)
 {
-  pn_map_t *m = build_map(0, 0.75, PN_REFCOUNT,
+  pn_map_t *m = build_map(0, 0.75,
                           pn_string("key"),
                           pn_string("value"),
                           pn_string("key2"),
@@ -395,11 +448,11 @@ static void test_build_map_odd(void)
 
 static void test_map(void)
 {
-  void *one = pn_new(0, NULL);
-  void *two = pn_new(0, NULL);
-  void *three = pn_new(0, NULL);
+  void *one = pn_class_new(PN_OBJECT, 0);
+  void *two = pn_class_new(PN_OBJECT, 0);
+  void *three = pn_class_new(PN_OBJECT, 0);
 
-  pn_map_t *map = pn_map(4, 0.75, PN_REFCOUNT);
+  pn_map_t *map = pn_map(PN_OBJECT, PN_OBJECT, 4, 0.75);
   assert(pn_map_size(map) == 0);
 
   pn_string_t *key = pn_string("key");
@@ -458,11 +511,11 @@ static void test_map(void)
 
 static void test_hash(void)
 {
-  void *one = pn_new(0, NULL);
-  void *two = pn_new(0, NULL);
-  void *three = pn_new(0, NULL);
+  void *one = pn_class_new(PN_OBJECT, 0);
+  void *two = pn_class_new(PN_OBJECT, 0);
+  void *three = pn_class_new(PN_OBJECT, 0);
 
-  pn_hash_t *hash = pn_hash(4, 0.75, PN_REFCOUNT);
+  pn_hash_t *hash = pn_hash(PN_OBJECT, 4, 0.75);
   pn_hash_put(hash, 0, NULL);
   pn_hash_put(hash, 1, one);
   pn_hash_put(hash, 2, two);
@@ -512,6 +565,7 @@ static uintptr_t collider_hashcode(void *obj)
   return 23;
 }
 
+#define CID_collider CID_pn_object
 #define collider_initialize NULL
 #define collider_finalize NULL
 #define collider_inspect NULL
@@ -521,12 +575,12 @@ static void test_map_links(void)
   const pn_class_t collider_clazz = PN_CLASS(collider);
   void *keys[3];
   for (int i = 0; i < 3; i++)
-    keys[i] = pn_new(0, &collider_clazz);
+    keys[i] = pn_class_new(&collider_clazz, 0);
 
   // test deleting a head, middle link, tail
 
   for (int delete_idx=0; delete_idx < 3; delete_idx++) {
-    pn_map_t *map = pn_map(0, 0.75, 0);
+    pn_map_t *map = pn_map(PN_WEAKREF, PN_WEAKREF, 0, 0.75);
     // create a chain of entries that have same head (from identical key hashcode)
     for (int i = 0; i < 3; i++) {
       pn_map_put(map, keys[i], keys[i]);
@@ -637,17 +691,17 @@ static void test_string_addf(void)
 
 static void test_map_iteration(int n)
 {
-  pn_list_t *pairs = pn_list(2*n, PN_REFCOUNT);
+  pn_list_t *pairs = pn_list(PN_OBJECT, 2*n);
   for (int i = 0; i < n; i++) {
-    void *key = pn_new(0, NULL);
-    void *value = pn_new(0, NULL);
+    void *key = pn_class_new(PN_OBJECT, 0);
+    void *value = pn_class_new(PN_OBJECT, 0);
     pn_list_add(pairs, key);
     pn_list_add(pairs, value);
     pn_decref(key);
     pn_decref(value);
   }
 
-  pn_map_t *map = pn_map(0, 0.75, PN_REFCOUNT);
+  pn_map_t *map = pn_map(PN_OBJECT, PN_OBJECT, 0, 0.75);
 
   assert(pn_map_head(map) == 0);
 
@@ -684,22 +738,22 @@ void test_inspect(void *o, const char *expected)
 
 void test_list_inspect(void)
 {
-  pn_list_t *l = build_list(0, PN_REFCOUNT, END);
+  pn_list_t *l = build_list(0, END);
   test_inspect(l, "[]");
   pn_free(l);
 
-  l = build_list(0, PN_REFCOUNT, pn_string("one"), END);
+  l = build_list(0, pn_string("one"), END);
   test_inspect(l, "[\"one\"]");
   pn_free(l);
 
-  l = build_list(0, PN_REFCOUNT,
+  l = build_list(0,
                  pn_string("one"),
                  pn_string("two"),
                  END);
   test_inspect(l, "[\"one\", \"two\"]");
   pn_free(l);
 
-  l = build_list(0, PN_REFCOUNT,
+  l = build_list(0,
                  pn_string("one"),
                  pn_string("two"),
                  pn_string("three"),
@@ -713,24 +767,24 @@ void test_map_inspect(void)
   // note that when there is more than one entry in a map, the order
   // of the entries is dependent on the hashes involved, it will be
   // deterministic though
-  pn_map_t *m = build_map(0, 0.75, PN_REFCOUNT, END);
+  pn_map_t *m = build_map(0, 0.75, END);
   test_inspect(m, "{}");
   pn_free(m);
 
-  m = build_map(0, 0.75, PN_REFCOUNT,
+  m = build_map(0, 0.75,
                 pn_string("key"), pn_string("value"),
                 END);
   test_inspect(m, "{\"key\": \"value\"}");
   pn_free(m);
 
-  m = build_map(0, 0.75, PN_REFCOUNT,
+  m = build_map(0, 0.75,
                 pn_string("k1"), pn_string("v1"),
                 pn_string("k2"), pn_string("v2"),
                 END);
   test_inspect(m, "{\"k1\": \"v1\", \"k2\": \"v2\"}");
   pn_free(m);
 
-  m = build_map(0, 0.75, PN_REFCOUNT,
+  m = build_map(0, 0.75,
                 pn_string("k1"), pn_string("v1"),
                 pn_string("k2"), pn_string("v2"),
                 pn_string("k3"), pn_string("v3"),
@@ -741,14 +795,14 @@ void test_map_inspect(void)
 
 void test_list_compare(void)
 {
-  pn_list_t *a = pn_list(0, PN_REFCOUNT);
-  pn_list_t *b = pn_list(0, PN_REFCOUNT);
+  pn_list_t *a = pn_list(PN_OBJECT, 0);
+  pn_list_t *b = pn_list(PN_OBJECT, 0);
 
   assert(pn_equals(a, b));
 
-  void *one = pn_new(0, NULL);
-  void *two = pn_new(0, NULL);
-  void *three = pn_new(0, NULL);
+  void *one = pn_class_new(PN_OBJECT, 0);
+  void *two = pn_class_new(PN_OBJECT, 0);
+  void *three = pn_class_new(PN_OBJECT, 0);
 
   pn_list_add(a, one);
   assert(!pn_equals(a, b));
@@ -785,7 +839,7 @@ static void *pn_it_next(void *state) {
 
 void test_iterator(void)
 {
-  pn_list_t *list = build_list(0, PN_REFCOUNT,
+  pn_list_t *list = build_list(0,
                                pn_string("one"),
                                pn_string("two"),
                                pn_string("three"),
@@ -811,8 +865,13 @@ void test_iterator(void)
 int main(int argc, char **argv)
 {
   for (size_t i = 0; i < 128; i++) {
-    test_new(i, NULL);
-    test_new(i, &null_class);
+    test_class(PN_OBJECT, i);
+    test_class(PN_VOID, i);
+    test_class(&noop_class, i);
+  }
+
+  for (size_t i = 0; i < 128; i++) {
+    test_new(i, PN_OBJECT);
     test_new(i, &noop_class);
   }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/tests/parse-url.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/parse-url.c b/proton-c/src/tests/parse-url.c
index f57e739..829e9ab 100644
--- a/proton-c/src/tests/parse-url.c
+++ b/proton-c/src/tests/parse-url.c
@@ -20,7 +20,6 @@
  */
 
 #include <stdarg.h>
-#include <proton/type_compat.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -29,8 +28,9 @@
 #undef NDEBUG
 #include <assert.h>
 
-#include <proton/error.h>
-#include <proton/util.h>
+#include "proton/type_compat.h"
+#include "proton/error.h"
+#include "util.h"
 
 static inline bool equalStrP(const char* s1, const char* s2)
 {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
index 1ac2876..b4435ab 100644
--- a/proton-c/src/transport/transport.c
+++ b/proton-c/src/transport/transport.c
@@ -19,7 +19,7 @@
  *
  */
 
-#include "../engine/engine-internal.h"
+#include "engine/engine-internal.h"
 #include <stdlib.h>
 #include <string.h>
 #include <proton/framing.h>
@@ -30,12 +30,10 @@
 #include <stdarg.h>
 #include <stdio.h>
 
-#include "../engine/event.h"
-
-#include "../sasl/sasl-internal.h"
-#include "../ssl/ssl-internal.h"
-#include "../platform.h"
-#include "../platform_fmt.h"
+#include "sasl/sasl-internal.h"
+#include "ssl/ssl-internal.h"
+#include "platform.h"
+#include "platform_fmt.h"
 
 static ssize_t transport_consume(pn_transport_t *transport);
 
@@ -43,7 +41,7 @@ static ssize_t transport_consume(pn_transport_t *transport);
 
 void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next)
 {
-  db->deliveries = pn_hash(0, 0.75, PN_REFCOUNT);
+  db->deliveries = pn_hash(PN_OBJECT, 0, 0.75);
   db->next = next;
 }
 
@@ -91,6 +89,7 @@ void pn_delivery_map_clear(pn_delivery_map_t *dm)
     pn_delivery_t *dlv = (pn_delivery_t *) pn_hash_value(hash, entry);
     pn_delivery_map_del(dm, dlv);
   }
+  dm->next = 0;
 }
 
 static ssize_t pn_input_read_amqp_header(pn_io_layer_t *io_layer, const char *bytes, size_t available);
@@ -164,9 +163,10 @@ static void pn_transport_initialize(void *object)
   transport->remote_properties = pn_data(0);
   transport->disp_data = pn_data(0);
   pn_condition_init(&transport->remote_condition);
+  pn_condition_init(&transport->condition);
 
-  transport->local_channels = pn_hash(0, 0.75, PN_REFCOUNT);
-  transport->remote_channels = pn_hash(0, 0.75, PN_REFCOUNT);
+  transport->local_channels = pn_hash(PN_OBJECT, 0, 0.75);
+  transport->remote_channels = pn_hash(PN_OBJECT, 0, 0.75);
 
   transport->bytes_input = 0;
   transport->bytes_output = 0;
@@ -175,6 +175,9 @@ static void pn_transport_initialize(void *object)
   transport->output_pending = 0;
 
   transport->done_processing = false;
+
+  transport->posted_head_closed = false;
+  transport->posted_tail_closed = false;
 }
 
 pn_session_t *pn_channel_state(pn_transport_t *transport, uint16_t channel)
@@ -189,12 +192,12 @@ static void pni_map_remote_channel(pn_session_t *session, uint16_t channel)
   session->state.remote_channel = channel;
 }
 
-void pni_transport_unbind_handles(pn_hash_t *handles);
+void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state);
 
 static void pni_unmap_remote_channel(pn_session_t *ssn)
 {
   // XXX: should really update link state also
-  pni_transport_unbind_handles(ssn->state.remote_handles);
+  pni_transport_unbind_handles(ssn->state.remote_handles, false);
   pn_transport_t *transport = ssn->connection->transport;
   uint16_t channel = ssn->state.remote_channel;
   ssn->state.remote_channel = -2;
@@ -211,8 +214,8 @@ static void pn_transport_finalize(void *object);
 pn_transport_t *pn_transport()
 {
   static const pn_class_t clazz = PN_CLASS(pn_transport);
-  pn_transport_t *transport = (pn_transport_t *) pn_new(sizeof(pn_transport_t),
-                                                        &clazz);
+  pn_transport_t *transport =
+    (pn_transport_t *) pn_class_new(&clazz, sizeof(pn_transport_t));
   if (!transport) return NULL;
 
   transport->output_buf = (char *) malloc(transport->output_size);
@@ -254,6 +257,7 @@ static void pn_transport_finalize(void *object)
   pn_free(transport->remote_properties);
   pn_free(transport->disp_data);
   pn_condition_tini(&transport->remote_condition);
+  pn_condition_tini(&transport->condition);
   pn_free(transport->local_channels);
   pn_free(transport->remote_channels);
   if (transport->input_buf) free(transport->input_buf);
@@ -263,25 +267,36 @@ static void pn_transport_finalize(void *object)
 
 int pn_transport_bind(pn_transport_t *transport, pn_connection_t *connection)
 {
-  if (!transport) return PN_ARG_ERR;
+  assert(transport);
+  assert(connection);
+
   if (transport->connection) return PN_STATE_ERR;
   if (connection->transport) return PN_STATE_ERR;
+
   transport->connection = connection;
   connection->transport = transport;
-  pn_incref2(connection, transport);
+
+  pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_BOUND);
+
+  pn_incref(connection);
   if (transport->open_rcvd) {
     PN_SET_REMOTE(connection->endpoint.state, PN_REMOTE_ACTIVE);
-    pn_collector_put(connection->collector, PN_CONNECTION_REMOTE_OPEN, connection);
+    pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_REMOTE_OPEN);
     transport->disp->halt = false;
     transport_consume(transport);        // blech - testBindAfterOpen
   }
+
   return 0;
 }
 
-void pni_transport_unbind_handles(pn_hash_t *handles)
+void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state)
 {
   for (pn_handle_t h = pn_hash_head(handles); h; h = pn_hash_next(handles, h)) {
     uintptr_t key = pn_hash_key(handles, h);
+    if (reset_state) {
+      pn_link_t *link = (pn_link_t *) pn_hash_value(handles, h);
+      pn_link_unbound(link);
+    }
     pn_hash_del(handles, key);
   }
 }
@@ -291,8 +306,9 @@ void pni_transport_unbind_channels(pn_hash_t *channels)
   for (pn_handle_t h = pn_hash_head(channels); h; h = pn_hash_next(channels, h)) {
     uintptr_t key = pn_hash_key(channels, h);
     pn_session_t *ssn = (pn_session_t *) pn_hash_value(channels, h);
-    pni_transport_unbind_handles(ssn->state.local_handles);
-    pni_transport_unbind_handles(ssn->state.remote_handles);
+    pni_transport_unbind_handles(ssn->state.local_handles, true);
+    pni_transport_unbind_handles(ssn->state.remote_handles, true);
+    pn_session_unbound(ssn);
     pn_hash_del(channels, key);
   }
 }
@@ -302,9 +318,12 @@ int pn_transport_unbind(pn_transport_t *transport)
   assert(transport);
   if (!transport->connection) return 0;
 
+
   pn_connection_t *conn = transport->connection;
   transport->connection = NULL;
 
+  pn_collector_put(conn->collector, PN_OBJECT, conn, PN_CONNECTION_UNBOUND);
+
   // XXX: what happens if the endpoints are freed before we get here?
   pn_session_t *ssn = pn_session_head(conn, 0);
   while (ssn) {
@@ -324,7 +343,7 @@ int pn_transport_unbind(pn_transport_t *transport)
   pni_transport_unbind_channels(transport->remote_channels);
 
   pn_connection_unbound(conn);
-  pn_decref2(conn, transport);
+  pn_decref(conn);
   return 0;
 }
 
@@ -333,6 +352,12 @@ pn_error_t *pn_transport_error(pn_transport_t *transport)
   return NULL;
 }
 
+pn_condition_t *pn_transport_condition(pn_transport_t *transport)
+{
+  assert(transport);
+  return &transport->condition;
+}
+
 static void pni_map_remote_handle(pn_link_t *link, uint32_t handle)
 {
   link->state.remote_handle = handle;
@@ -413,6 +438,15 @@ int pn_post_close(pn_transport_t *transport, const char *condition, const char *
                        (bool) condition, ERROR, condition, description, info);
 }
 
+static pn_collector_t *pni_transport_collector(pn_transport_t *transport)
+{
+  if (transport->connection && transport->connection->collector) {
+    return transport->connection->collector;
+  } else {
+    return NULL;
+  }
+}
+
 int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...)
 {
   va_list ap;
@@ -430,6 +464,10 @@ int pn_do_error(pn_transport_t *transport, const char *condition, const char *fm
     transport->close_sent = true;
   }
   transport->disp->halt = true;
+  pn_condition_set_name(&transport->condition, condition);
+  pn_condition_set_description(&transport->condition, buf);
+  pn_collector_t *collector = pni_transport_collector(transport);
+  pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_ERROR);
   pn_transport_logf(transport, "ERROR %s %s", condition, buf);
   return PN_ERR;
 }
@@ -479,7 +517,7 @@ int pn_do_open(pn_dispatcher_t *disp)
 
   if (conn) {
     PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_ACTIVE);
-    pn_collector_put(conn->collector, PN_CONNECTION_REMOTE_OPEN, conn);
+    pn_collector_put(conn->collector, PN_OBJECT, conn, PN_CONNECTION_REMOTE_OPEN);
   } else {
     transport->disp->halt = true;
   }
@@ -508,7 +546,7 @@ int pn_do_begin(pn_dispatcher_t *disp)
   ssn->state.incoming_transfer_count = next;
   pni_map_remote_channel(ssn, disp->channel);
   PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_ACTIVE);
-  pn_collector_put(transport->connection->collector, PN_SESSION_REMOTE_OPEN, ssn);
+  pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_OPEN);
   return 0;
 }
 
@@ -682,7 +720,7 @@ int pn_do_attach(pn_dispatcher_t *disp)
     link->state.delivery_count = idc;
   }
 
-  pn_collector_put(transport->connection->collector, PN_LINK_REMOTE_OPEN, link);
+  pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_OPEN);
   return 0;
 }
 
@@ -763,7 +801,7 @@ int pn_do_transfer(pn_dispatcher_t *disp)
     pn_post_flow(transport, ssn, link);
   }
 
-  pn_collector_put(transport->connection->collector, PN_DELIVERY, delivery);
+  pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
   return 0;
 }
 
@@ -813,7 +851,7 @@ int pn_do_flow(pn_dispatcher_t *disp)
       }
     }
 
-    pn_collector_put(transport->connection->collector, PN_LINK_FLOW, link);
+    pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
   }
 
   return 0;
@@ -908,7 +946,7 @@ int pn_do_disposition(pn_dispatcher_t *disp)
       delivery->updated = true;
       pn_work_update(transport->connection, delivery);
 
-      pn_collector_put(transport->connection->collector, PN_DELIVERY, delivery);
+      pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
     }
   }
 
@@ -938,9 +976,9 @@ int pn_do_detach(pn_dispatcher_t *disp)
   if (closed)
   {
     PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_CLOSED);
-    pn_collector_put(transport->connection->collector, PN_LINK_REMOTE_CLOSE, link);
+    pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_CLOSE);
   } else {
-    // TODO: implement
+    pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_DETACH);
   }
 
   pni_unmap_remote_handle(link);
@@ -954,7 +992,7 @@ int pn_do_end(pn_dispatcher_t *disp)
   int err = pn_scan_error(disp->args, &ssn->endpoint.remote_condition, SCAN_ERROR_DEFAULT);
   if (err) return err;
   PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_CLOSED);
-  pn_collector_put(transport->connection->collector, PN_SESSION_REMOTE_CLOSE, ssn);
+  pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_CLOSE);
   pni_unmap_remote_channel(ssn);
   return 0;
 }
@@ -967,7 +1005,7 @@ int pn_do_close(pn_dispatcher_t *disp)
   if (err) return err;
   transport->close_rcvd = true;
   PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_CLOSED);
-  pn_collector_put(transport->connection->collector, PN_CONNECTION_REMOTE_CLOSE, conn);
+  pn_collector_put(transport->connection->collector, PN_OBJECT, conn, PN_CONNECTION_REMOTE_CLOSE);
   return 0;
 }
 
@@ -997,6 +1035,14 @@ ssize_t pn_transport_input(pn_transport_t *transport, const char *bytes, size_t
   return original - available;
 }
 
+static void pni_maybe_post_closed(pn_transport_t *transport)
+{
+  pn_collector_t *collector = pni_transport_collector(transport);
+  if (transport->posted_head_closed && transport->posted_tail_closed) {
+    pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_CLOSED);
+  }
+}
+
 // process pending input until none remaining or EOS
 static ssize_t transport_consume(pn_transport_t *transport)
 {
@@ -1018,6 +1064,12 @@ static ssize_t transport_consume(pn_transport_t *transport)
       if (transport->disp->trace & (PN_TRACE_RAW | PN_TRACE_FRM))
         pn_transport_log(transport, "  <- EOS");
       transport->input_pending = 0;  // XXX ???
+      if (!transport->posted_tail_closed) {
+        pn_collector_t *collector = pni_transport_collector(transport);
+        pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_TAIL_CLOSED);
+        transport->posted_tail_closed = true;
+        pni_maybe_post_closed(transport);
+      }
       return n;
     }
   }
@@ -1445,7 +1497,7 @@ int pn_process_tpwork_sender(pn_transport_t *transport, pn_delivery_t *delivery,
         link->session->outgoing_deliveries--;
       }
 
-      pn_collector_put(transport->connection->collector, PN_LINK_FLOW, link);
+      pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
     }
   }
 
@@ -1571,7 +1623,7 @@ int pn_process_link_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
     pn_session_t *session = link->session;
     pn_session_state_t *ssn_state = &session->state;
     pn_link_state_t *state = &link->state;
-    if (endpoint->state & PN_LOCAL_CLOSED && (int32_t) state->local_handle >= 0 &&
+    if (((endpoint->state & PN_LOCAL_CLOSED) || link->detached) && (int32_t) state->local_handle >= 0 &&
         (int16_t) ssn_state->local_channel >= 0 && !transport->close_sent) {
       if (pn_link_is_sender(link) && pn_link_queued(link) &&
           (int32_t) state->remote_handle != -2 &&
@@ -1588,8 +1640,10 @@ int pn_process_link_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
         info = pn_condition_info(&endpoint->condition);
       }
 
-      int err = pn_post_frame(transport->disp, ssn_state->local_channel, "DL[Io?DL[sSC]]", DETACH,
-                              state->local_handle, true, (bool) name, ERROR, name, description, info);
+      int err =
+          pn_post_frame(transport->disp, ssn_state->local_channel,
+                        "DL[Io?DL[sSC]]", DETACH, state->local_handle, !link->detached,
+                        (bool)name, ERROR, name, description, info);
       if (err) return err;
       pni_unmap_local_handle(link);
     }
@@ -1625,7 +1679,7 @@ bool pn_pointful_buffering(pn_transport_t *transport, pn_session_t *session)
 
 static void pni_unmap_local_channel(pn_session_t *ssn) {
   // XXX: should really update link state also
-  pni_transport_unbind_handles(ssn->state.local_handles);
+  pni_transport_unbind_handles(ssn->state.local_handles, false);
   pn_transport_t *transport = ssn->connection->transport;
   pn_session_state_t *state = &ssn->state;
   uintptr_t channel = state->local_channel;
@@ -2039,6 +2093,13 @@ ssize_t pn_transport_push(pn_transport_t *transport, const char *src, size_t siz
   }
 }
 
+void pni_close_tail(pn_transport_t *transport)
+{
+  if (!transport->tail_closed) {
+    transport->tail_closed = true;
+  }
+}
+
 int pn_transport_process(pn_transport_t *transport, size_t size)
 {
   assert(transport);
@@ -2048,7 +2109,7 @@ int pn_transport_process(pn_transport_t *transport, size_t size)
 
   ssize_t n = transport_consume( transport );
   if (n == PN_EOS) {
-    transport->tail_closed = true;
+    pni_close_tail(transport);
   }
 
   if (n < 0 && n != PN_EOS) return n;
@@ -2058,7 +2119,7 @@ int pn_transport_process(pn_transport_t *transport, size_t size)
 // input stream has closed
 int pn_transport_close_tail(pn_transport_t *transport)
 {
-  transport->tail_closed = true;
+  pni_close_tail(transport);
   transport_consume( transport );
   return 0;
   // XXX: what if not all input processed at this point?  do we care???
@@ -2110,6 +2171,14 @@ void pn_transport_pop(pn_transport_t *transport, size_t size)
       memmove( transport->output_buf,  &transport->output_buf[size],
                transport->output_pending );
     }
+
+    if (!transport->output_pending && pn_transport_pending(transport) < 0 &&
+        !transport->posted_head_closed) {
+      pn_collector_t *collector = pni_transport_collector(transport);
+      pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_HEAD_CLOSED);
+      transport->posted_head_closed = true;
+      pni_maybe_post_closed(transport);
+    }
   }
 }
 
@@ -2143,3 +2212,9 @@ bool pn_transport_closed(pn_transport_t *transport)
   ssize_t pending = pn_transport_pending(transport);
   return capacity < 0 && pending < 0;
 }
+
+pn_connection_t *pn_transport_connection(pn_transport_t *transport)
+{
+  assert(transport);
+  return transport->connection;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/url.c
----------------------------------------------------------------------
diff --git a/proton-c/src/url.c b/proton-c/src/url.c
new file mode 100644
index 0000000..12d6f9d
--- /dev/null
+++ b/proton-c/src/url.c
@@ -0,0 +1,168 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/url.h"
+#include "proton/object.h"
+#include "util.h"
+#include "platform.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+static char* copy(const char* str) {
+    if (str ==  NULL) return NULL;
+    char *str2 = (char*)malloc(strlen(str)+1);
+    if (str2) strcpy(str2, str);
+    return str2;
+}
+
+struct pn_url_t {
+    char *scheme;
+    char *username;
+    char *password;
+    char *host;
+    char *port;
+    char *path;
+    pn_string_t *str;
+};
+
+/** Internal use only, returns the pn_string_t. Public function is pn_url_str() */
+static pn_string_t *pn_url_string(pn_url_t* url)
+{
+    pn_url_str(url);               /* Make sure str is up to date */
+    return url->str;
+}
+
+static void pn_url_finalize(void *object)
+{
+    pn_url_t *url = (pn_url_t *) object;
+    pn_url_clear(url);
+    pn_free(url->str);
+}
+
+static uintptr_t pn_url_hashcode(void *object)
+{
+    pn_url_t *url = (pn_url_t *) object;
+    return pn_hashcode(pn_url_string(url));
+}
+
+static intptr_t pn_url_compare(void *oa, void *ob)
+{
+    pn_url_t *a = (pn_url_t *) oa;
+    pn_url_t *b = (pn_url_t *) ob;
+    return pn_compare(pn_url_string(a), pn_url_string(b));
+}
+
+
+static int pn_url_inspect(void *obj, pn_string_t *dst)
+{
+    pn_url_t *url = (pn_url_t *) obj;
+    int err = 0;
+    err = pn_string_addf(dst, "Url("); if (err) return err;
+    err = pn_inspect(pn_url_string(url), dst); if (err) return err;
+    return pn_string_addf(dst, ")");
+}
+
+#define pn_url_initialize NULL
+
+
+PN_EXTERN pn_url_t *pn_url() {
+    static const pn_class_t clazz = PN_CLASS(pn_url);
+    pn_url_t *url = (pn_url_t*) pn_class_new(&clazz, sizeof(pn_url_t));
+    if (!url) return NULL;
+    memset(url, 0, sizeof(*url));
+    url->str = pn_string(NULL);
+    return url;
+}
+
+/** Parse a string URL as a pn_url_t.
+ *@param[in] url A URL string.
+ *@return The parsed pn_url_t or NULL if url is not a valid URL string.
+ */
+PN_EXTERN pn_url_t *pn_url_parse(const char *str) {
+    if (!str || !*str)          /* Empty string or NULL is illegal. */
+        return NULL;
+
+    pn_url_t *url = pn_url();
+    char *str2 = copy(str);
+    pni_parse_url(str2, &url->scheme, &url->username, &url->password, &url->host, &url->port, &url->path);
+    url->scheme = copy(url->scheme);
+    url->username = copy(url->username);
+    url->password = copy(url->password);
+    url->host = (url->host && !*url->host) ? NULL : copy(url->host);
+    url->port = copy(url->port);
+    url->path = copy(url->path);
+
+    free(str2);
+    return url;
+}
+
+/** Free a URL */
+PN_EXTERN void pn_url_free(pn_url_t *url) { pn_free(url); }
+
+/** Clear the contents of the URL. */
+PN_EXTERN void pn_url_clear(pn_url_t *url) {
+    pn_url_set_scheme(url, NULL);
+    pn_url_set_username(url, NULL);
+    pn_url_set_password(url, NULL);
+    pn_url_set_host(url, NULL);
+    pn_url_set_port(url, NULL);
+    pn_url_set_path(url, NULL);
+    pn_string_clear(url->str);
+}
+
+static inline int len(const char *str) { return str ? strlen(str) : 0; }
+
+/** Return the string form of a URL. */
+PN_EXTERN const char *pn_url_str(pn_url_t *url) {
+    if (pn_string_get(url->str) == NULL) {
+        pn_string_set(url->str, "");
+        if (url->scheme) pn_string_addf(url->str, "%s://", url->scheme);
+        if (url->username) pn_string_addf(url->str, "%s", url->username);
+        if (url->password) pn_string_addf(url->str, ":%s", url->password);
+        if (url->username || url->password) pn_string_addf(url->str, "@");
+        if (url->host) {
+            if (strchr(url->host, ':')) pn_string_addf(url->str, "[%s]", url->host);
+            else pn_string_addf(url->str, "%s", url->host);
+        }
+        if (url->port) pn_string_addf(url->str, ":%s", url->port);
+        if (url->path) pn_string_addf(url->str, "/%s", url->path);
+    }
+    return pn_string_get(url->str);
+}
+
+PN_EXTERN const char *pn_url_get_scheme(pn_url_t *url) { return url->scheme; }
+PN_EXTERN const char *pn_url_get_username(pn_url_t *url) { return url->username; }
+PN_EXTERN const char *pn_url_get_password(pn_url_t *url) { return url->password; }
+PN_EXTERN const char *pn_url_get_host(pn_url_t *url) { return url->host; }
+PN_EXTERN const char *pn_url_get_port(pn_url_t *url) { return url->port; }
+PN_EXTERN const char *pn_url_get_path(pn_url_t *url) { return url->path; }
+
+#define SET(part) free(url->part); url->part = copy(part); pn_string_clear(url->str)
+PN_EXTERN void pn_url_set_scheme(pn_url_t *url, const char *scheme) { SET(scheme); }
+PN_EXTERN void pn_url_set_username(pn_url_t *url, const char *username) { SET(username); }
+PN_EXTERN void pn_url_set_password(pn_url_t *url, const char *password) { SET(password); }
+PN_EXTERN void pn_url_set_host(pn_url_t *url, const char *host) { SET(host); }
+PN_EXTERN void pn_url_set_port(pn_url_t *url, const char *port) { SET(port); }
+PN_EXTERN void pn_url_set_path(pn_url_t *url, const char *path) { SET(path); }
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/util.c
----------------------------------------------------------------------
diff --git a/proton-c/src/util.c b/proton-c/src/util.c
index 16e3685..84d594b 100644
--- a/proton-c/src/util.c
+++ b/proton-c/src/util.c
@@ -27,7 +27,6 @@
 #include <ctype.h>
 #include <string.h>
 #include <proton/error.h>
-#include <proton/util.h>
 #include <proton/types.h>
 #include "util.h"
 
@@ -200,17 +199,17 @@ void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **ho
   if (*pass) pni_urldecode(*pass, *pass);
 }
 
-void pn_vfatal(const char *fmt, va_list ap)
+void pni_vfatal(const char *fmt, va_list ap)
 {
   vfprintf(stderr, fmt, ap);
   abort();
 }
 
-void pn_fatal(const char *fmt, ...)
+void pni_fatal(const char *fmt, ...)
 {
   va_list ap;
   va_start(ap, fmt);
-  pn_vfatal(fmt, ap);
+  pni_vfatal(fmt, ap);
   va_end(ap);
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/util.h
----------------------------------------------------------------------
diff --git a/proton-c/src/util.h b/proton-c/src/util.h
index 322f4ef..ad299b9 100644
--- a/proton-c/src/util.h
+++ b/proton-c/src/util.h
@@ -33,6 +33,9 @@
 #include <proton/types.h>
 #include <proton/object.h>
 
+PN_EXTERN void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path);
+void pni_fatal(const char *fmt, ...);
+void pni_vfatal(const char *fmt, va_list ap);
 PN_EXTERN ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size);
 int pn_quote(pn_string_t *dst, const char *src, size_t size);
 PN_EXTERN void pn_fprint_data(FILE *stream, const char *bytes, size_t size);


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


[10/51] [abbrv] qpid-proton git commit: Implemented the remainder of the codec methods and ported the codec unit test suite to test it all

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index 43634d4..08aeb3e 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -37,15 +37,16 @@
  * from minifying e.g. <pre>Module['Messenger'] = ...</pre>
  * Exported Objects can be used in client code using the appropriate namespace:
  * <pre>
- * proton = require("proton.js");
+ * proton = require('proton.js');
  * var messenger = new proton.Messenger();
  * var message = new proton.Message();
  * </pre>
  * @namespace proton
  */
+
 var Module = {
     // Prevent emscripten runtime exiting, we will be enabling network callbacks.
-    'noExitRuntime' : true
+    'noExitRuntime' : true,
 };
 
 /*****************************************************************************/
@@ -790,7 +791,7 @@ Module['Message'] = function() { // Message Constructor.
      * Application defined Message properties.
      * @type map
      */
-    this['properties'] = null;
+    this['properties'] = {};
 
     /**
      * Message body.
@@ -835,32 +836,35 @@ _Message_._check = function(code) {
  * Encode the Message prior to sending on the wire.
  */
 _Message_._preEncode = function() {
-    if (this.instructions) {
+    // A Message Object may be reused so we create new Data instances and clear
+    // the state for them each time put() gets called.
+    var inst = new Data(_pn_message_instructions(this._message));
+    var ann = new Data(_pn_message_annotations(this._message));
+    var props = new Data(_pn_message_properties(this._message));
+    var body = new Data(_pn_message_body(this._message));
+
+    inst.clear();
+    if (this['instructions']) {
 console.log("Encoding instructions");
-        var inst = new Data(_pn_message_instructions(this._message));
-        inst.clear();
-        inst.putObject(this.instructions);
+        inst['putObject'](this['instructions']);
     }
 
-    if (this.annotations) {
+    ann.clear();
+    if (this['annotations']) {
 console.log("Encoding annotations");
-        var ann = new Data(_pn_message_annotations(this._message));
-        ann.clear();
-        ann.putObject(this.annotations);
+        ann['putObject'](this['annotations']);
     }
 
-    if (this.properties) {
+    props.clear();
+    if (this['properties']) {
 console.log("Encoding properties");
-        var props = new Data(_pn_message_properties(this._message));
-        props.clear();
-        props.putObject(this.properties);
+        props['putObject'](this['properties']);
     }
 
-    if (this.body != null) {
+    body.clear();
+    if (this['body']) {
 console.log("Encoding body");
-        var body = new Data(_pn_message_body(this._message));
-        body.clear();
-        body.putObject(this.body);
+        body['putObject'](this['body']);
     }
 };
 
@@ -874,27 +878,27 @@ _Message_._postDecode = function() {
     var body = new Data(_pn_message_body(this._message));
 
     if (inst.next()) {
-        this.instructions = inst.getObject();
+        this['instructions'] = inst['getObject']();
     } else {
-        this.instructions = {};
+        this['instructions'] = {};
     }
 
     if (ann.next()) {
-        this.annotations = ann.getObject();
+        this['annotations'] = ann['getObject']();
     } else {
-        this.annotations = {};
+        this['annotations'] = {};
     }
 
     if (props.next()) {
-        this.properties = props.getObject();
+        this['properties'] = props['getObject']();
     } else {
-        this.properties = {};
+        this['properties'] = {};
     }
 
     if (body.next()) {
-        this.body = body.getObject();
+        this['body'] = body['getObject']();
     } else {
-        this.body = null;
+        this['body'] = null;
     }
 };
 
@@ -933,7 +937,7 @@ _Message_['getError'] = function() {
 /**
  * @method getAddress
  * @memberof! proton.Message#
- * @return {string} the address of the Message.
+ * @returns {string} the address of the Message.
  */
 _Message_['getAddress'] = function() {
     return Pointer_stringify(_pn_message_get_address(this._message));
@@ -1014,13 +1018,25 @@ _Message_['setSubject'] = function(subject) {
  * sibling then one will be added. The put* methods always set the added/modified
  * node to the current node. The get* methods read the value of the current node
  * and do not change which node is current.
- * @constructor proton.Data                                                                
+ * @constructor proton.Data
+ * @param {number} data an optional pointer to a pn_data_t instance. If supplied
+ *        the underlying data is "owned" by another object (for example a Message)
+ *        and that object is assumed to be responsible for freeing the data if
+ *        necessary. If no data is supplied then the Data is stand-alone and the
+ *        client application is responsible for freeing the underlying data via
+ *        a call to free().
  */
 Module['Data'] = function(data) { // Data Constructor.
-    this._data = data;
-
     if (!data) {
-        console.log("Warning Data created with null data");
+        this._data = _pn_data(16); // Default capacity is 16
+        this['free'] = function() {
+            _pn_data_free(this._data);
+            // Set free to a null function to prevent possibility of a "double free".
+            this['free'] = function() {};
+        };
+    } else {
+        this._data = data;
+        this['free'] = function() {};
     }
 };
 
@@ -1030,62 +1046,89 @@ var Data = Module['Data'];
 // Expose prototype as a variable to make method declarations less verbose.
 var _Data_ = Data.prototype;
 
+// ************************** Class properties ********************************
+
+Data['NULL']       = 1;
+Data['BOOL']       = 2;
+Data['UBYTE']      = 3;
+Data['BYTE']       = 4;
+Data['USHORT']     = 5;
+Data['SHORT']      = 6;
+Data['UINT']       = 7;
+Data['INT']        = 8;
+Data['CHAR']       = 9;
+Data['ULONG']      = 10;
+Data['LONG']       = 11;
+Data['TIMESTAMP']  = 12;
+Data['FLOAT']      = 13;
+Data['DOUBLE']     = 14;
+Data['DECIMAL32']  = 15;
+Data['DECIMAL64']  = 16;
+Data['DECIMAL128'] = 17;
+Data['UUID']       = 18;
+Data['BINARY']     = 19;
+Data['STRING']     = 20;
+Data['SYMBOL']     = 21;
+Data['DESCRIBED']  = 22;
+Data['ARRAY']      = 23;
+Data['LIST']       = 24;
+Data['MAP']        = 25;
+
 /**
  * Look-up table mapping proton-c types to the accessor method used to
  * deserialise the type. N.B. this is a simple Array and not a map because the
  * types that we get back from pn_data_type are integers from the pn_type_t enum.
- * @property {Array<String>} GetMappings
+ * @property {Array<String>} TypeNames
  * @memberof! proton.Data
  */
-Data.GetMappings = [
-    'getNull',            // 0
-    'getNull',            // PN_NULL = 1
-    'getBoolean',         // PN_BOOL = 2
-    'getUnsignedByte',    // PN_UBYTE = 3
-    'getByte',            // PN_BYTE = 4
-    'getUnsignedShort',   // PN_USHORT = 5
-    'getShort',           // PN_SHORT = 6
-    'getUnsignedInteger', // PN_UINT = 7
-    'getInteger',         // PN_INT = 8
-    'getChar',            // PN_CHAR = 9
-    'getUnsignedLong',    // PN_ULONG = 10
-    'getLong',            // PN_LONG = 11
-    'getTimestamp',       // PN_TIMESTAMP = 12
-    'getFloat',           // PN_FLOAT = 13
-    'getDouble',          // PN_DOUBLE = 14
-    'getDecimal32',       // PN_DECIMAL32 = 15
-    'getDecimal64',       // PN_DECIMAL64 = 16
-    'getDecimal128',      // PN_DECIMAL128 = 17
-    'getUUID',            // PN_UUID = 18
-    'getBinary',          // PN_BINARY = 19
-    'getString',          // PN_STRING = 20
-    'getSymbol',          // PN_SYMBOL = 21
-    'getDescribed',       // PN_DESCRIBED = 22
-    'getArray',           // PN_ARRAY = 23
-    'getJSArray',         // PN_LIST = 24
-    'getDictionary'       // PN_MAP = 25
+Data['TypeNames'] = [
+    'NULL',       // 0
+    'NULL',       // PN_NULL       = 1
+    'BOOL',       // PN_BOOL       = 2
+    'UBYTE',      // PN_UBYTE      = 3
+    'BYTE',       // PN_BYTE       = 4
+    'USHORT',     // PN_USHORT     = 5
+    'SHORT',      // PN_SHORT      = 6
+    'UINT',       // PN_UINT       = 7
+    'INT',        // PN_INT        = 8
+    'CHAR',       // PN_CHAR       = 9
+    'ULONG',      // PN_ULONG      = 10
+    'LONG',       // PN_LONG       = 11
+    'TIMESTAMP',  // PN_TIMESTAMP  = 12
+    'FLOAT',      // PN_FLOAT      = 13
+    'DOUBLE',     // PN_DOUBLE     = 14
+    'DECIMAL32',  // PN_DECIMAL32  = 15
+    'DECIMAL64',  // PN_DECIMAL64  = 16
+    'DECIMAL128', // PN_DECIMAL128 = 17
+    'UUID',       // PN_UUID       = 18
+    'BINARY',     // PN_BINARY     = 19
+    'STRING',     // PN_STRING     = 20
+    'SYMBOL',     // PN_SYMBOL     = 21
+    'DESCRIBED',  // PN_DESCRIBED  = 22
+    'ARRAY',      // PN_ARRAY      = 23
+    'LIST',       // PN_LIST       = 24
+    'MAP'         // PN_MAP        = 25
 ];
 
 // *************************** Class methods **********************************
 
 /**
- * Test if a given Object is an Array.
+ * Test if a given Object is a JavaScript Array.
  * @method isArray
  * @memberof! proton.Data
  * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is an Array.
+ * @returns {boolean} true iff the Object is a JavaScript Array.
  */
 Data.isArray = Array.isArray || function(o) {
-console.log("Data.isArray");
     return Object.prototype.toString.call(o) === '[object Array]';
 };
 
 /**
- * Test if a given Object is a Number.
+ * Test if a given Object is a JavaScript Number.
  * @method isNumber
  * @memberof! proton.Data
  * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a Number.
+ * @returns {boolean} true iff the Object is a JavaScript Number.
  */
 Data.isNumber = function(o) {
     return typeof o === 'number' || 
@@ -1093,11 +1136,11 @@ Data.isNumber = function(o) {
 };
 
 /**
- * Test if a given Object is a String.
+ * Test if a given Object is a JavaScript String.
  * @method isString
  * @memberof! proton.Data
  * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a String.
+ * @returns {boolean} true iff the Object is a JavaScript String.
  */
 Data.isString = function(o) {
     return typeof o === 'string' ||
@@ -1105,11 +1148,11 @@ Data.isString = function(o) {
 };
 
 /**
- * Test if a given Object is a Boolean.
+ * Test if a given Object is a JavaScript Boolean.
  * @method isBoolean
  * @memberof! proton.Data
  * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a Boolean.
+ * @returns {boolean} true iff the Object is a JavaScript Boolean.
  */
 Data.isBoolean = function(o) {
     return typeof o === 'boolean' ||
@@ -1118,20 +1161,20 @@ Data.isBoolean = function(o) {
 
 // **************************** Inner Classes *********************************
 
-// --------------------------- proton.Data.UUID -------------------------------
+// --------------------------- proton.Data.Uuid -------------------------------
 /**
- * Create a proton.Data.UUID which is a type 4 UUID.
+ * Create a proton.Data.Uuid which is a type 4 UUID.
  * @classdesc
  * This class represents a type 4 UUID, wich may use crypto libraries to generate
  * the UUID if supported by the platform (e.g. node.js or a modern browser)
- * @constructor proton.Data.UUID
+ * @constructor proton.Data.Uuid
  * @param u a UUID. If null a type 4 UUID is generated wich may use crypto if
  *        supported by the platform. If u is an emscripten "pointer" we copy the
  *        data from that. If u is a JavaScript Array we use it as-is. If u is a
  *        String then we try to parse that as a UUID.
  * @property {Array} uuid is the compact array form of the UUID.
  */
-Data['UUID'] = function(u) { // Data.UUID Constructor.
+Data['Uuid'] = function(u) { // Data.Uuid Constructor.
     // Helper to copy from emscriptem allocated storage into JavaScript Array.
     function _p2a(p) {
         var uuid = new Array(16);
@@ -1167,13 +1210,14 @@ Data['UUID'] = function(u) { // Data.UUID Constructor.
 };
 
 /**
+ * Returns the string representation of the proton.Data.Uuid.
  * @method toString
- * @memberof! proton.Data.UUID#
+ * @memberof! proton.Data.Uuid#
  * @returns {string} the String
  *          /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
- *          form of a {@link proton.Data.UUID}.
+ *          form of a {@link proton.Data.Uuid}.
  */
-Data['UUID'].prototype.toString = function() {
+Data['Uuid'].prototype.toString = Data['Uuid'].prototype.valueOf = function() {
     if (!this.string) { // Check if we've cached the string version.
         var i = 0;
         var uu = this['uuid'];
@@ -1189,17 +1233,16 @@ Data['UUID'].prototype.toString = function() {
 };
 
 /**
- * Compare two instances of proton.Data.UUID for equality.
+ * Compare two instances of proton.Data.Uuid for equality.
  * @method equals
- * @memberof! proton.Data.UUID#
- * @param {proton.Data.UUID} rhs the instance we wish to compare this instance with.
+ * @memberof! proton.Data.Uuid#
+ * @param {proton.Data.Uuid} rhs the instance we wish to compare this instance with.
  * @returns {boolean} true iff the two compared instances are equal.
  */
-Data['UUID'].prototype['equals'] = function(rhs) {
+Data['Uuid'].prototype['equals'] = function(rhs) {
     return this.toString() === rhs.toString();
 };
 
-
 // ---------------------------- proton.Data.Symbol ---------------------------- 
 /**
  * Create a proton.Data.Symbol.
@@ -1212,7 +1255,6 @@ Data['UUID'].prototype['equals'] = function(rhs) {
  */
 Data['Symbol'] = function(s) { // Data.Symbol Constructor.
     this.value = s;
-    this.length = this.value.length;
 };
 
 /**
@@ -1235,54 +1277,178 @@ Data['Symbol'].prototype['equals'] = function(rhs) {
     return this.toString() === rhs.toString();
 };
 
+// ---------------------------- proton.Data.Described ---------------------------- 
+/**
+ * Create a proton.Data.Described.
+ * @classdesc
+ * This class represents an AMQP Described.
+ * @constructor proton.Data.Described
+ * @param {object} value the value of the described type.
+ * @param {string} descriptor an optional string describing the type.
+ * @property {object} value the actual value of the described type.
+ * @property {string} descriptor a string describing the type.
+ */
+Data['Described'] = function(value, descriptor) { // Data.Described Constructor.
+    this['value'] = value;
+    this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Described#
+ * @returns {string} the String form of a {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.toString = function() {
+    return 'Described(' + this['value'] + ', ' + this['descriptor'] + ')';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Described#
+ * @returns {object} the value of the {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.valueOf = function() {
+    return this['value'];
+};
+
+/**
+ * Compare two instances of proton.Data.Described for equality.
+ * @method equals
+ * @memberof! proton.Data.Described#
+ * @param {proton.Data.Described} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Described'].prototype['equals'] = function(rhs) {
+    if (rhs instanceof Data['Described']) {
+        return ((this['descriptor'] === rhs['descriptor']) && (this['value'] === rhs['value']));
+    } else {
+        return false;
+    }
+};
+
+// ---------------------------- proton.Data.Array ---------------------------- 
+/**
+ * TODO make this behave more like a native JavaScript Array: http://www.bennadel.com/blog/2292-extending-javascript-arrays-while-keeping-native-bracket-notation-functionality.htm
+ * Create a proton.Data.Array.
+ * @classdesc
+ * This class represents an AMQP Array.
+ * @constructor proton.Data.Array
+ * @param {{string|number)} type the type of the Number either as a string or number.
+ *        Stored internally as a string corresponding to one of the TypeNames.       
+ * @param {Array|TypedArray} elements the Native JavaScript Array or TypedArray that we wish to serialise.
+ * @param {object} descriptor an optional object describing the type.
+ */
+Data['Array'] = function(type, elements, descriptor) { // Data.Array Constructor.
+    // This block caters for an empty Array or a Described empty Array.
+    if (arguments.length < 2) {
+        descriptor = type;
+        type = 'NULL';
+        elements = [];
+    }
+
+    this['type']  = (typeof type === 'number') ? Data['TypeNames'][type] : type;
+    this['elements'] = elements;
+    this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Array#
+ * @returns {string} the String form of a {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.toString = function() {
+    var descriptor = (this['descriptor'] == null) ? '' : ':' + this['descriptor'];
+    return this['type'] + 'Array' + descriptor + '[' + this['elements'] + ']';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Array#
+ * @returns {Array} the elements of the {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.valueOf = function() {
+    return this['elements'];
+};
+
+/**
+ * Compare two instances of proton.Data.Array for equality. N.B. this method
+ * compares the value of every Array element so its performance is O(n).
+ * @method equals
+ * @memberof! proton.Data.Array#
+ * @param {proton.Data.Array} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Array'].prototype['equals'] = function(rhs) {
+    if (rhs instanceof Data['Array'] &&
+        // Check the string value of the descriptors.
+        (('' + this['descriptor']) === ('' + rhs['descriptor'])) &&
+        (this['type'] === rhs['type'])) {
+        var elements = this['elements'];
+        var relements = rhs['elements'];
+        var length = elements.length;
+        if (length === relements.length) {
+            for (var i = 0; i < length; i++) {
+                if (elements[i].valueOf() !== relements[i].valueOf()) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    } else {
+        return false;
+    }
+};
+
 // ---------------------- JavaScript Number Extensions ------------------------ 
 
-Number.prototype['asUnsignedByte'] = function() {
-    return new Data.TypedNumber('UnsignedByte', this);
+Number.prototype['ubyte'] = function() {
+    return new Data.TypedNumber('UBYTE', this);
 };
 
-Number.prototype['asByte'] = function() {
-    return new Data.TypedNumber('Byte', this);
+Number.prototype['byte'] = function() {
+    return new Data.TypedNumber('BYTE', this);
 };
 
-Number.prototype['asUnsignedShort'] = function() {
-    return new Data.TypedNumber('UnsignedShort', this);
+Number.prototype['ushort'] = function() {
+    return new Data.TypedNumber('USHORT', this);
 };
 
-Number.prototype['asShort'] = function() {
-    return new Data.TypedNumber('Short', this);
+Number.prototype['short'] = function() {
+    return new Data.TypedNumber('SHORT', this);
 };
 
-Number.prototype['asUnsignedInteger'] = function() {
-    return new Data.TypedNumber('UnsignedInteger', this);
+Number.prototype['uint'] = function() {
+    return new Data.TypedNumber('UINT', this);
 };
 
-Number.prototype['asInteger'] = function() {
-    return new Data.TypedNumber('Integer', this);
+Number.prototype['int'] = function() {
+    return new Data.TypedNumber('INT', this);
 };
 
-Number.prototype['asUnsignedLong'] = function() {
-    return new Data.TypedNumber('UnsignedLong', this);
+Number.prototype['ulong'] = function() {
+    return new Data.TypedNumber('ULONG', this);
 };
 
-Number.prototype['asLong'] = function() {
-    return new Data.TypedNumber('Long', this);
+Number.prototype['long'] = function() {
+    return new Data.TypedNumber('LONG', this);
 };
 
-Number.prototype['asFloat'] = function() {
-    return new Data.TypedNumber('Float', this);
+Number.prototype['float'] = function() {
+    return new Data.TypedNumber('FLOAT', this);
 };
 
-Number.prototype['asDouble'] = function() {
-    return new Data.TypedNumber('Double', this);
+Number.prototype['double'] = function() {
+    return new Data.TypedNumber('DOUBLE', this);
 };
 
-Number.prototype['asChar'] = function() {
-    return new Data.TypedNumber('Char', this);
+Number.prototype['char'] = function() {
+    return new Data.TypedNumber('CHAR', this);
 };
 
-String.prototype['asChar'] = function() {
-    return new Data.TypedNumber('Char', this.charCodeAt(0));
+String.prototype['char'] = function() {
+    return new Data.TypedNumber('CHAR', this.charCodeAt(0));
 };
 
 // ------------------------- proton.Data.TypedNumber -------------------------- 
@@ -1292,21 +1458,30 @@ String.prototype['asChar'] = function() {
  * This class is a simple wrapper class that allows a "type" to be recorded for
  * a number. The idea is that the JavaScript Number class is extended with extra
  * methods to allow numbers to be "modified" to TypedNumbers, so for example
- * 1.0.asFloat() would modify 1.0 by returning a TypedNumber with type = Float
+ * 1.0.float() would modify 1.0 by returning a TypedNumber with type = FLOAT
  * and value = 1. The strings used for type correspond to the names of the Data
- * put* methods e.g. UnsignedByte, Byte, UnsignedShort, Short, UnsignedInteger,
- * Integer, UnsignedLong, Long, Float, Double, Char so that the correct method
- * to call can be easily derived from the TypedNumber's type.
+ * put* methods e.g. UBYTE, BYTE, USHORT, SHORT, UINT, INT, ULONG, LONG, FLOAT,
+ * DOUBLE, CHAR so that the correct method to call can be derived from the type.
  * @constructor proton.Data.TypedNumber
- * @param {string} type the type of the Number.
- * @param {number} value the most significant word.
+ * @param {(string|number)} type the type of the Number either as a string or number.
+ *        Stored internally as a string corresponding to one of the TypeNames.
+ * @param {number} value the value of the Number.
  */
 // Use dot notation as it is a "protected" inner class not exported from the closure.
 Data.TypedNumber = function(type, value) { // Data.TypedNumber Constructor.
-    this.type  = type;
+    this.type  = (typeof type === 'number') ? Data['TypeNames'][type] : type;
     this.value = value;
 };
 
+/**
+ * @method toString
+ * @memberof! proton.Data.TypedNumber#
+ * @returns {string} the String form of a {@link proton.Data.TypedNumber}.
+ */
+Data.TypedNumber.prototype.toString = Data.TypedNumber.prototype.valueOf = function() {
+    return +this.value;
+};
+
 // ----------------------------- proton.Data.Long ----------------------------- 
 /**
  * Create a proton.Data.Long.
@@ -1345,7 +1520,7 @@ Data.Long.fromNumber = function(value) {
     if (isNaN(value) || !isFinite(value)) {
         return Data.Long.ZERO;
     } else if (value <= -Data.Long.TWO_PWR_63_DBL_) {
-        return Data.MIN_VALUE;
+        return Data.Long.MIN_VALUE;
     } else if (value + 1 >= Data.Long.TWO_PWR_63_DBL_) {
         return Data.Long.MAX_VALUE;
     } else if (value < 0) {
@@ -1470,71 +1645,93 @@ Data.Long.prototype.toNumber = function() {
  * @returns {string} the String form of a {@link proton.Data.Long}.
  */
 Data.Long.prototype.toString = function() {
-    return this.high + ":" + this.getLowBitsUnsigned();
+    return this.high + ':' + this.getLowBitsUnsigned();
 };
 
 // ---------------------------- proton.Data.Binary ----------------------------
 /**
- * Create a proton.Data.Binary. This constructor takes one or two parameters,
- * size specifies the size in bytes of the Binary buffer, start is a pointer
- * to the data in an internal data store. If start is not specified then size
- * bytes will be allocated in the internal data store and start will point to
- * the start of that block of data.
+ * Create a proton.Data.Binary. This constructor takes one or two parameters.
+ * The first parameter may serve different purposes depending on its type;
+ * If value is a number then it represents the size of the Binary data buffer,
+ * if it is a string then we copy the string to the buffer, if it is an Array
+ * or a TypedArray then we copy the data to the buffer. The optional second
+ * parameter is a pointer to the data in an internal data store. If start is
+ * not specified then the number of bytes specified in the first parameter
+ * will be allocated in the internal data store and start will point to the
+ * start of that block of data.
  * @classdesc
  * This class represents an AMQP Binary type. This class allows us to create and
  * use raw binary data and map it efficiently between JavaScript client code and
- * the underlying implementation, where all data is managed on a virtual heap.
+ * the underlying implementation, where all data is managed on a "virtual heap".
+ * <p>
+ * Client applications should generally not have to care about memory management
+ * as, for most common use cases, client applications would "transfer ownership"
+ * to a "container" which would then "own" the underlying data and free the data
+ * held by the {@link proton.Data.Binary}.
  * <p>
- * Client applications should not have to care about memory management. A client
- * should create a {@link proton.Data.Binary} specifying the required size then
- * call getBuffer to access the underlying Uint8Array. When {@link proton.Data.putBinary}
- * is called ownership of the bytes transfers from the Binary to the Data and
- * putBinary can then safely call free. Conversely when receiving data a Binary
- * may be created by {@link proton.Data.getBinary} in this case the Binary is
- * simply a "view" onto the bytes owned by the Data instance. A client application
- * can safely access the bytes from the view, but if it wishes to use the bytes
- * beyond the scope of the Data instance (for example after the next
- * {@link proton.Messenger.get} call then the client must explicitly *copy* the
- * bytes into a new buffer via copyBuffer().
+ * As an example one common use-case would be where client application creates a
+ * {@link proton.Data.Binary} specifying the required size. It would usually then
+ * call getBuffer() to access the underlying Uint8Array. At this point the client
+ * "owns" the data and so would have to call free() if it did nothing more with
+ * the Binary, however when {@link proton.Data.putBINARY} is called the ownership
+ * of the raw data on the virtual heap transfers from the Binary to the Data and
+ * the client no longer needs to call free() itself. In this case the putBINARY()
+ * call transfers ownership and can then safely call free() on the Binary.
+ * <p>
+ * Conversely a common use-case when receiving data is where a Binary may be
+ * created by {@link proton.Data.getBINARY}. In this case the Binary is simply a
+ * "view" onto the bytes owned by the Data instance. A client application can
+ * safely access the bytes from the view, but if it wishes to use the bytes beyond
+ * the scope of the Data instance (e.g. after the next {@link proton.Messenger.get}
+ * call then the client must explicitly *copy* the bytes into a new buffer, for
+ * example via copyBuffer().
+ * <p>
+ * Most of the {@link proton.Data} methods that take {@link proton.Data.Binary}
+ * as a parameter "consume" the underlying data and take responsibility for
+ * freeing it from the heap {@link proton.Data.putBINARY} {@link proton.Data.decode}.
+ * For the methods that return a {@link proton.Data.Binary} the call to
+ * {@link proton.Data.getBINARY}, which is the most common case, returns a Binary
+ * that has a "view" of the underlying data that is actually owned by the Data
+ * instance and thus doesn't need to be explicitly freed on the Binary. The call
+ * to {@link proton.Data.encode} however returns a Binary that represents a *copy*
+ * of the underlying data, in this case (like a client calling new proton.Data.Binary)
+ * the client takes responsibility for freeing the data, unless of course it is
+ * subsequently passed to a method that will consume the data (putBINARY/decode).
  * @constructor proton.Data.Binary
- * @param {object} data. If data is a number then it represents the size of the
- *        Binary data buffer, if it is a string then we copy the string to the
- *        buffer, if it is an Array or a TypedArray then we copy the data to
- *        the buffer. N.B. although convenient do bear in mind that every method
- *        other than constructing with a size followed by a call to getBuffer will
- *        result in some form of additional data copy.
- * @param {number} start an optional data pointer to the start of the Binary data buffer.
- */
-Data['Binary'] = function(data, start) { // Data.Binary Constructor.
+ * @param {(number|string|Array|TypedArray)} value. If value is a number then it 
+ *        represents the size of the Binary data buffer, if it is a string then
+ *        we copy the string to the buffer, if it is an Array or a TypedArray
+ *        then we copy the data to the buffer. N.B. although convenient do bear
+ *        in mind that using a mechanism other than constructing with a simple
+ *        size will result in some form of additional data copy.
+ * @param {number} start an optional pointer to the start of the Binary data buffer.
+ */
+Data['Binary'] = function(value, start) { // Data.Binary Constructor.
     /**
      * If the start pointer is specified then the underlying binary data is owned
      * by another object, so we set the call to free to be a null function. If
      * the start pointer is not passed then we allocate storage of the specified
      * size on the emscripten heap and set the call to free to free the data from
-     * the emscripten heap. We have made the call to free a protected method that
-     * is only visible within the scope of the binding closure, clients should
-     * not have to call free themselves as the data is either already "owned" by
-     * a Data object or is destined to be passed to a Data object, which will in
-     * turn take responsibility for calling free once it has taken ownership of
-     * the underlying binary data.
+     * the emscripten heap.
      */
-    var size = data;
+    var size = value;
     if (start) {
-        this.free = function() {};
-    } else { // Create Binary from Array, ArrayBuffer or TypedArray
-        if (Data.isArray(data) ||
-            (data instanceof ArrayBuffer) || 
-            (data.buffer && data.buffer instanceof ArrayBuffer)) {
-            data = new Uint8Array(data);
-            size = data.length;
+        this['free'] = function() {};
+    } else { // Create Binary from Array, ArrayBuffer or TypedArray.
+        var hasArrayBuffer = (typeof ArrayBuffer === 'function');
+        if (Data.isArray(value) ||
+            (hasArrayBuffer && value instanceof ArrayBuffer) || 
+            (value.buffer && hasArrayBuffer && value.buffer instanceof ArrayBuffer)) {
+            value = new Uint8Array(value);
+            size = value.length;
             start = _malloc(size); // Allocate storage from emscripten heap.
-            Module.HEAPU8.set(data, start);
-        } else if (Data.isString(data)) { // Create Binary from native string
-            data = unescape(encodeURIComponent(data)); // Create a C-like UTF representation.
-            size = data.length;
+            Module['HEAPU8'].set(value, start); // Copy the data to the emscripten heap.
+        } else if (Data.isString(value)) { // Create Binary from native string
+            value = unescape(encodeURIComponent(value)); // Create a C-like UTF representation.
+            size = value.length;
             start = _malloc(size); // Allocate storage from emscripten heap.
             for (var i = 0; i < size; i++) {
-                setValue(start + i, data.charCodeAt(i), 'i8', 1);
+                setValue(start + i, value.charCodeAt(i), 'i8', 1);
             }
         } else { // Create unpopulated Binary of specified size.
             // If the type is not a number by this point then an unrecognised data
@@ -1542,7 +1739,13 @@ Data['Binary'] = function(data, start) { // Data.Binary Constructor.
             size = Data.isNumber(size) ? size : 0;
             start = _malloc(size); // Allocate storage from emscripten heap.
         }
-        this.free = function() {_free(start);};
+        this['free'] = function() {
+            _free(this.start);
+            this.size = 0;
+            this.start = 0;
+            // Set free to a null function to prevent possibility of a "double free".
+            this['free'] = function() {};
+        };
     }
 
     this.size = size;
@@ -1562,16 +1765,28 @@ Data['Binary'].prototype['getBuffer'] = function() {
 };
 
 /**
- * Explicitly create a *copy* of the underlying binary data and present a Uint8Array
- * view of that copy. This method should be used if a client application wishes to
- * retain an interest in the binary data for longer than it wishes to retain an
- * interest in say a {@link proton.Message}, if that's not the case getBuffer
- * should be used as that avoids the need to copy the data.
- * @method copyBuffer
+ * Explicitly create a *copy* of the Binary copying the underlying binary data too.
+ * @method copy
+ * @param {number} offset an optional offset into the underlying buffer from
+ *        where we want to copy the data, default is zero.
+ * @param {number} n an optional number of bytes to copy, default is this.size - offset.
  * @memberof! proton.Data.Binary#
  */
-Data['Binary'].prototype['copyBuffer'] = function() {
-    return new Uint8Array(new Uint8Array(HEAPU8.buffer, this.start, this.size));
+Data['Binary'].prototype['copy'] = function(offset, n) {
+    offset = offset | 0;
+    n = n ? n : (this.size - offset);
+
+    if (offset >= this.size) {
+        offset = 0;
+        n = 0;
+    } else if ((offset + n) > this.size) {
+        n = this.size - offset; // Clamp length
+    }
+
+    var start = _malloc(n); // Allocate storage from emscripten heap.
+    _memcpy(start, this.start + offset, n); // Copy the raw data to new buffer.
+
+    return new Data['Binary'](n, start);
 };
 
 /**
@@ -1648,9 +1863,8 @@ _Data_['clear'] = function() {
 };
 
 /**
- * Clears current node and sets the parent to the root node.  Clearing the
- * current node sets it _before_ the first node, calling next() will advance
- * to the first node.
+ * Clears current node and sets the parent to the root node.  Clearing the current
+ * node sets it _before_ the first node, calling next() will advance to the first node.
  * @method rewind
  * @memberof! proton.Data#
  */
@@ -1659,9 +1873,8 @@ _Data_['rewind'] = function() {
 };
 
 /**
- * Advances the current node to its next sibling and returns its
- * type. If there is no next sibling the current node remains
- * unchanged and null is returned.
+ * Advances the current node to its next sibling and returns its type. If there
+ * is no next sibling the current node remains unchanged and null is returned.
  * @method next
  * @memberof! proton.Data#
  * @returns {number} the type of the next sibling or null.
@@ -1671,14 +1884,13 @@ _Data_['next'] = function() {
     if (found) {
         return this.type();
     } else {
-        return null;  
+        return null;
     }
 };
 
 /**
- * Advances the current node to its previous sibling and returns its
- * type. If there is no previous sibling the current node remains
- * unchanged and null is returned.
+ * Advances the current node to its previous sibling and returns its type. If there
+ * is no previous sibling the current node remains unchanged and null is returned.
  * @method prev
  * @memberof! proton.Data#
  * @returns {number} the type of the previous sibling or null.
@@ -1693,9 +1905,8 @@ _Data_['prev'] = function() {
 };
 
 /**
- * Sets the parent node to the current node and clears the current node.
- * Clearing the current node sets it _before_ the first child,
- * call next() advances to the first child.
+ * Sets the parent node to the current node and clears the current node. Clearing
+ * the current node sets it _before_ the first child, next() advances to the first child.
  * @method enter
  * @memberof! proton.Data#
  */
@@ -1704,8 +1915,7 @@ _Data_['enter'] = function() {
 };
 
 /**
- * Sets the current node to the parent node and the parent node to
- * its own parent.
+ * Sets the current node to the parent node and the parent node to its own parent.
  * @method exit
  * @memberof! proton.Data#
  */
@@ -1713,10 +1923,13 @@ _Data_['exit'] = function() {
     return (_pn_data_exit(this._data) > 0);
 };
 
-
 /**
+ * Look up a value by name. N.B. Need to use getObject() to retrieve the actual
+ * value after lookup suceeds.
  * @method lookup
  * @memberof! proton.Data#
+ * @param {string} name the name of the property to look up.
+ * @returns {boolean} true iff the lookup succeeded.
  */
 _Data_['lookup'] = function(name) {
     var sp = Runtime.stackSave();
@@ -1725,6 +1938,7 @@ _Data_['lookup'] = function(name) {
     return (lookup > 0);
 };
 
+// TODO document - not quite sure what these are for?
 _Data_['narrow'] = function() {
     _pn_data_narrow(this._data);
 };
@@ -1733,11 +1947,10 @@ _Data_['widen'] = function() {
     _pn_data_widen(this._data);
 };
 
-
 /**
  * @method type
  * @memberof! proton.Data#
- * @returns the type of the current node or null if the type is unknown.
+ * @returns {number} the type of the current node or null if the type is unknown.
  */
 _Data_['type'] = function() {
     var dtype = _pn_data_type(this._data);
@@ -1748,218 +1961,322 @@ _Data_['type'] = function() {
     }
 };
 
-// TODO encode and decode
+/**
+ * Return a Binary representation of the data encoded in AMQP format. N.B. the
+ * returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
+ * responsible for freeing it or passing it to a method that consumes a Binary
+ * such as {@link proton.Data.decode} or {@link proton.Data.putBINARY}.
+ * @method type
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Binary} a representation of the data encoded in AMQP format.
+ */
+_Data_['encode'] = function() {
+    var size = 1024;
+    while (true) {
+        var bytes = _malloc(size); // Allocate storage from emscripten heap.
+        var cd = _pn_data_encode(this._data, bytes, size);
+
+        if (cd === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else if (cd >= 0) {
+            return new Data['Binary'](cd, bytes);
+        } else {
+            _free(bytes);
+            this._check(cd);
+            return;
+        }
+    }
+};
 
 /**
- * Puts a list value. Elements may be filled by entering the list
+ * Decodes the first value from supplied Binary AMQP data and returns a new
+ * {@link proton.Data.Binary} containing the remainder of the data or null if
+ * all the supplied data has been consumed. N.B. this method "consumes" data
+ * from a {@link proton.Data.Binary} in other words it takes responsibility for
+ * the underlying data and frees the raw data from the Binary.
+ * @method decode
+ * @memberof! proton.Data#
+ * @param {proton.Data.Binary} encoded the AMQP encoded binary data.
+ * @returns {proton.Data.Binary} a Binary contianing the remaining bytes or null
+ *          if all the data has been consumed.
+ */
+_Data_['decode'] = function(encoded) {
+    var start = encoded.start;
+    var size = encoded.size;
+    var consumed = this._check(_pn_data_decode(this._data, start, size));
+
+    size = size - consumed;
+    start = _malloc(size); // Allocate storage from emscripten heap.
+    _memcpy(start, encoded.start + consumed, size);
+
+    encoded['free'](); // Free the original Binary.
+    return size > 0 ? new Data['Binary'](size, start) : null;
+};
+
+/**
+ * Puts a list node. Elements may be filled by entering the list
  * node and putting element values.
  * <pre>
- *  data = new Data();
- *  data.putList();
+ *  var data = new proton.Data();
+ *  data.putLISTNODE();
  *  data.enter();
- *  data.putInt(1);
- *  data.putInt(2);
- *  data.putInt(3);
+ *  data.putINT(1);
+ *  data.putINT(2);
+ *  data.putINT(3);
  *  data.exit();
  * </pre>
- * @method putList
+ * @method putLISTNODE
  * @memberof! proton.Data#
  */
-_Data_['putList'] = function() {
+_Data_['putLISTNODE'] = function() {
     this._check(_pn_data_put_list(this._data));
 };
 
 /**
- * Puts a map value. Elements may be filled by entering the map node
+ * Puts a map node. Elements may be filled by entering the map node
  * and putting alternating key value pairs.
  * <pre>
- *  data = new Data();
- *  data.putMap();
+ *  var data = new proton.Data();
+ *  data.putMAPNODE();
  *  data.enter();
- *  data.putString("key");
- *  data.putString("value");
+ *  data.putSTRING('key');
+ *  data.putSTRING('value');
  *  data.exit();
  * </pre>
- * @method putMap
+ * @method putMAPNODE
  * @memberof! proton.Data#
  */
-_Data_['putMap'] = function() {
+_Data_['putMAPNODE'] = function() {
     this._check(_pn_data_put_map(this._data));
 };
 
-// TODO putArray and putDescribed
+/**
+ * Puts an array node. Elements may be filled by entering the array node and
+ * putting the element values. The values must all be of the specified array
+ * element type. If an array is described then the first child value of the array
+ * is the descriptor and may be of any type.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putARRAYNODE(false, proton.Data.INT);
+ *  data.enter();
+ *  data.putINT(1);
+ *  data.putINT(2);
+ *  data.putINT(3);
+ *  data.exit();
+ *
+ *  data.putARRAYNODE(true, proton.Data.DOUBLE);
+ *  data.enter();
+ *  data.putSYMBOL('array-descriptor');
+ *  data.putDOUBLE(1.1);
+ *  data.putDOUBLE(1.2);
+ *  data.putDOUBLE(1.3);
+ *  data.exit();
+ * </pre>
+ * @method putARRAYNODE
+ * @param {boolean} described specifies whether the array is described.
+ * @param {number} type the type of the array elements.
+ * @memberof! proton.Data#
+ */
+_Data_['putARRAYNODE'] = function(described, type) {
+    this._check(_pn_data_put_array(this._data, described, type));
+};
+
+/**
+ * Puts a described node. A described node has two children, the descriptor and
+ * value. These are specified by entering the node and putting the desired values.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putDESCRIBEDNODE();
+ *  data.enter();
+ *  data.putSYMBOL('value-descriptor');
+ *  data.putSTRING('the value');
+ *  data.exit();
+ * </pre>
+ * @method putDESCRIBEDNODE
+ * @memberof! proton.Data#
+ */
+_Data_['putDESCRIBEDNODE'] = function() {
+    this._check(_pn_data_put_described(this._data));
+};
 
 /**
  * Puts a null value.
- * @method putNull
+ * @method putNULL
  * @memberof! proton.Data#
  */
-_Data_['putNull'] = function() {
+_Data_['putNULL'] = function() {
     this._check(_pn_data_put_null(this._data));
 };
 
 /**
  * Puts a boolean value.
- * @method putBoolean
+ * @method putBOOL
  * @memberof! proton.Data#
  * @param {boolean} b a boolean value.
  */
-_Data_['putBoolean'] = function(b) {
+_Data_['putBOOL'] = function(b) {
     this._check(_pn_data_put_bool(this._data, b));
 };
 
 /**
  * Puts a unsigned byte value.
- * @method putUnsignedByte
+ * @method putUBYTE
  * @memberof! proton.Data#
  * @param {number} ub an integral value.
  */
-_Data_['putUnsignedByte'] = function(ub) {
+_Data_['putUBYTE'] = function(ub) {
     this._check(_pn_data_put_ubyte(this._data, ub));
 };
 
 /**
  * Puts a signed byte value.
- * @method putByte
+ * @method putBYTE
  * @memberof! proton.Data#
  * @param {number} b an integral value.
  */
-_Data_['putByte'] = function(b) {
+_Data_['putBYTE'] = function(b) {
     this._check(_pn_data_put_byte(this._data, b));
 };
 
 /**
  * Puts a unsigned short value.
- * @method putUnsignedShort
+ * @method putUSHORT
  * @memberof! proton.Data#
  * @param {number} us an integral value.
  */
-_Data_['putUnsignedShort'] = function(us) {
+_Data_['putUSHORT'] = function(us) {
     this._check(_pn_data_put_ushort(this._data, us));
 };
 
 /**
  * Puts a signed short value.
- * @method putShort
+ * @method putSHORT
  * @memberof! proton.Data#
  * @param {number} s an integral value.
  */
-_Data_['putShort'] = function(s) {
+_Data_['putSHORT'] = function(s) {
     this._check(_pn_data_put_short(this._data, s));
 };
 
 /**
  * Puts a unsigned integer value.
- * @method putUnsignedInteger
+ * @method putUINT
  * @memberof! proton.Data#
  * @param {number} ui an integral value.
  */
-_Data_['putUnsignedInteger'] = function(ui) {
+_Data_['putUINT'] = function(ui) {
     this._check(_pn_data_put_uint(this._data, ui));
 };
 
 /**
  * Puts a signed integer value.
- * @method putInteger
+ * @method putINT
  * @memberof! proton.Data#
  * @param {number} i an integral value.
  */
-_Data_['putInteger'] = function(i) {
+_Data_['putINT'] = function(i) {
     this._check(_pn_data_put_int(this._data, i));
 };
 
 /**
  * Puts a signed char value.
- * @method putChar
+ * @method putCHAR
  * @memberof! proton.Data#
- * @param {number} c a single character.
+ * @param {(string|number)} c a single character expressed either as a string or a number.
  */
-_Data_['putChar'] = function(c) {
+_Data_['putCHAR'] = function(c) {
+    c = Data.isString(c) ? c.charCodeAt(0) : c;
     this._check(_pn_data_put_char(this._data, c));
 };
 
 /**
- * Puts a unsigned long value.
- * @method putUnsignedLong
+ * Puts a unsigned long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method putULONG
  * @memberof! proton.Data#
  * @param {number} ul an integral value.
  */
-_Data_['putUnsignedLong'] = function(ul) {
-    this._check(_pn_data_put_ulong(this._data, ul));
+_Data_['putULONG'] = function(ul) {
+    // If the supplied number exceeds the range of Data.Long invert it before
+    // constructing the Data.Long.
+    ul = (ul >= Data.Long.TWO_PWR_63_DBL_) ? (ul = -(Data.Long.TWO_PWR_64_DBL_ - ul)) : ul;
+    var long = Data.Long.fromNumber(ul);
+    this._check(_pn_data_put_ulong(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
 };
 
 /**
- * Puts a signed long value.
- * @method putLong
+ * Puts a signed long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method putLONG
  * @memberof! proton.Data#
  * @param {number} i an integral value.
  */
-_Data_['putLong'] = function(l) {
-console.log("putLong " + l);
-
+_Data_['putLONG'] = function(l) {
     var long = Data.Long.fromNumber(l);
     this._check(_pn_data_put_long(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
 };
 
 /**
  * Puts a timestamp.
- * @method putTimestamp
+ * @method putTIMESTAMP
  * @memberof! proton.Data#
- * @param {number} t an integral value.
+ * @param {Date} d a Date value.
  */
-_Data_['putTimestamp'] = function(t) {
-console.log("putTimestamp not properly implemented yet");
-    this._check(_pn_data_put_timestamp(this._data, t));
+_Data_['putTIMESTAMP'] = function(d) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(d.valueOf());
+    this._check(_pn_data_put_timestamp(this._data, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
 };
 
 /**
- * Puts a float value.
- * @method putFloat
+ * Puts a float value. N.B. converting between floats and doubles is imprecise
+ * so the resulting value might not quite be what you expect.
+ * @method putFLOAT
  * @memberof! proton.Data#
  * @param {number} f a floating point value.
  */
-_Data_['putFloat'] = function(f) {
-console.log("putFloat f = " + f);
+_Data_['putFLOAT'] = function(f) {
     this._check(_pn_data_put_float(this._data, f));
 };
 
 /**
  * Puts a double value.
- * @method putDouble
+ * @method putDOUBLE
  * @memberof! proton.Data#
  * @param {number} d a floating point value.
  */
-_Data_['putDouble'] = function(d) {
+_Data_['putDOUBLE'] = function(d) {
     this._check(_pn_data_put_double(this._data, d));
 };
 
 /**
  * Puts a decimal32 value.
- * @method putDecimal32
+ * @method putDECIMAL32
  * @memberof! proton.Data#
  * @param {number} d a decimal32 value.
  */
-_Data_['putDecimal32'] = function(d) {
+_Data_['putDECIMAL32'] = function(d) {
     this._check(_pn_data_put_decimal32(this._data, d));
 };
 
 /**
  * Puts a decimal64 value.
- * @method putDecimal64
+ * @method putDECIMAL64
  * @memberof! proton.Data#
  * @param {number} d a decimal64 value.
  */
-_Data_['putDecimal64'] = function(d) {
+_Data_['putDECIMAL64'] = function(d) {
     this._check(_pn_data_put_decimal64(this._data, d));
 };
 
 /**
  * Puts a decimal128 value.
- * @method putDecimal128
+ * @method putDECIMAL128
  * @memberof! proton.Data#
  * @param {number} d a decimal128 value.
  */
-_Data_['putDecimal128'] = function(d) {
+_Data_['putDECIMAL128'] = function(d) {
     this._check(_pn_data_put_decimal128(this._data, d));
 };
 
@@ -1967,7 +2284,7 @@ _Data_['putDecimal128'] = function(d) {
  * Puts a UUID value.
  * @method putUUID
  * @memberof! proton.Data#
- * @param {proton.Data.UUID} u a uuid value
+ * @param {proton.Data.Uuid} u a uuid value
  */
 _Data_['putUUID'] = function(u) {
     var sp = Runtime.stackSave();
@@ -1976,12 +2293,12 @@ _Data_['putUUID'] = function(u) {
 };
 
 /**
- * Puts a binary value.
- * @method putBinary
+ * Puts a binary value consuming the underlying raw data in the process.
+ * @method putBINARY
  * @memberof! proton.Data#
  * @param {proton.Data.Binary} b a binary value.
  */
-_Data_['putBinary'] = function(b) {
+_Data_['putBINARY'] = function(b) {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -1999,20 +2316,20 @@ _Data_['putBinary'] = function(b) {
     // The compiled pn_data_put_binary takes the pn_bytes_t by reference not value.
     this._check(_pn_data_put_binary(this._data, bytes));
 
-    // After calling _pn_data_put_binary the underlying data object "owns" the
+    // After calling _pn_data_put_binary the underlying Data object "owns" the
     // binary data, so we can call free on the proton.Data.Binary instance to
     // release any storage it has acquired back to the emscripten heap.
-    b.free();
+    b['free']();
     Runtime.stackRestore(sp);
 };
 
 /**
  * Puts a unicode string value.
- * @method putString
+ * @method putSTRING
  * @memberof! proton.Data#
  * @param {string} s a unicode string value.
  */
-_Data_['putString'] = function(s) {
+_Data_['putSTRING'] = function(s) {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2045,11 +2362,11 @@ _Data_['putString'] = function(s) {
  * open-ended, typically the both number and size of symbols in use for any
  * given application will be small, e.g. small enough that it is reasonable to
  * cache all the distinct values. Symbols are encoded as ASCII characters.
- * @method putSymbol
+ * @method putSYMBOL
  * @memberof! proton.Data#
- * @param {proton.Data.Symbol} s the symbol name.
+ * @param {proton.Data.Symbol|string} s the symbol name.
  */
-_Data_['putSymbol'] = function(s) {
+_Data_['putSYMBOL'] = function(s) {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2076,116 +2393,220 @@ _Data_['putSymbol'] = function(s) {
     Runtime.stackRestore(sp);
 };
 
-// TODO getArray and isDescribed
+/**
+ * If the current node is a list node, return the number of elements,
+ * otherwise return zero. List elements can be accessed by entering
+ * the list.
+ * <pre>
+ *  var count = data.getLISTNODE();
+ *  data.enter();
+ *  for (var i = 0; i < count; i++) {
+ *      var type = data.next();
+ *      if (type === proton.Data.STRING) {
+ *          console.log(data.getSTRING());
+ *      }
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getLISTNODE
+ * @memberof! proton.Data#
+ * @returns {number} the number of elements if the current node is a list,
+ *          zero otherwise.
+ */
+_Data_['getLISTNODE'] = function() {
+    return _pn_data_get_list(this._data);
+};
+
+/**
+ * If the current node is a map, return the number of child elements,
+ * otherwise return zero. Key value pairs can be accessed by entering
+ * the map.
+ * <pre>
+ *  var count = data.getMAPNODE();
+ *  data.enter();
+ *  for (var i = 0; i < count/2; i++) {
+ *      var type = data.next();
+ *      if (type === proton.Data.STRING) {
+ *          console.log(data.getSTRING());
+ *      }
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getMAPNODE
+ * @memberof! proton.Data#
+ * @returns {number} the number of elements if the current node is a list,
+ *          zero otherwise.
+ */
+_Data_['getMAPNODE'] = function() {
+    return _pn_data_get_map(this._data);
+};
+
+/**
+ * If the current node is an array, return an object containing the tuple of the
+ * element count, a boolean indicating whether the array is described, and the
+ * type of each element, otherwise return {count: 0, described: false, type: null).
+ * Array data can be accessed by entering the array.
+ * <pre>
+ *  // Read an array of strings with a symbolic descriptor
+ *  var metadata = data.getARRAYNODE();
+ *  var count = metadata.count;
+ *  data.enter();
+ *  data.next();
+ *  console.log("Descriptor:" + data.getSYMBOL());
+ *  for (var i = 0; i < count; i++) {
+ *      var type = data.next();
+ *      console.log("Element:" + data.getSTRING());
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getARRAYNODE
+ * @memberof! proton.Data#
+ * @returns {object} the tuple of the element count, a boolean indicating whether
+ *          the array is described, and the type of each element.
+ */
+_Data_['getARRAYNODE'] = function() {
+    var count = _pn_data_get_array(this._data);
+    var described = (_pn_data_is_array_described(this._data) > 0);
+    var type = _pn_data_get_array_type(this._data);
+    type = (type == -1) ? null : type;
+    return {'count': count, 'described': described, 'type': type};
+};
+
+/**
+ * Checks if the current node is a described node. The descriptor and value may
+ * be accessed by entering the described node.
+ * <pre>
+ *  // read a symbolically described string
+ *  assert(data.isDESCRIBEDNODE()); // will error if the current node is not described
+ *  data.enter();
+ *  console.log(data.getSYMBOL());
+ *  console.log(data.getSTRING());
+ *  data.exit();
+ * </pre>
+ * @method isDESCRIBEDNODE
+ * @memberof! proton.Data#
+ * @returns {boolean} true iff the current node is a described, false otherwise.
+ */
+_Data_['isDESCRIBEDNODE'] = function() {
+    return _pn_data_is_described(this._data);
+};
 
 /**
- * @method getNull
+ * @method getNULL
  * @memberof! proton.Data#
- * @return a null value.
+ * @returns a null value.
  */
-_Data_['getNull'] = function() {
+_Data_['getNULL'] = function() {
     return null;
 };
 
 /**
  * Checks if the current node is a null.
- * @method isNull
+ * @method isNULL
  * @memberof! proton.Data#
  * @returns {boolean} true iff the current node is null.
  */
-_Data_['isNull'] = function() {
+_Data_['isNULL'] = function() {
     return (_pn_data_is_null(this._data) > 0);
 };
 
 /**
- * @method getBoolean
+ * @method getBOOL
  * @memberof! proton.Data#
  * @returns {boolean} a boolean value if the current node is a boolean, returns
  *          false otherwise.
  */
-_Data_['getBoolean'] = function() {
+_Data_['getBOOL'] = function() {
     return (_pn_data_get_bool(this._data) > 0);
 };
 
 /**
- * @method getUnsignedByte
+ * @method getUBYTE
  * @memberof! proton.Data#
  * @returns {number} value if the current node is an unsigned byte, returns 0 otherwise.
  */
-_Data_['getUnsignedByte'] = function() {
+_Data_['getUBYTE'] = function() {
     return _pn_data_get_ubyte(this._data) & 0xFF; // & 0xFF converts to unsigned;
 };
 
 /**
- * @method getByte
+ * @method getBYTE
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a signed byte, returns 0 otherwise.
  */
-_Data_['getByte'] = function() {
+_Data_['getBYTE'] = function() {
     return _pn_data_get_byte(this._data);
 };
 
 /**
- * @return value if the current node is an unsigned short, returns 0 otherwise.
+ * @method getUSHORT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned short, returns 0 otherwise.
  */
-_Data_['getUnsignedShort'] = function() {
+_Data_['getUSHORT'] = function() {
     return _pn_data_get_ushort(this._data) & 0xFFFF; // & 0xFFFF converts to unsigned;
 };
 
 /**
- * @method getShort
+ * @method getSHORT
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a signed short, returns 0 otherwise.
  */
-_Data_['getShort'] = function() {
+_Data_['getSHORT'] = function() {
     return _pn_data_get_short(this._data);
 };
 
 /**
- * @method getUnsignedInteger
+ * @method getUINT
  * @memberof! proton.Data#
  * @returns {number} value if the current node is an unsigned int, returns 0 otherwise.
  */
-_Data_['getUnsignedInteger'] = function() {
+_Data_['getUINT'] = function() {
     var value = _pn_data_get_uint(this._data);
     return (value > 0) ? value : 4294967296 + value; // 4294967296 == 2^32
 };
 
 /**
- * @method getInteger
+ * @method getINT
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a signed int, returns 0 otherwise.
  */
-_Data_['getInteger'] = function() {
-    return _pn_data_put_int(this._data);
+_Data_['getINT'] = function() {
+    return _pn_data_get_int(this._data);
 };
 
 /**
- * @method getChar
+ * @method getCHAR
  * @memberof! proton.Data#
  * @returns {string} the character represented by the unicode value of the current node.
  */
-_Data_['getChar'] = function() {
+_Data_['getCHAR'] = function() {
     return String.fromCharCode(_pn_data_get_char(this._data));
 };
 
 /**
- * @method getUnsignedLong
+ * Retrieve an unsigned long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method getULONG
  * @memberof! proton.Data#
- * @returns {number} value if the current node is an unsigned long, returns 0 otherwise.
+ * @returns {proton.Data.Long} value if the current node is an unsigned long, returns 0 otherwise.
  */
-_Data_['getUnsignedLong'] = function() {
-console.log("getUnsignedLong");
-    return _pn_data_get_ulong(this._data);
+_Data_['getULONG'] = function() {
+    var low = _pn_data_get_ulong(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return (long > 0) ? long : Data.Long.TWO_PWR_64_DBL_ + long;
 };
 
 /**
- * @method getLong
+ * Retrieve a signed long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method getLONG
  * @memberof! proton.Data#
- * @returns {number} value if the current node is a signed long, returns 0 otherwise.
+ * @returns {proton.Data.Long} value if the current node is a signed long, returns 0 otherwise.
  */
-_Data_['getLong'] = function() {
-console.log("getLong");
+_Data_['getLONG'] = function() {
     // Getting the long is a little tricky as it is a 64 bit number. The way
     // emscripten handles this is to return the low 32 bits directly and pass
     // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
@@ -2195,75 +2616,81 @@ console.log("getLong");
     var high = Runtime.getTempRet0();
     var long = new Data.Long(low, high);
     long = long.toNumber();
-
-console.log("Data.getLong() long = " + long);
-
     return long;
 };
 
 /**
- * @method getTimestamp
+ * @method getTIMESTAMP
  * @memberof! proton.Data#
- * @returns {number} value if the current node is a timestamp, returns 0 otherwise.
+ * @returns {Date} a native JavaScript Date instance representing the timestamp.
  */
-_Data_['getTimestamp'] = function() {
-console.log("getTimestamp not properly implemented yet");
-return 123456;
-    //return _pn_data_get_timestamp(this._data);
+_Data_['getTIMESTAMP'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_data_get_timestamp(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
 };
 
 /**
- * @method getFloat
+ * Retrieves a  float value. N.B. converting between floats and doubles is imprecise
+ * so the resulting value might not quite be what you expect.
+ * @method getFLOAT
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a float, returns 0 otherwise.
  */
-_Data_['getFloat'] = function() {
+_Data_['getFLOAT'] = function() {
     return _pn_data_get_float(this._data);
 };
 
 /**
- * @method getDouble
+ * @method getDOUBLE
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a double, returns 0 otherwise.
  */
-_Data_['getDouble'] = function() {
+_Data_['getDOUBLE'] = function() {
     return _pn_data_get_double(this._data);
 };
 
 /**
- * @method getDecimal32
+ * @method getDECIMAL32
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a decimal32, returns 0 otherwise.
  */
-_Data_['getDecimal32'] = function() {
-console.log("getDecimal32 not properly implemented yet");
+_Data_['getDECIMAL32'] = function() {
+console.log("getDECIMAL32 not properly implemented yet");
     return _pn_data_get_decimal32(this._data);
 };
 
 /**
- * @method getDecimal64
+ * @method getDECIMAL64
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a decimal64, returns 0 otherwise.
  */
-_Data_['getDecimal64'] = function() {
-console.log("getDecimal64 not properly implemented yet");
+_Data_['getDECIMAL64'] = function() {
+console.log("getDECIMAL64 not properly implemented yet");
     return _pn_data_get_decimal64(this._data);
 };
 
 /**
- * @method getDecimal128
+ * @method getDECIMAL128
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a decimal128, returns 0 otherwise.
  */
-_Data_['getDecimal128'] = function() {
-console.log("getDecimal128 not properly implemented yet");
+_Data_['getDECIMAL128'] = function() {
+console.log("getDECIMAL128 not properly implemented yet");
     return _pn_data_get_decimal128(this._data);
 };
 
 /**
  * @method getUUID
  * @memberof! proton.Data#
- * @return {proton.Data.UUID} value if the current node is a UUID, returns null otherwise.
+ * @returns {proton.Data.Uuid} value if the current node is a UUID, returns null otherwise.
  */
 _Data_['getUUID'] = function() {
     var sp = Runtime.stackSave();
@@ -2277,7 +2704,7 @@ _Data_['getUUID'] = function() {
     _pn_data_get_uuid(bytes, this._data);
 
     // Create a new UUID from the bytes
-    var uuid = new Data['UUID'](bytes);
+    var uuid = new Data['Uuid'](bytes);
 
     // Tidy up the memory that we allocated on emscripten's stack.
     Runtime.stackRestore(sp);
@@ -2286,11 +2713,11 @@ _Data_['getUUID'] = function() {
 };
 
 /**
- * @method getBinary
+ * @method getBINARY
  * @memberof! proton.Data#
  * @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise.
  */
-_Data_['getBinary'] = function() {
+_Data_['getBINARY'] = function() {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2322,11 +2749,11 @@ _Data_['getBinary'] = function() {
 
 /**
  * Gets a unicode String value from the current node.
- * @method getString
+ * @method getSTRING
  * @memberof! proton.Data#
- * @return {string} value if the current node is a String, returns "" otherwise.
+ * @returns {string} value if the current node is a String, returns "" otherwise.
  */
-_Data_['getString'] = function() {
+_Data_['getSTRING'] = function() {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2362,11 +2789,11 @@ _Data_['getString'] = function() {
  * open-ended, typically the both number and size of symbols in use for any
  * given application will be small, e.g. small enough that it is reasonable to
  * cache all the distinct values. Symbols are encoded as ASCII characters.
- * @method getSymbol
+ * @method getSYMBOL
  * @memberof! proton.Data#
- * @return {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
+ * @returns {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
  */
-_Data_['getSymbol'] = function() {
+_Data_['getSYMBOL'] = function() {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2396,18 +2823,65 @@ _Data_['getSymbol'] = function() {
     return new Data['Symbol'](string);
 };
 
+/**
+ * Performs a deep copy of the current {@link proton.Data} instance and returns it
+ * @method copy
+ * @memberof! proton.Data#
+ * @returns {proton.Data} a copy of the current {@link proton.Data} instance.
+ */
+_Data_['copy'] = function() {
+    var copy = new Data();
+    this._check(_pn_data_copy(copy._data, this._data));
+    return copy;
+};
 
-// TODO copy, format and dump
+/**
+ * Format the encoded AMQP Data into a string representation and return it.
+ * @method format
+ * @memberof! proton.Data#
+ * @returns {string} a formatted string representation of the encoded Data.
+ */
+_Data_['format'] = function() {
+    var size = 1024; // Pass by reference variable - need to use setValue to initialise it.
+    while (true) {
+        setValue(size, size, 'i32'); // Set pass by reference variable.
+        var bytes = _malloc(size);   // Allocate storage from emscripten heap.
+        var err = _pn_data_format(this._data, bytes, size);
+        var size = getValue(size, 'i32'); // Dereference the real size value;
+
+        if (err === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else {
+            var string = Pointer_stringify(bytes);
+            _free(bytes);
+            this._check(err)
+            return string;
+        }
+    }
+};
 
+/**
+ * Print the internal state of the {@link proton.Data} in human readable form.
+ * TODO. This seems to "crash" if compound nodes such as DESCRIBED, MAP or LIST
+ * are present in the tree, this is most likely a problem with the underlying C
+ * implementation as all the other navigation and format methods work - need to
+ * check by testing with some native C code.
+ * @method dump
+ * @memberof! proton.Data#
+ */
+_Data_['dump'] = function() {
+    _pn_data_dump(this._data);
+};
 
 /**
  * Serialise a Native JavaScript Object into an AMQP Map.
- * @method putDictionary
+ * @method putMAP
  * @memberof! proton.Data#
  * @param {object} object the Native JavaScript Object that we wish to serialise.
  */
-_Data_['putDictionary'] = function(object) {
-    this['putMap']();
+_Data_['putMAP'] = function(object) {
+    this['putMAPNODE']();
     this['enter']();
     for (var key in object) {
         if (object.hasOwnProperty(key)) {
@@ -2420,18 +2894,18 @@ _Data_['putDictionary'] = function(object) {
 
 /**
  * Deserialise from an AMQP Map into a Native JavaScript Object.
- * @method getDictionary
+ * @method getMAP
  * @memberof! proton.Data#
  * @returns {object} the deserialised Native JavaScript Object.
  */
-_Data_['getDictionary'] = function() {
+_Data_['getMAP'] = function() {
     if (this['enter']()) {
         var result = {};
         while (this['next']()) {
             var key = this['getObject']();
             var value = null;
             if (this['next']()) {
-                value = this['getObject']()
+                value = this['getObject']();
             }
             result[key] = value;
         }
@@ -2442,26 +2916,26 @@ _Data_['getDictionary'] = function() {
 
 /**
  * Serialise a Native JavaScript Array into an AMQP List.
- * @method putJSArray
+ * @method putLIST
  * @memberof! proton.Data#
  * @param {Array} array the Native JavaScript Array that we wish to serialise.
  */
-_Data_['putJSArray'] = function(array) {
-    this['putList']();
+_Data_['putLIST'] = function(array) {
+    this['putLISTNODE']();
     this['enter']();
     for (var i = 0, len = array.length; i < len; i++) {
-        this['putObject'](array[i])
+        this['putObject'](array[i]);
     }
     this['exit']();
 };
 
 /**
  * Deserialise from an AMQP List into a Native JavaScript Array.
- * @method getJSArray
+ * @method getLIST
  * @memberof! proton.Data#
- * @returns {array} the deserialised Native JavaScript Array.
+ * @returns {Array} the deserialised Native JavaScript Array.
  */
-_Data_['getJSArray'] = function() {
+_Data_['getLIST'] = function() {
     if (this['enter']()) {
         var result = [];
         while (this['next']()) {
@@ -2473,6 +2947,150 @@ _Data_['getJSArray'] = function() {
 };
 
 /**
+ * Serialise a proton.Data.Described into an AMQP Described.
+ * @method putDESCRIBED
+ * @memberof! proton.Data#
+ * @param {proton.Data.Described} d the proton.Data.Described that we wish to serialise.
+ */
+_Data_['putDESCRIBED'] = function(d) {
+    this['putDESCRIBEDNODE']();
+    this['enter']();
+    this['putObject'](d['descriptor']);
+    this['putObject'](d['value']);
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Described into a proton.Data.Described.
+ * @method getDESCRIBED
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Described} the deserialised proton.Data.Described.
+ */
+_Data_['getDESCRIBED'] = function() {
+    if (this['enter']()) {
+        this['next']();
+        var descriptor = this['getObject']();
+        this['next']();
+        var value = this['getObject']();
+        this['exit']();
+        return new Data['Described'](value, descriptor);
+    }
+};
+
+/**
+ * Serialise a proton.Data.Array or JavaScript TypedArray into an AMQP Array.
+ * @method putARRAY
+ * @memberof! proton.Data#
+ * @param {object} a the proton.Data.Array or TypedArray that we wish to serialise.
+ */
+_Data_['putARRAY'] = function(a) {
+    var type = 1;
+    var descriptor = 'TypedArray';
+    var array = a;
+
+    if (a instanceof Data['Array']) { // Array is a proton.Data.Array
+        type = Data[a['type']]; // Find the integer type from its name string.
+        descriptor = a['descriptor'];
+        array = a['elements'];
+    } else { // Array is a Native JavaScript TypedArray so work out the right type.
+        if (a instanceof Int8Array) {
+            type = Data['BYTE'];
+        } else if (a instanceof Uint8Array || a instanceof Uint8ClampedArray) {
+            type = Data['UBYTE'];
+        } else if (a instanceof Int16Array) {
+            type = Data['SHORT'];
+        } else if (a instanceof Uint16Array) {
+            type = Data['USHORT'];
+        } else if (a instanceof Int32Array) {
+            type = Data['INT'];
+        } else if (a instanceof Uint32Array) {
+            type = Data['UINT'];
+        } else if (a instanceof Float32Array) {
+            type = Data['FLOAT'];
+        } else if (a instanceof Float64Array) {
+            type = Data['DOUBLE'];
+        }
+    }
+
+    var described = descriptor != null;
+
+    this['putARRAYNODE'](described, type);
+    this['enter']();
+    if (described) {
+        this['putObject'](descriptor);
+    }
+    var putter = 'put' + Data['TypeNames'][type];
+    for (var i = 0, len = array.length; i < len; i++) {
+        var value = array[i];
+        value = (value instanceof Data.TypedNumber) ? value.value : value;
+        this[putter](value);
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Array into a proton.Data.Array.
+ * @method getARRAY
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Array} the deserialised proton.Data.Array.
+ */
+_Data_['getARRAY'] = function() {
+    var metadata = this['getARRAYNODE']();
+    var count = metadata['count'];
+    var described = metadata['described'];
+    var type = metadata['type'];
+
+    if (type === null) {
+        return null;
+    }
+
+    var elements = null;
+    if (typeof ArrayBuffer === 'function') {
+        if (type === Data['BYTE']) {
+            elements = new Int8Array(count);
+        } else if (type === Data['UBYTE']) {
+            elements = new Uint8Array(count);
+        } else if (type === Data['SHORT']) {
+            elements = new Int16Array(count);
+        } else if (type === Data['USHORT']) {
+            elements = new Uint16Array(count);
+        } else if (type === Data['INT']) {
+            elements = new Int32Array(count);
+        } else if (type === Data['UINT']) {
+            elements = new Uint32Array(count);
+        } else if (type === Data['FLOAT']) {
+            elements = new Float32Array(count);
+        } else if (type === Data['DOUBLE']) {
+            elements = new Float64Array(count);
+        } else {
+            elements = new Array(count);
+        }
+    } else {
+        elements = new Array(count);
+    }
+
+    if (this['enter']()) {
+        var descriptor; // Deliberately initialised as undefined not null.
+        if (described) {
+            this['next']();
+            descriptor = this['getObject']();
+        }
+
+        for (var i = 0; i < count; i++) {
+            this['next']();
+            elements[i] = this['getObject']();
+        }
+
+        this['exit']();
+        if (descriptor === 'TypedArray') {
+            return elements;
+        } else {
+            return new Data['Array'](type, elements, descriptor);
+        }
+    }
+};
+
+/**
  * This method is the entry point for serialising native JavaScript types into
  * AMQP types. In an ideal world there would be a nice clean one to one mapping
  * and we could employ a look-up table but in practice the JavaScript type system
@@ -2485,32 +3103,33 @@ _Data_['getJSArray'] = function() {
 _Data_['putObject'] = function(obj) {
 console.log("Data.putObject");
 
-
 console.log("obj = " + obj);
 //console.log("typeof obj = " + (typeof obj));
 //console.log("obj prototype = " + Object.prototype.toString.call(obj));
 
     if (obj == null) { // == Checks for null and undefined.
-console.log("obj is null");
-        this['putNull']();
+        this['putNULL']();
     } else if (Data.isString(obj)) {
-console.log("obj is String");
-
         var quoted = obj.match(/(['"])[^'"]*\1/);
-        if (quoted) {
-            quoted = quoted[0].slice(1, -1);
-console.log("obj is quoted String " + quoted);
-            this['putString'](quoted);
-        } else {
-            // TODO check for stringified numbers.
-            this['putString'](obj);
-        }   
-    } else if (obj instanceof Data['UUID']) {
+        if (quoted) { // If a quoted string extract the string inside the quotes.
+            obj = quoted[0].slice(1, -1);
+        }
+        this['putSTRING'](obj);
+    } else if (obj instanceof Date) {
+        this['putTIMESTAMP'](obj);
+    } else if (obj instanceof Data['Uuid']) {
         this['putUUID'](obj);
     } else if (obj instanceof Data['Binary']) {
-        this['putBinary'](obj);
+        this['putBINARY'](obj);
     } else if (obj instanceof Data['Symbol']) {
-        this['putSymbol'](obj);
+        this['putSYMBOL'](obj);
+    } else if (obj instanceof Data['Described']) {
+        this['putDESCRIBED'](obj);
+    } else if (obj instanceof Data['Array']) {
+        this['putARRAY'](obj);
+    } else if (obj.buffer && (typeof ArrayBuffer === 'function') && 
+               obj.buffer instanceof ArrayBuffer) {
+        this['putARRAY'](obj);
     } else if (obj instanceof Data.TypedNumber) { // Dot notation used for "protected" inner class.
         // Call the appropriate serialisation method based upon the numerical type.
         this['put' + obj.type](obj.value);
@@ -2519,42 +3138,37 @@ console.log("obj is quoted String " + quoted);
          * This block encodes standard JavaScript numbers by making some inferences.
          * Encoding JavaScript numbers is surprisingly complex and has several
          * gotchas. The code here tries to do what the author believes is the
-         * most intuitive encoding of the native JavaScript Number. It first
+         * most "intuitive" encoding of the native JavaScript Number. It first
          * tries to identify if the number is an integer or floating point type
          * by checking if the number modulo 1 is zero (i.e. if it has a remainder
          * then it's a floating point type, which is encoded here as a double).
          * If the number is an integer type a test is made to check if it is a
-         * 32 bit Int value. N.B. JavaScript automagically coerces floating
-         * point numbers with a zero Fractional Part into an exact integer so
+         * 32 bit Int value. N.B. gotcha - JavaScript automagically coerces floating
+         * point numbers with a zero Fractional Part into an *exact* integer so
          * numbers like 1.0, 100.0 etc. will be encoded as int or long here,
          * which is unlikely to be what is wanted. There's no easy "transparent"
          * way around this. The TypedNumber approach above allows applications
-         * to express more explicitly what is require, for example 1.0.asFloat()
-         * (1).asUnsignedByte(), (5).asLong() etc.
+         * to express more explicitly what is required, for example (1.0).float()
+         * (1).ubyte(), (5).long() etc.
          */
         if (obj % 1 === 0) {
-console.log(obj + " is Integer Type " + (obj|0));
             if (obj === (obj|0)) { // the |0 coerces to a 32 bit value.
-                // 32 bit integer - encode as an Integer.
-console.log(obj + " is Int ");
-                this['putInteger'](obj);
+                // 32 bit integer - encode as an INT.
+                this['putINT'](obj);
             } else { // Longer than 32 bit - encode as a Long.
-console.log(obj + " is Long");
-                this['putLong'](obj);
+                this['putLONG'](obj);
             }
         } else { // Floating point type - encode as a Double
-console.log(obj + " is Float Type");
-            this['putDouble'](obj);
+            this['putDOUBLE'](obj);
         }
     } else if (Data.isBoolean(obj)) {
-        this['putBoolean'](obj);
+        this['putBOOL'](obj);
     } else if (Data.isArray(obj)) { // Native JavaScript Array
-        this['putJSArray'](obj);
+        this['putLIST'](obj);
     } else {
-        this['putDictionary'](obj);
+        this['putMAP'](obj);
     }
 };
-_Data_.putObject = _Data_['putObject'];
 
 /**
  * @method getObject
@@ -2562,18 +3176,10 @@ _Data_.putObject = _Data_['putObject'];
  * @returns {object} the JavaScript Object or primitive being deserialised.
  */
 _Data_['getObject'] = function() {
-console.log("Data.getObject: not fully implemented yet");
-
-    var type = this.type();
-console.log("type = " + type);
-
-    var getter = Data.GetMappings[type];
-
-console.log("getter = " + getter);
-
+    var type = Data['TypeNames'][this.type()];
+    type = type ? type : 'NULL';
+    var getter = 'get' + type;
     return this[getter]();
 };
-_Data_.getObject = _Data_['getObject'];
-
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/proton-c/bindings/javascript/data-test.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-test.js b/proton-c/bindings/javascript/data-test.js
deleted file mode 100644
index 6904bc9..0000000
--- a/proton-c/bindings/javascript/data-test.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/**
- * Unit tests for the Data Class.
- * TODO this is just some random stuff at the moment - need to port the python codec test.
- */
-
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("../../../bld/proton-c/bindings/javascript/proton.js");
-}
-
-
-try {
-
-    var messenger = new proton.Messenger();
-
-    console.log("name = " + messenger.getName());
-
-    console.log("timeout = " + messenger.getTimeout());
-
-    console.log("isBlocking = " + messenger.isBlocking());
-
-    messenger.setIncomingWindow(1234);
-    console.log("incoming window = " + messenger.getIncomingWindow());
-
-    messenger.setOutgoingWindow(5678);
-    console.log("outgoing window = " + messenger.getOutgoingWindow());
-
-
-    messenger.start();
-    console.log("isStopped = " + messenger.isStopped());
-
-
-    //messenger.subscribe("amqp://narnia");
-    var subscription = messenger.subscribe("amqp://~0.0.0.0");
-    console.log("subscription address = " + subscription.getAddress());
-
-
-    var message = new proton.Message();
-    message.setAddress("amqp://localhost:5672");
-    console.log("message address = " + message.getAddress());
-
-    message.setSubject("UK.WEATHER");
-    console.log("message subject = " + message.getSubject());
-
-
-    messenger.stop();
-    console.log("isStopped = " + messenger.isStopped());
-
-
-
-    message.free();
-
-    messenger.free();
-
-} catch(e) {
-    console.log("Caught Exception " + e);
-}


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


[09/51] [abbrv] qpid-proton git commit: Implemented the remainder of the codec methods and ported the codec unit test suite to test it all

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/tests/javascript/codec.js
----------------------------------------------------------------------
diff --git a/tests/javascript/codec.js b/tests/javascript/codec.js
new file mode 100644
index 0000000..95e36e4
--- /dev/null
+++ b/tests/javascript/codec.js
@@ -0,0 +1,544 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * This is a fairly literal JavaScript port of codec.py used to unit test the
+ * proton.Data wrapper class.
+ */
+
+// Check if the environment is Node.js and if so import the required libraries.
+if (typeof exports !== "undefined" && exports !== null) {
+    unittest = require("./unittest.js");
+    assert = require("assert");
+    proton = require("qpid-proton");
+}
+
+// We extend TestCase by creating an instance and adding test methods as properties.
+var DataTest = new unittest.TestCase();
+
+DataTest.setUp = function() {
+    this.data = new proton.Data();
+};
+
+DataTest.tearDown = function() {
+    this.data.free();
+    this.data = null;
+};
+
+DataTest.testTopLevelNext = function() {
+    console.log("testTopLevelNext");
+    assert(this.data.next() === null);
+    this.data.putNULL();
+    this.data.putBOOL(false);
+    this.data.putINT(0);
+    assert(this.data.next() === null);
+    this.data.rewind();
+    assert(this.data.next() === proton.Data.NULL);
+    assert(this.data.next() === proton.Data.BOOL);
+    assert(this.data.next() === proton.Data.INT);
+    assert(this.data.next() === null);
+    console.log("OK\n");
+};
+
+DataTest.testNestedNext = function() {
+    console.log("testNestedNext");
+    assert(this.data.next() === null);
+    this.data.putNULL();
+    assert(this.data.next() === null);
+    this.data.putLISTNODE();
+    assert(this.data.next() === null);
+    this.data.putBOOL(false);
+    assert(this.data.next() === null);
+    this.data.rewind();
+    assert(this.data.next() === proton.Data.NULL);
+    assert(this.data.next() === proton.Data.LIST);
+    this.data.enter();
+    assert(this.data.next() === null);
+    this.data.putUBYTE(0);
+    assert(this.data.next() === null);
+    this.data.putUINT(0);
+    assert(this.data.next() === null);
+    this.data.putINT(0);
+    assert(this.data.next() === null);
+    this.data.exit();
+    assert(this.data.next() === proton.Data.BOOL);
+    assert(this.data.next() === null);
+
+    this.data.rewind();
+    assert(this.data.next() === proton.Data.NULL);
+    assert(this.data.next() === proton.Data.LIST);
+    assert(this.data.enter());
+    assert(this.data.next() === proton.Data.UBYTE);
+    assert(this.data.next() === proton.Data.UINT);
+    assert(this.data.next() === proton.Data.INT);
+    assert(this.data.next() === null);
+    assert(this.data.exit());
+    assert(this.data.next() === proton.Data.BOOL);
+    assert(this.data.next() === null);
+    console.log("OK\n");
+};
+
+DataTest.testEnterExit = function() {
+    console.log("testEnterExit");
+    assert(this.data.next() === null);
+    assert(!this.data.enter());
+    this.data.putLISTNODE();
+    assert(this.data.enter());
+    assert(this.data.next() === null);
+    this.data.putLISTNODE();
+    assert(this.data.enter());
+    this.data.putLISTNODE();
+    assert(this.data.enter());
+    assert(this.data.exit());
+    assert(this.data.getLISTNODE() === 0);
+    assert(this.data.exit());
+    assert(this.data.getLISTNODE() === 1);
+    assert(this.data.exit());
+    assert(this.data.getLISTNODE() === 1);
+    assert(!this.data.exit());
+    assert(this.data.getLISTNODE() === 1);
+    assert(this.data.next() === null);
+
+    this.data.rewind();
+    assert(this.data.next() === proton.Data.LIST);
+    assert(this.data.getLISTNODE() === 1);
+    assert(this.data.enter());
+    assert(this.data.next() === proton.Data.LIST);
+    assert(this.data.getLISTNODE() === 1);
+    assert(this.data.enter());
+    assert(this.data.next() === proton.Data.LIST);
+    assert(this.data.getLISTNODE() === 0);
+    assert(this.data.enter());
+    assert(this.data.next() === null);
+    assert(this.data.exit());
+    assert(this.data.getLISTNODE() === 0);
+    assert(this.data.exit());
+    assert(this.data.getLISTNODE() === 1);
+    assert(this.data.exit());
+    assert(this.data.getLISTNODE() === 1);
+    assert(!this.data.exit());
+    console.log("OK\n");
+};
+
+/**
+ * This tests the "low level" putARRAYNODE/getARRAYNODE methods.
+ * In general though applications would create a proton.Data.Array and use the
+ * higher level putARRAY/getARRAY
+ */
+DataTest._testArray = function(dtype, descriptor, atype, values) {
+    var values = Array.prototype.slice.apply(arguments, [3]);
+    dtype = (dtype == null) ? null : dtype.toUpperCase();
+    atype = atype.toUpperCase();
+
+    // Create an array node, enter it and put the descriptor (if present) and values.
+    this.data.putARRAYNODE(dtype != null, proton.Data[atype]);
+    this.data.enter();
+    if (dtype != null) {
+        var putter = 'put' + dtype;
+        this.data[putter](descriptor);
+    }
+    var putter = 'put' + atype;
+    for (var i = 0; i < values.length; i++) {
+        this.data[putter](values[i]);
+    }
+    this.data.exit();
+
+    // Check that we did indeed add an Array node
+    this.data.rewind();
+    assert(this.data.next() === proton.Data.ARRAY);
+
+    // Get the count, described and type metadata from the array node and compare
+    // with the values we passed to putARRAYNODE.
+    var metadata = this.data.getARRAYNODE();
+    var count = metadata.count;
+    var described = metadata.described;
+    var type = metadata.type;
+
+    assert(count === values.length);
+    if (dtype == null) {
+        assert(described === false);
+    } else {
+        assert(described === true);
+    }
+    assert(type === proton.Data[atype]);
+
+    // Enter the array node and compare the descriptor and values with those that
+    // we put into the array.
+    assert(this.data.enter());
+    if (described) {
+        assert(this.data.next() === proton.Data[dtype]);
+        var getter = 'get' + dtype;
+        var gotten = this.data[getter]();
+        assert(gotten.toString() === descriptor.toString());
+    }
+    var getter = 'get' + atype;
+    for (var i = 0; i < values.length; i++) {
+        assert(this.data.next() === proton.Data[atype]);
+        var gotten = this.data[getter]();
+        assert(gotten.toString() === values[i].toString());
+    }
+    assert(this.data.next() === null);
+    assert(this.data.exit());
+};
+
+DataTest.testStringArray = function() {
+    console.log("testStringArray");
+    this._testArray(null, null, "string", "one", "two", "three");
+
+    // Now try using the proton.Data.Array class.
+    this.data.clear();
+    var put = new proton.Data.Array("STRING", ["four", "five", "six"]);
+    this.data.putARRAY(put);
+    var get = this.data.getARRAY();
+    assert(get.equals(put));
+    console.log("OK\n");
+};
+
+DataTest.testDescribedStringArray = function() {
+    console.log("testDescribedStringArray");
+    this._testArray("symbol", "url", "string", "one", "two", "three");
+
+    // Now try using the proton.Data.Array class.
+    this.data.clear();
+    var put = new proton.Data.Array("STRING", ["four", "five", "six"], new proton.Data.Symbol("url"));
+    this.data.putARRAY(put);
+    var get = this.data.getARRAY();
+    assert(get.equals(put));
+    console.log("OK\n");
+};
+
+DataTest.testIntArray = function() {
+    console.log("testIntArray");
+    this._testArray(null, null, "int", 1, 2, 3);
+
+    // Now try using the proton.Data.Array class.
+    this.data.clear();
+    var put = new proton.Data.Array("INT", [4, 5, 6]);
+    this.data.putARRAY(put);
+    var get = this.data.getARRAY();
+    assert(get.equals(put));
+    console.log("OK\n");
+};
+
+DataTest.testUUIDArray = function() {
+    console.log("testUUIDArray");
+    this._testArray(null, null, "uuid", new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid());
+
+    // Now try using the proton.Data.Array class.
+    this.data.clear();
+    var put = new proton.Data.Array("UUID", [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()]);
+    this.data.putARRAY(put);
+    var get = this.data.getARRAY();
+    assert(get.equals(put));
+    console.log("OK\n");
+};
+
+DataTest.testEmptyArray = function() {
+    console.log("testEmptyArray");
+    this._testArray(null, null, "null");
+
+    // Now try using the proton.Data.Array class.
+    this.data.clear();
+    var put = new proton.Data.Array();
+    this.data.putARRAY(put);
+    var get = this.data.getARRAY();
+    assert(get.equals(put));
+    console.log("OK\n");
+};
+
+DataTest.testDescribedEmptyArray = function() {
+    console.log("testDescribedEmptyArray");
+    this._testArray("long", 0, "null");
+
+    // Now try using the proton.Data.Array class.
+    this.data.clear();
+    var put = new proton.Data.Array((0).long());
+    this.data.putARRAY(put);
+    var get = this.data.getARRAY();
+    assert(get.equals(put));
+    console.log("OK\n");
+};
+
+DataTest._test = function(dtype, values) {
+    var values = Array.prototype.slice.apply(arguments, [1]);
+    var lastValue = values[values.length - 1];
+
+    // Default equality function. Note that we use valueOf because some of the
+    // types we are trying to compare (Symbol, Timestamp, Uuid etc.) are object
+    // types and we want to compare their value not whether they are the same object.
+    var eq = function(x, y) {return x.valueOf() === y.valueOf();};
+
+    if (typeof lastValue === 'function') {
+        eq = values.pop();
+    }
+
+    dtype = dtype.toUpperCase();
+    var ntype = proton.Data[dtype];
+    var putter = 'put' + dtype;
+    var getter = 'get' + dtype;
+
+    for (var i = 0; i < values.length; i++) {
+        var v = values[i];
+        /*
+         * Replace the array element with its value. We do this to make testing
+         * simpler for Binary elements. In the case of Binary putBINARY "consumes"
+         * the data, in other words ownership of the underlying raw data transfers
+         * to the Data object so the v object becomes "empty" after calling the
+         * putter. Calling its valueOf() happens to call its toString() which
+         * provides a stringified version of the Binary whilst also working for
+         * the other data types we want to test too.
+         */
+        values[i] = v.valueOf();
+        this.data[putter](v);
+        var gotten = this.data[getter]();
+        assert(eq(gotten, values[i]));
+    }
+
+    this.data.rewind();
+
+    for (var i = 0; i < values.length; i++) {
+        var v = values[i];
+        var vtype = this.data.next();
+        assert(vtype === ntype);
+        var gotten = this.data[getter]();
+        assert(eq(gotten, v));
+    }
+
+    // Test encode and decode methods.
+    var encoded = this.data.encode();
+    var copy = new proton.Data();
+    while (encoded) {
+        encoded = copy.decode(encoded);
+    }
+    copy.rewind();
+
+    for (var i = 0; i < values.length; i++) {
+        var v = values[i];
+        var vtype = copy.next();
+        assert(vtype === ntype);
+        var gotten = copy[getter]();
+        assert(eq(gotten, v));
+    }
+    copy.free();
+};
+
+DataTest.testInt = function() {
+    console.log("testInt");
+    this._test("int", 1, 2, 3, -1, -2, -3);
+    console.log("OK\n");
+
+};
+
+DataTest.testString = function() {
+    console.log("testString");
+    this._test("string", "one", "two", "three", "this is a test", "");
+    console.log("OK\n");
+};
+
+DataTest.testBigString = function() {
+    // Try a 2MB string, this is about as big as we can cope with using the default
+    // emscripten heap size.
+    console.log("testBigString");
+    var data = "";
+    for (var i = 0; i < 2000000; i++) {
+        data += "*";
+    }
+    var string = "start\n" + data + "\nfinish\n";
+    this._test("string", string);
+    console.log("OK\n");
+};
+
+DataTest.testFloat = function() {
+    console.log("testFloat");
+    // We have to use a special comparison here because JavaScript internally
+    // only uses doubles and converting between floats and doubles is imprecise.
+    this._test("float", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3,
+               function(x, y) {return (x - y < 0.000001);});
+    console.log("OK\n");
+};
+
+DataTest.testDouble = function() {
+    console.log("testDouble");
+    this._test("double", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3);
+    console.log("OK\n");
+};
+
+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("ВИНАРЫ"));
+    console.log("OK\n");
+};
+
+DataTest.testSymbol = function() {
+    console.log("testSymbol");
+    this._test("symbol", new proton.Data.Symbol("this is a symbol test"),
+                         new proton.Data.Symbol("bleh"), new proton.Data.Symbol("blah"));
+    console.log("OK\n");
+};
+
+DataTest.testTimestamp = function() {
+    console.log("testTimestamp");
+    this._test("timestamp", new Date(0), new Date(12345), new Date(1000000));
+    console.log("OK\n");
+};
+
+DataTest.testChar = function() {
+    console.log("testChar");
+    this._test("char", 'a', 'b', 'c', '\u1234');
+    console.log("OK\n");
+};
+
+DataTest.testUUID = function() {
+    console.log("testUUID");
+    this._test("uuid", new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid());
+    console.log("OK\n");
+};
+
+/* TODO
+DataTest.testDecimal32 = function() {
+    console.log("testDecimal32");
+    //this._test("decimal32", 0, 1, 2, 3, 4, Math.pow(2, 30));
+};
+
+DataTest.testDecimal64 = function() {
+    console.log("testDecimal64");
+    //this._test("decimal64", 0, 1, 2, 3, 4, Math.pow(2, 60));
+};
+
+DataTest.testDecimal128 = function() {
+    console.log("testDecimal128");
+    // TODO
+};
+*/
+
+DataTest.testCopy = function() {
+    console.log("testCopy");
+    this.data.putDESCRIBEDNODE();
+    this.data.enter();
+    this.data.putULONG(123);
+    this.data.putMAPNODE();
+    this.data.enter();
+    this.data.putSTRING("pi");
+    this.data.putDOUBLE(3.14159265359);
+    this.data.exit();
+    this.data.exit();
+
+    var dst = this.data.copy();
+    var copy = dst.format();
+    var orig = this.data.format();
+    assert(copy === orig);
+    dst.free();
+    console.log("OK\n");
+};
+
+DataTest.testCopyNested = function() {
+    console.log("testCopyNested");
+    var nested = [1, 2, 3, [4, 5, 6], 7, 8, 9];
+    this.data.putObject(nested);
+    var dst = this.data.copy();
+    assert(dst.format() === this.data.format());
+    dst.free();
+    console.log("OK\n");
+};
+
+DataTest.testCopyNestedArray = function() {
+    console.log("testCopyNestedArray");
+    var nested = [new proton.Data.Array("LIST", [
+                    ["first",  [new proton.Data.Array("INT", [1, 2, 3]), "this"]],
+                    ["second", [new proton.Data.Array("INT", [1, 2, 3]), "is"]],
+                    ["third",  [new proton.Data.Array("INT", [1, 2, 3]), "fun"]]
+                    ]),
+                "end"];
+    this.data.putObject(nested);
+    var dst = this.data.copy();
+    assert(dst.format() === this.data.format());
+    dst.free();
+    console.log("OK\n");
+};
+
+DataTest.testRoundTrip = function() {
+    console.log("testRoundTrip");
+    var obj = {key: new Date(1234),
+               123: "blah",
+               c: "bleh",
+               desc: new proton.Data.Described("http://example.org", new proton.Data.Symbol("url")),
+               array: new proton.Data.Array("INT", [1, 2, 3]),
+               list: [1, 2, 3, null, 4],
+               boolean: true};
+    // Serialise obj into this.data.
+    this.data.putObject(obj);
+
+    // Encode this.data into a Binary representation.
+    var enc = this.data.encode();
+
+    // Create a new Data instance and decode from the Binary representation
+    // consuming the Binary contents in the process.
+    var data = new proton.Data();
+    data.decode(enc);
+
+    assert(data.format() === this.data.format());
+
+    // Deserialise from the copied Data instance into a new JavaScript Object.
+    data.rewind();
+    assert(data.next());
+    var copy = data.getObject();
+
+    // Create yet another Data instance and serialise the new Object into that.
+    var data1 = new proton.Data();
+    data1.putObject(copy);
+
+    // Compare the round tripped Data with the original one.
+    assert(data1.format() === this.data.format());
+
+    data.free();
+    data1.free();
+    console.log("OK\n");
+};
+
+DataTest.testLookup = function() {
+    console.log("testLookup");
+    var obj = {key: "value",
+               pi: 3.14159,
+               list: [1, 2, 3, 4]};
+    // Serialise obj into this.data.
+    this.data.putObject(obj);
+    this.data.rewind();
+    this.data.next();
+    this.data.enter();
+    this.data.narrow();
+    assert(this.data.lookup("pi"));
+    assert(this.data.getObject() === 3.14159);
+    this.data.rewind();
+    assert(this.data.lookup("key"));
+    assert(this.data.getObject() === "value");
+    this.data.rewind();
+    assert(this.data.lookup("list"));
+    assert(this.data.getObject().toString() === "1,2,3,4");
+    this.data.widen();
+    this.data.rewind();
+    assert(!this.data.lookup("pi"));
+    console.log("OK\n");
+};
+
+DataTest.run();
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/tests/javascript/unittest.js
----------------------------------------------------------------------
diff --git a/tests/javascript/unittest.js b/tests/javascript/unittest.js
new file mode 100644
index 0000000..bc1567c
--- /dev/null
+++ b/tests/javascript/unittest.js
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * The TestCase class provides a simple dependency-free Unit Test framework to
+ * automagically invoke methods that start with "test" on classes that extend it.
+ */
+
+// TestCase Constructor
+var TestCase = function() {};
+
+// Enumerate all functions of the class and invoke those beginning with "test".
+TestCase.prototype.run = function() {
+    for (var property in this) {
+        if ((typeof this[property] === 'function') &&
+            property.lastIndexOf('test', 0) === 0) {
+            this.setUp();
+            this[property]();
+            this.tearDown();
+        }
+    }
+};
+
+TestCase.prototype.setUp = function() {};
+TestCase.prototype.tearDown = function() {};
+
+module.exports.TestCase = TestCase;
+


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


[15/51] [abbrv] qpid-proton git commit: NO-JIRA: add .gitignore file to ensure git creates the otherwise empty lib dir

Posted by rh...@apache.org.
NO-JIRA: add .gitignore file to ensure git creates the otherwise empty lib dir

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1620859 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/c3efc08e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/c3efc08e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/c3efc08e

Branch: refs/heads/master
Commit: c3efc08e84e839368eec63e648a23ad8e47a225e
Parents: a61e5f9
Author: Robert Gemmell <ro...@apache.org>
Authored: Wed Aug 27 10:48:58 2014 +0000
Committer: Robert Gemmell <ro...@apache.org>
Committed: Wed Aug 27 10:48:58 2014 +0000

----------------------------------------------------------------------
 .../javascript/qpid-proton/lib/.gitignore       | 21 ++++++++++++++++++++
 1 file changed, 21 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c3efc08e/proton-c/bindings/javascript/qpid-proton/lib/.gitignore
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/qpid-proton/lib/.gitignore b/proton-c/bindings/javascript/qpid-proton/lib/.gitignore
new file mode 100644
index 0000000..2b1f291
--- /dev/null
+++ b/proton-c/bindings/javascript/qpid-proton/lib/.gitignore
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Currently empty .gitignore
+# Used to ensure git creates the otherwise empty directory


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


[31/51] [abbrv] qpid-proton git commit: Refactor JavaScript binding from a single ludicrously huge binding.js into a set of sub-modules that should hopefully make maintenance much simpler

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/data.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data.js b/proton-c/bindings/javascript/data.js
new file mode 100644
index 0000000..018c5fb
--- /dev/null
+++ b/proton-c/bindings/javascript/data.js
@@ -0,0 +1,1577 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                    Data                                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.Data instance.
+ * @classdesc
+ * The Data class provides an interface for decoding, extracting, creating, and
+ * encoding arbitrary AMQP data. A Data object contains a tree of AMQP values.
+ * Leaf nodes in this tree correspond to scalars in the AMQP type system such as
+ * ints<INT> or strings<STRING>. Non-leaf nodes in this tree correspond to compound
+ * values in the AMQP type system such as lists<LIST>, maps<MAP>, arrays<ARRAY>,
+ * or described values<DESCRIBED>. The root node of the tree is the Data object
+ * itself and can have an arbitrary number of children.
+ * <p>
+ * A Data object maintains the notion of the current sibling node and a current
+ * parent node. Siblings are ordered within their parent. Values are accessed
+ * and/or added by using the next, prev, enter, and exit methods to navigate to
+ * the desired location in the tree and using the supplied variety of put* and
+ * get* methods to access or add a value of the desired type.
+ * <p>
+ * The put* methods will always add a value after the current node in the tree.
+ * If the current node has a next sibling the put* method will overwrite the value
+ * on this node. If there is no current node or the current node has no next
+ * sibling then one will be added. The put* methods always set the added/modified
+ * node to the current node. The get* methods read the value of the current node
+ * and do not change which node is current.
+ * @constructor proton.Data
+ * @param {number} data an optional pointer to a pn_data_t instance. If supplied
+ *        the underlying data is "owned" by another object (for example a Message)
+ *        and that object is assumed to be responsible for freeing the data if
+ *        necessary. If no data is supplied then the Data is stand-alone and the
+ *        client application is responsible for freeing the underlying data via
+ *        a call to free().
+ * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
+ *        objects as strings. This can be useful as the data in Binary objects
+ *        will be overwritten with subsequent calls to get, so they must be
+ *        explicitly copied. Needless to say it is only safe to set this flag if
+ *        you know that the data you are dealing with is actually a string, for
+ *        example C/C++ applications often seem to encode strings as AMQP binary,
+ *        a common cause of interoperability problems.
+ */
+Module['Data'] = function(data, decodeBinaryAsString) { // Data Constructor.
+    if (!data) {
+        this._data = _pn_data(16); // Default capacity is 16
+        this['free'] = function() {
+            _pn_data_free(this._data);
+            // Set free to a null function to prevent possibility of a "double free".
+            this['free'] = function() {};
+        };
+    } else {
+        this._data = data;
+        this['free'] = function() {};
+    }
+    this._decodeBinaryAsString = decodeBinaryAsString;
+};
+
+// Expose constructor as package scope variable to make internal calls less verbose.
+var Data = Module['Data'];
+
+// Expose prototype as a variable to make method declarations less verbose.
+var _Data_ = Data.prototype;
+
+// ************************** Class properties ********************************
+
+Data['NULL']       = 1;
+Data['BOOL']       = 2;
+Data['UBYTE']      = 3;
+Data['BYTE']       = 4;
+Data['USHORT']     = 5;
+Data['SHORT']      = 6;
+Data['UINT']       = 7;
+Data['INT']        = 8;
+Data['CHAR']       = 9;
+Data['ULONG']      = 10;
+Data['LONG']       = 11;
+Data['TIMESTAMP']  = 12;
+Data['FLOAT']      = 13;
+Data['DOUBLE']     = 14;
+Data['DECIMAL32']  = 15;
+Data['DECIMAL64']  = 16;
+Data['DECIMAL128'] = 17;
+Data['UUID']       = 18;
+Data['BINARY']     = 19;
+Data['STRING']     = 20;
+Data['SYMBOL']     = 21;
+Data['DESCRIBED']  = 22;
+Data['ARRAY']      = 23;
+Data['LIST']       = 24;
+Data['MAP']        = 25;
+
+/**
+ * Look-up table mapping proton-c types to the accessor method used to
+ * deserialise the type. N.B. this is a simple Array and not a map because the
+ * types that we get back from pn_data_type are integers from the pn_type_t enum.
+ * @property {Array<String>} TypeNames ['NULL', 'NULL', 'BOOL', 'UBYTE', 'BYTE',
+ * 'USHORT', 'SHORT', 'UINT', 'INT', 'CHAR', 'ULONG', 'LONG', 'TIMESTAMP',
+ * 'FLOAT', 'DOUBLE', 'DECIMAL32', 'DECIMAL64', 'DECIMAL128', 'UUID',
+ * 'BINARY', 'STRING', 'SYMBOL', 'DESCRIBED', 'ARRAY', 'LIST', 'MAP']
+ * @memberof! proton.Data
+ */
+Data['TypeNames'] = [
+    'NULL',       // 0
+    'NULL',       // PN_NULL       = 1
+    'BOOL',       // PN_BOOL       = 2
+    'UBYTE',      // PN_UBYTE      = 3
+    'BYTE',       // PN_BYTE       = 4
+    'USHORT',     // PN_USHORT     = 5
+    'SHORT',      // PN_SHORT      = 6
+    'UINT',       // PN_UINT       = 7
+    'INT',        // PN_INT        = 8
+    'CHAR',       // PN_CHAR       = 9
+    'ULONG',      // PN_ULONG      = 10
+    'LONG',       // PN_LONG       = 11
+    'TIMESTAMP',  // PN_TIMESTAMP  = 12
+    'FLOAT',      // PN_FLOAT      = 13
+    'DOUBLE',     // PN_DOUBLE     = 14
+    'DECIMAL32',  // PN_DECIMAL32  = 15
+    'DECIMAL64',  // PN_DECIMAL64  = 16
+    'DECIMAL128', // PN_DECIMAL128 = 17
+    'UUID',       // PN_UUID       = 18
+    'BINARY',     // PN_BINARY     = 19
+    'STRING',     // PN_STRING     = 20
+    'SYMBOL',     // PN_SYMBOL     = 21
+    'DESCRIBED',  // PN_DESCRIBED  = 22
+    'ARRAY',      // PN_ARRAY      = 23
+    'LIST',       // PN_LIST       = 24
+    'MAP'         // PN_MAP        = 25
+];
+
+// *************************** Class methods **********************************
+
+/**
+ * Test if a given Object is a JavaScript Array.
+ * @method isArray
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a JavaScript Array.
+ */
+Data.isArray = Array.isArray || function(o) {
+    return Object.prototype.toString.call(o) === '[object Array]';
+};
+
+/**
+ * Test if a given Object is a JavaScript Number.
+ * @method isNumber
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a JavaScript Number.
+ */
+Data.isNumber = function(o) {
+    return typeof o === 'number' || 
+          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object Number]');
+};
+
+/**
+ * Test if a given Object is a JavaScript String.
+ * @method isString
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a JavaScript String.
+ */
+Data.isString = function(o) {
+    return typeof o === 'string' ||
+          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object String]');
+};
+
+/**
+ * Test if a given Object is a JavaScript Boolean.
+ * @method isBoolean
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a JavaScript Boolean.
+ */
+Data.isBoolean = function(o) {
+    return typeof o === 'boolean' ||
+          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object Boolean]');
+};
+
+
+// ************************* Protected methods ********************************
+
+// We use the dot notation rather than associative array form for protected
+// methods so they are visible to this "package", but the Closure compiler will
+// minify and obfuscate names, effectively making a defacto "protected" method.
+
+/**
+ * This helper method checks the supplied error code, converts it into an
+ * exception and throws the exception. This method will try to use the message
+ * populated in pn_data_error(), if present, but if not it will fall
+ * back to using the basic error code rendering from pn_code().
+ * @param code the error code to check.
+ */
+_Data_._check = function(code) {
+    if (code < 0) {
+        var errno = this['getErrno']();
+        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
+
+        throw new Module['DataError'](message);
+    } else {
+        return code;
+    }
+};
+
+
+// *************************** Public methods *********************************
+
+/**
+ * @method getErrno
+ * @memberof! proton.Data#
+ * @returns {number} the most recent error message code.
+ */
+_Data_['getErrno'] = function() {
+    return _pn_data_errno(this._data);
+};
+
+/**
+ * @method getError
+ * @memberof! proton.Data#
+ * @returns {string} the most recent error message as a String.
+ */
+_Data_['getError'] = function() {
+    return Pointer_stringify(_pn_error_text(_pn_data_error(this._data)));
+};
+
+/**
+ * Clears the data object.
+ * @method clear
+ * @memberof! proton.Data#
+ */
+_Data_['clear'] = function() {
+    _pn_data_clear(this._data);
+};
+
+/**
+ * Clears current node and sets the parent to the root node.  Clearing the current
+ * node sets it _before_ the first node, calling next() will advance to the first node.
+ * @method rewind
+ * @memberof! proton.Data#
+ */
+_Data_['rewind'] = function() {
+    _pn_data_rewind(this._data);
+};
+
+/**
+ * Advances the current node to its next sibling and returns its type. If there
+ * is no next sibling the current node remains unchanged and null is returned.
+ * @method next
+ * @memberof! proton.Data#
+ * @returns {number} the type of the next sibling or null.
+ */
+_Data_['next'] = function() {
+    var found = _pn_data_next(this._data);
+    if (found) {
+        return this.type();
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Advances the current node to its previous sibling and returns its type. If there
+ * is no previous sibling the current node remains unchanged and null is returned.
+ * @method prev
+ * @memberof! proton.Data#
+ * @returns {number} the type of the previous sibling or null.
+ */
+_Data_['prev'] = function() {
+    var found = _pn_data_prev(this._data);
+    if (found) {
+        return this.type();
+    } else {
+        return null;  
+    }
+};
+
+/**
+ * Sets the parent node to the current node and clears the current node. Clearing
+ * the current node sets it _before_ the first child, next() advances to the first child.
+ * @method enter
+ * @memberof! proton.Data#
+ */
+_Data_['enter'] = function() {
+    return (_pn_data_enter(this._data) > 0);
+};
+
+/**
+ * Sets the current node to the parent node and the parent node to its own parent.
+ * @method exit
+ * @memberof! proton.Data#
+ */
+_Data_['exit'] = function() {
+    return (_pn_data_exit(this._data) > 0);
+};
+
+/**
+ * Look up a value by name. N.B. Need to use getObject() to retrieve the actual
+ * value after lookup suceeds.
+ * @method lookup
+ * @memberof! proton.Data#
+ * @param {string} name the name of the property to look up.
+ * @returns {boolean} true iff the lookup succeeded.
+ */
+_Data_['lookup'] = function(name) {
+    var sp = Runtime.stackSave();
+    var lookup = _pn_data_lookup(this._data, allocate(intArrayFromString(name), 'i8', ALLOC_STACK));
+    Runtime.stackRestore(sp);
+    return (lookup > 0);
+};
+
+// TODO document - not quite sure what these are for?
+_Data_['narrow'] = function() {
+    _pn_data_narrow(this._data);
+};
+
+_Data_['widen'] = function() {
+    _pn_data_widen(this._data);
+};
+
+/**
+ * @method type
+ * @memberof! proton.Data#
+ * @returns {number} the type of the current node or null if the type is unknown.
+ */
+_Data_['type'] = function() {
+    var dtype = _pn_data_type(this._data);
+    if (dtype === -1) {
+        return null;
+    } else {
+        return dtype;
+    }
+};
+
+/**
+ * Return a Binary representation of the data encoded in AMQP format. N.B. the
+ * returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
+ * responsible for freeing it or passing it to a method that consumes a Binary
+ * such as {@link proton.Data.decode} or {@link proton.Data.putBINARY}.
+ * @method encode
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Binary} a representation of the data encoded in AMQP format.
+ */
+_Data_['encode'] = function() {
+    var size = 1024;
+    while (true) {
+        var bytes = _malloc(size); // Allocate storage from emscripten heap.
+        var cd = _pn_data_encode(this._data, bytes, size);
+
+        if (cd === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else if (cd >= 0) {
+            return new Data['Binary'](cd, bytes);
+        } else {
+            _free(bytes);
+            this._check(cd);
+            return;
+        }
+    }
+};
+
+/**
+ * Decodes the first value from supplied Binary AMQP data and returns a new
+ * {@link proton.Data.Binary} containing the remainder of the data or null if
+ * all the supplied data has been consumed. N.B. this method "consumes" data
+ * from a {@link proton.Data.Binary} in other words it takes responsibility for
+ * the underlying data and frees the raw data from the Binary.
+ * @method decode
+ * @memberof! proton.Data#
+ * @param {proton.Data.Binary} encoded the AMQP encoded binary data.
+ * @returns {proton.Data.Binary} a Binary containing the remaining bytes or null
+ *          if all the data has been consumed.
+ */
+_Data_['decode'] = function(encoded) {
+    var start = encoded.start;
+    var size = encoded.size;
+    var consumed = this._check(_pn_data_decode(this._data, start, size));
+
+    size = size - consumed;
+    start = _malloc(size); // Allocate storage from emscripten heap.
+    _memcpy(start, encoded.start + consumed, size);
+
+    encoded['free'](); // Free the original Binary.
+    return size > 0 ? new Data['Binary'](size, start) : null;
+};
+
+/**
+ * Puts a list node. Elements may be filled by entering the list
+ * node and putting element values.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putLISTNODE();
+ *  data.enter();
+ *  data.putINT(1);
+ *  data.putINT(2);
+ *  data.putINT(3);
+ *  data.exit();
+ * </pre>
+ * @method putLISTNODE
+ * @memberof! proton.Data#
+ */
+_Data_['putLISTNODE'] = function() {
+    this._check(_pn_data_put_list(this._data));
+};
+
+/**
+ * Puts a map node. Elements may be filled by entering the map node
+ * and putting alternating key value pairs.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putMAPNODE();
+ *  data.enter();
+ *  data.putSTRING('key');
+ *  data.putSTRING('value');
+ *  data.exit();
+ * </pre>
+ * @method putMAPNODE
+ * @memberof! proton.Data#
+ */
+_Data_['putMAPNODE'] = function() {
+    this._check(_pn_data_put_map(this._data));
+};
+
+/**
+ * Puts an array node. Elements may be filled by entering the array node and
+ * putting the element values. The values must all be of the specified array
+ * element type. If an array is described then the first child value of the array
+ * is the descriptor and may be of any type.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putARRAYNODE(false, proton.Data.INT);
+ *  data.enter();
+ *  data.putINT(1);
+ *  data.putINT(2);
+ *  data.putINT(3);
+ *  data.exit();
+ *
+ *  data.putARRAYNODE(true, proton.Data.DOUBLE);
+ *  data.enter();
+ *  data.putSYMBOL('array-descriptor');
+ *  data.putDOUBLE(1.1);
+ *  data.putDOUBLE(1.2);
+ *  data.putDOUBLE(1.3);
+ *  data.exit();
+ * </pre>
+ * @method putARRAYNODE
+ * @param {boolean} described specifies whether the array is described.
+ * @param {number} type the type of the array elements.
+ * @memberof! proton.Data#
+ */
+_Data_['putARRAYNODE'] = function(described, type) {
+    this._check(_pn_data_put_array(this._data, described, type));
+};
+
+/**
+ * Puts a described node. A described node has two children, the descriptor and
+ * value. These are specified by entering the node and putting the desired values.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putDESCRIBEDNODE();
+ *  data.enter();
+ *  data.putSYMBOL('value-descriptor');
+ *  data.putSTRING('the value');
+ *  data.exit();
+ * </pre>
+ * @method putDESCRIBEDNODE
+ * @memberof! proton.Data#
+ */
+_Data_['putDESCRIBEDNODE'] = function() {
+    this._check(_pn_data_put_described(this._data));
+};
+
+/**
+ * Puts a null value.
+ * @method putNULL
+ * @memberof! proton.Data#
+ */
+_Data_['putNULL'] = function() {
+    this._check(_pn_data_put_null(this._data));
+};
+
+/**
+ * Puts a boolean value.
+ * @method putBOOL
+ * @memberof! proton.Data#
+ * @param {boolean} b a boolean value.
+ */
+_Data_['putBOOL'] = function(b) {
+    this._check(_pn_data_put_bool(this._data, b));
+};
+
+/**
+ * Puts a unsigned byte value.
+ * @method putUBYTE
+ * @memberof! proton.Data#
+ * @param {number} ub an integral value.
+ */
+_Data_['putUBYTE'] = function(ub) {
+    this._check(_pn_data_put_ubyte(this._data, ub));
+};
+
+/**
+ * Puts a signed byte value.
+ * @method putBYTE
+ * @memberof! proton.Data#
+ * @param {number} b an integral value.
+ */
+_Data_['putBYTE'] = function(b) {
+    this._check(_pn_data_put_byte(this._data, b));
+};
+
+/**
+ * Puts a unsigned short value.
+ * @method putUSHORT
+ * @memberof! proton.Data#
+ * @param {number} us an integral value.
+ */
+_Data_['putUSHORT'] = function(us) {
+    this._check(_pn_data_put_ushort(this._data, us));
+};
+
+/**
+ * Puts a signed short value.
+ * @method putSHORT
+ * @memberof! proton.Data#
+ * @param {number} s an integral value.
+ */
+_Data_['putSHORT'] = function(s) {
+    this._check(_pn_data_put_short(this._data, s));
+};
+
+/**
+ * Puts a unsigned integer value.
+ * @method putUINT
+ * @memberof! proton.Data#
+ * @param {number} ui an integral value.
+ */
+_Data_['putUINT'] = function(ui) {
+    this._check(_pn_data_put_uint(this._data, ui));
+};
+
+/**
+ * Puts a signed integer value.
+ * @method putINT
+ * @memberof! proton.Data#
+ * @param {number} i an integral value.
+ */
+_Data_['putINT'] = function(i) {
+    this._check(_pn_data_put_int(this._data, i));
+};
+
+/**
+ * Puts a signed char value.
+ * @method putCHAR
+ * @memberof! proton.Data#
+ * @param {(string|number)} c a single character expressed either as a string or a number.
+ */
+_Data_['putCHAR'] = function(c) {
+    c = Data.isString(c) ? c.charCodeAt(0) : c;
+    this._check(_pn_data_put_char(this._data, c));
+};
+
+/**
+ * Puts a unsigned long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method putULONG
+ * @memberof! proton.Data#
+ * @param {number} ul an integral value.
+ */
+_Data_['putULONG'] = function(ul) {
+    // If the supplied number exceeds the range of Data.Long invert it before
+    // constructing the Data.Long.
+    ul = (ul >= Data.Long.TWO_PWR_63_DBL_) ? (ul = -(Data.Long.TWO_PWR_64_DBL_ - ul)) : ul;
+    var long = Data.Long.fromNumber(ul);
+    this._check(_pn_data_put_ulong(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
+};
+
+/**
+ * Puts a signed long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method putLONG
+ * @memberof! proton.Data#
+ * @param {number} i an integral value.
+ */
+_Data_['putLONG'] = function(l) {
+    var long = Data.Long.fromNumber(l);
+    this._check(_pn_data_put_long(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
+};
+
+/**
+ * Puts a timestamp.
+ * @method putTIMESTAMP
+ * @memberof! proton.Data#
+ * @param {(number|Date)} d a Date value.
+ */
+_Data_['putTIMESTAMP'] = function(d) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(d.valueOf());
+    this._check(_pn_data_put_timestamp(this._data, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
+};
+
+/**
+ * Puts a float value. N.B. converting between floats and doubles is imprecise
+ * so the resulting value might not quite be what you expect.
+ * @method putFLOAT
+ * @memberof! proton.Data#
+ * @param {number} f a floating point value.
+ */
+_Data_['putFLOAT'] = function(f) {
+    this._check(_pn_data_put_float(this._data, f));
+};
+
+/**
+ * Puts a double value.
+ * @method putDOUBLE
+ * @memberof! proton.Data#
+ * @param {number} d a floating point value.
+ */
+_Data_['putDOUBLE'] = function(d) {
+    this._check(_pn_data_put_double(this._data, d));
+};
+
+/**
+ * Puts a decimal32 value.
+ * @method putDECIMAL32
+ * @memberof! proton.Data#
+ * @param {number} d a decimal32 value.
+ */
+_Data_['putDECIMAL32'] = function(d) {
+    this._check(_pn_data_put_decimal32(this._data, d));
+};
+
+/**
+ * Puts a decimal64 value.
+ * @method putDECIMAL64
+ * @memberof! proton.Data#
+ * @param {number} d a decimal64 value.
+ */
+_Data_['putDECIMAL64'] = function(d) {
+    this._check(_pn_data_put_decimal64(this._data, d));
+};
+
+/**
+ * Puts a decimal128 value.
+ * @method putDECIMAL128
+ * @memberof! proton.Data#
+ * @param {number} d a decimal128 value.
+ */
+_Data_['putDECIMAL128'] = function(d) {
+    this._check(_pn_data_put_decimal128(this._data, d));
+};
+
+/**
+ * Puts a UUID value.
+ * @method putUUID
+ * @memberof! proton.Data#
+ * @param {proton.Data.Uuid} u a uuid value
+ */
+_Data_['putUUID'] = function(u) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_data_put_uuid(this._data, allocate(u['uuid'], 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Puts a binary value consuming the underlying raw data in the process.
+ * @method putBINARY
+ * @memberof! proton.Data#
+ * @param {proton.Data.Binary} b a binary value.
+ */
+_Data_['putBINARY'] = function(b) {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_data_put_binary(data, pn_bytes(b.size, b.start));
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, b.size, b.start);
+
+    // The compiled pn_data_put_binary takes the pn_bytes_t by reference not value.
+    this._check(_pn_data_put_binary(this._data, bytes));
+
+    // After calling _pn_data_put_binary the underlying Data object "owns" the
+    // binary data, so we can call free on the proton.Data.Binary instance to
+    // release any storage it has acquired back to the emscripten heap.
+    b['free']();
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Puts a unicode string value.
+ * @method putSTRING
+ * @memberof! proton.Data#
+ * @param {string} s a unicode string value.
+ */
+_Data_['putSTRING'] = function(s) {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_data_put_string(data, pn_bytes(strlen(text), text));
+
+    // First create an array from the JavaScript String using the intArrayFromString
+    // helper function (from emscripten/src/preamble.js). We use this idiom in a
+    // few places but here we create array as a separate var as we need its length.
+    var array = intArrayFromString(s, true); // The true means don't add NULL.
+    // Allocate temporary storage for the array on the emscripten stack.
+    var str = allocate(array, 'i8', ALLOC_STACK);
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, array.length, str);
+
+    // The compiled pn_data_put_string takes the pn_bytes_t by reference not value.
+    this._check(_pn_data_put_string(this._data, bytes));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Puts a symbolic value. According to the AMQP 1.0 Specification Symbols are
+ * values from a constrained domain. Although the set of possible domains is
+ * open-ended, typically the both number and size of symbols in use for any
+ * given application will be small, e.g. small enough that it is reasonable to
+ * cache all the distinct values. Symbols are encoded as ASCII characters.
+ * @method putSYMBOL
+ * @memberof! proton.Data#
+ * @param {proton.Data.Symbol|string} s the symbol name.
+ */
+_Data_['putSYMBOL'] = function(s) {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_data_put_symbol(data, pn_bytes(strlen(text), text));
+
+    // First create an array from the JavaScript String using the intArrayFromString
+    // helper function (from emscripten/src/preamble.js). We use this idiom in a
+    // few places but here we create array as a separate var as we need its length.
+    var array = intArrayFromString(s, true); // The true means don't add NULL.
+    // Allocate temporary storage for the array on the emscripten stack.
+    var str = allocate(array, 'i8', ALLOC_STACK);
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, array.length, str);
+
+    // The compiled pn_data_put_symbol takes the pn_bytes_t by reference not value.
+    this._check(_pn_data_put_symbol(this._data, bytes));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * If the current node is a list node, return the number of elements,
+ * otherwise return zero. List elements can be accessed by entering
+ * the list.
+ * <pre>
+ *  var count = data.getLISTNODE();
+ *  data.enter();
+ *  for (var i = 0; i < count; i++) {
+ *      var type = data.next();
+ *      if (type === proton.Data.STRING) {
+ *          console.log(data.getSTRING());
+ *      }
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getLISTNODE
+ * @memberof! proton.Data#
+ * @returns {number} the number of elements if the current node is a list,
+ *          zero otherwise.
+ */
+_Data_['getLISTNODE'] = function() {
+    return _pn_data_get_list(this._data);
+};
+
+/**
+ * If the current node is a map, return the number of child elements,
+ * otherwise return zero. Key value pairs can be accessed by entering
+ * the map.
+ * <pre>
+ *  var count = data.getMAPNODE();
+ *  data.enter();
+ *  for (var i = 0; i < count/2; i++) {
+ *      var type = data.next();
+ *      if (type === proton.Data.STRING) {
+ *          console.log(data.getSTRING());
+ *      }
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getMAPNODE
+ * @memberof! proton.Data#
+ * @returns {number} the number of elements if the current node is a list,
+ *          zero otherwise.
+ */
+_Data_['getMAPNODE'] = function() {
+    return _pn_data_get_map(this._data);
+};
+
+/**
+ * If the current node is an array, return an object containing the tuple of the
+ * element count, a boolean indicating whether the array is described, and the
+ * type of each element, otherwise return {count: 0, described: false, type: null).
+ * Array data can be accessed by entering the array.
+ * <pre>
+ *  // Read an array of strings with a symbolic descriptor
+ *  var metadata = data.getARRAYNODE();
+ *  var count = metadata.count;
+ *  data.enter();
+ *  data.next();
+ *  console.log("Descriptor:" + data.getSYMBOL());
+ *  for (var i = 0; i < count; i++) {
+ *      var type = data.next();
+ *      console.log("Element:" + data.getSTRING());
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getARRAYNODE
+ * @memberof! proton.Data#
+ * @returns {object} the tuple of the element count, a boolean indicating whether
+ *          the array is described, and the type of each element.
+ */
+_Data_['getARRAYNODE'] = function() {
+    var count = _pn_data_get_array(this._data);
+    var described = (_pn_data_is_array_described(this._data) > 0);
+    var type = _pn_data_get_array_type(this._data);
+    type = (type == -1) ? null : type;
+    return {'count': count, 'described': described, 'type': type};
+};
+
+/**
+ * Checks if the current node is a described node. The descriptor and value may
+ * be accessed by entering the described node.
+ * <pre>
+ *  // read a symbolically described string
+ *  assert(data.isDESCRIBEDNODE()); // will error if the current node is not described
+ *  data.enter();
+ *  console.log(data.getSYMBOL());
+ *  console.log(data.getSTRING());
+ *  data.exit();
+ * </pre>
+ * @method isDESCRIBEDNODE
+ * @memberof! proton.Data#
+ * @returns {boolean} true iff the current node is a described, false otherwise.
+ */
+_Data_['isDESCRIBEDNODE'] = function() {
+    return _pn_data_is_described(this._data);
+};
+
+/**
+ * @method getNULL
+ * @memberof! proton.Data#
+ * @returns a null value.
+ */
+_Data_['getNULL'] = function() {
+    return null;
+};
+
+/**
+ * Checks if the current node is a null.
+ * @method isNULL
+ * @memberof! proton.Data#
+ * @returns {boolean} true iff the current node is null.
+ */
+_Data_['isNULL'] = function() {
+    return (_pn_data_is_null(this._data) > 0);
+};
+
+/**
+ * @method getBOOL
+ * @memberof! proton.Data#
+ * @returns {boolean} a boolean value if the current node is a boolean, returns
+ *          false otherwise.
+ */
+_Data_['getBOOL'] = function() {
+    return (_pn_data_get_bool(this._data) > 0);
+};
+
+/**
+ * @method getUBYTE
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned byte, returns 0 otherwise.
+ */
+_Data_['getUBYTE'] = function() {
+    return _pn_data_get_ubyte(this._data) & 0xFF; // & 0xFF converts to unsigned;
+};
+
+/**
+ * @method getBYTE
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed byte, returns 0 otherwise.
+ */
+_Data_['getBYTE'] = function() {
+    return _pn_data_get_byte(this._data);
+};
+
+/**
+ * @method getUSHORT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned short, returns 0 otherwise.
+ */
+_Data_['getUSHORT'] = function() {
+    return _pn_data_get_ushort(this._data) & 0xFFFF; // & 0xFFFF converts to unsigned;
+};
+
+/**
+ * @method getSHORT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed short, returns 0 otherwise.
+ */
+_Data_['getSHORT'] = function() {
+    return _pn_data_get_short(this._data);
+};
+
+/**
+ * @method getUINT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned int, returns 0 otherwise.
+ */
+_Data_['getUINT'] = function() {
+    var value = _pn_data_get_uint(this._data);
+    return (value > 0) ? value : 4294967296 + value; // 4294967296 == 2^32
+};
+
+/**
+ * @method getINT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed int, returns 0 otherwise.
+ */
+_Data_['getINT'] = function() {
+    return _pn_data_get_int(this._data);
+};
+
+/**
+ * @method getCHAR
+ * @memberof! proton.Data#
+ * @returns {string} the character represented by the unicode value of the current node.
+ */
+_Data_['getCHAR'] = function() {
+    return String.fromCharCode(_pn_data_get_char(this._data));
+};
+
+/**
+ * Retrieve an unsigned long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method getULONG
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Long} value if the current node is an unsigned long, returns 0 otherwise.
+ */
+_Data_['getULONG'] = function() {
+    var low = _pn_data_get_ulong(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return (long >= 0) ? long : Data.Long.TWO_PWR_64_DBL_ + long;
+};
+
+/**
+ * Retrieve a signed long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method getLONG
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Long} value if the current node is a signed long, returns 0 otherwise.
+ */
+_Data_['getLONG'] = function() {
+    // Getting the long is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low = _pn_data_get_long(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return long;
+};
+
+/**
+ * @method getTIMESTAMP
+ * @memberof! proton.Data#
+ * @returns {Date} a native JavaScript Date instance representing the timestamp.
+ */
+_Data_['getTIMESTAMP'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_data_get_timestamp(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
+};
+
+/**
+ * Retrieves a  float value. N.B. converting between floats and doubles is imprecise
+ * so the resulting value might not quite be what you expect.
+ * @method getFLOAT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a float, returns 0 otherwise.
+ */
+_Data_['getFLOAT'] = function() {
+    return _pn_data_get_float(this._data);
+};
+
+/**
+ * @method getDOUBLE
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a double, returns 0 otherwise.
+ */
+_Data_['getDOUBLE'] = function() {
+    return _pn_data_get_double(this._data);
+};
+
+/**
+ * @method getDECIMAL32
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a decimal32, returns 0 otherwise.
+ */
+_Data_['getDECIMAL32'] = function() {
+console.log("getDECIMAL32 not properly implemented yet");
+    return _pn_data_get_decimal32(this._data);
+};
+
+/**
+ * @method getDECIMAL64
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a decimal64, returns 0 otherwise.
+ */
+_Data_['getDECIMAL64'] = function() {
+console.log("getDECIMAL64 not properly implemented yet");
+    return _pn_data_get_decimal64(this._data);
+};
+
+/**
+ * @method getDECIMAL128
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a decimal128, returns 0 otherwise.
+ */
+_Data_['getDECIMAL128'] = function() {
+console.log("getDECIMAL128 not properly implemented yet");
+    return _pn_data_get_decimal128(this._data);
+};
+
+/**
+ * @method getUUID
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Uuid} value if the current node is a UUID, returns null otherwise.
+ */
+_Data_['getUUID'] = function() {
+    var sp = Runtime.stackSave();
+
+    // Here's the quirky bit, pn_data_get_uuid actually returns pn_uuid_t
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 16 bytes storage for pn_uuid_t on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_uuid.
+    var bytes = allocate(16, 'i8', ALLOC_STACK); // pn_uuid_t is 16 bytes.
+    _pn_data_get_uuid(bytes, this._data);
+
+    // Create a new UUID from the bytes
+    var uuid = new Data['Uuid'](bytes);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return uuid;
+};
+
+/**
+ * @method getBINARY
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise.
+ */
+_Data_['getBINARY'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes bytes = pn_data_get_binary(data);
+
+    // Here's the quirky bit, pn_data_get_binary actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_binary.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_data_get_binary(bytes, this._data);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a proton.Data.Binary from the pn_bytes_t information.
+    var binary = new Data['Binary'](size, start);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    // If _decodeBinaryAsString is set return the stringified form of the Binary.
+    if (this._decodeBinaryAsString) {
+        return binary.toString();
+    } else {
+        return binary;
+    }
+};
+
+/**
+ * Gets a unicode String value from the current node.
+ * @method getSTRING
+ * @memberof! proton.Data#
+ * @returns {string} value if the current node is a String, returns "" otherwise.
+ */
+_Data_['getSTRING'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes bytes = pn_data_get_string(data);
+
+    // Here's the quirky bit, pn_data_get_string actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_string.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_data_get_string(bytes, this._data);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a native JavaScript String from the pn_bytes_t information.
+    var string = Pointer_stringify(start, size);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return string;
+};
+
+/**
+ * Gets a symbolic value. According to the AMQP 1.0 Specification Symbols are
+ * values from a constrained domain. Although the set of possible domains is
+ * open-ended, typically the both number and size of symbols in use for any
+ * given application will be small, e.g. small enough that it is reasonable to
+ * cache all the distinct values. Symbols are encoded as ASCII characters.
+ * @method getSYMBOL
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
+ */
+_Data_['getSYMBOL'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes bytes = pn_data_get_symbol(data);
+
+    // Here's the quirky bit, pn_data_get_symbol actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_symbol.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_data_get_symbol(bytes, this._data);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a native JavaScript String from the pn_bytes_t information.
+    var string = Pointer_stringify(start, size);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return new Data['Symbol'](string);
+};
+
+/**
+ * Performs a deep copy of the current {@link proton.Data} instance and returns it
+ * @method copy
+ * @memberof! proton.Data#
+ * @returns {proton.Data} a copy of the current {@link proton.Data} instance.
+ */
+_Data_['copy'] = function() {
+    var copy = new Data();
+    this._check(_pn_data_copy(copy._data, this._data));
+    return copy;
+};
+
+/**
+ * Format the encoded AMQP Data into a string representation and return it.
+ * @method format
+ * @memberof! proton.Data#
+ * @returns {string} a formatted string representation of the encoded Data.
+ */
+_Data_['format'] = function() {
+    var size = 1024; // Pass by reference variable - need to use setValue to initialise it.
+    while (true) {
+        setValue(size, size, 'i32'); // Set pass by reference variable.
+        var bytes = _malloc(size);   // Allocate storage from emscripten heap.
+        var err = _pn_data_format(this._data, bytes, size);
+        var size = getValue(size, 'i32'); // Dereference the real size value;
+
+        if (err === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else {
+            var string = Pointer_stringify(bytes);
+            _free(bytes);
+            this._check(err)
+            return string;
+        }
+    }
+};
+
+/**
+ * Print the internal state of the {@link proton.Data} in human readable form.
+ * TODO. This seems to "crash" if compound nodes such as DESCRIBED, MAP or LIST
+ * are present in the tree, this is most likely a problem with the underlying C
+ * implementation as all the other navigation and format methods work - need to
+ * check by testing with some native C code.
+ * @method dump
+ * @memberof! proton.Data#
+ */
+_Data_['dump'] = function() {
+    _pn_data_dump(this._data);
+};
+
+/**
+ * Serialise a Native JavaScript Object into an AMQP Map.
+ * @method putMAP
+ * @memberof! proton.Data#
+ * @param {object} object the Native JavaScript Object that we wish to serialise.
+ */
+_Data_['putMAP'] = function(object) {
+    this['putMAPNODE']();
+    this['enter']();
+    for (var key in object) {
+        if (object.hasOwnProperty(key)) {
+            this['putObject'](key);
+            this['putObject'](object[key]);
+        }
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Map into a Native JavaScript Object.
+ * @method getMAP
+ * @memberof! proton.Data#
+ * @returns {object} the deserialised Native JavaScript Object.
+ */
+_Data_['getMAP'] = function() {
+    if (this['enter']()) {
+        var result = {};
+        while (this['next']()) {
+            var key = this['getObject']();
+            var value = null;
+            if (this['next']()) {
+                value = this['getObject']();
+            }
+            result[key] = value;
+        }
+        this['exit']();
+        return result;
+    }
+};
+
+/**
+ * Serialise a Native JavaScript Array into an AMQP List.
+ * @method putLIST
+ * @memberof! proton.Data#
+ * @param {Array} array the Native JavaScript Array that we wish to serialise.
+ */
+_Data_['putLIST'] = function(array) {
+    this['putLISTNODE']();
+    this['enter']();
+    for (var i = 0, len = array.length; i < len; i++) {
+        this['putObject'](array[i]);
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP List into a Native JavaScript Array.
+ * @method getLIST
+ * @memberof! proton.Data#
+ * @returns {Array} the deserialised Native JavaScript Array.
+ */
+_Data_['getLIST'] = function() {
+    if (this['enter']()) {
+        var result = [];
+        while (this['next']()) {
+            result.push(this['getObject']());
+        }
+        this['exit']();
+        return result;
+    }
+};
+
+/**
+ * Serialise a proton.Data.Described into an AMQP Described.
+ * @method putDESCRIBED
+ * @memberof! proton.Data#
+ * @param {proton.Data.Described} d the proton.Data.Described that we wish to serialise.
+ */
+_Data_['putDESCRIBED'] = function(d) {
+    this['putDESCRIBEDNODE']();
+    this['enter']();
+    this['putObject'](d['descriptor']);
+    this['putObject'](d['value']);
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Described into a proton.Data.Described.
+ * @method getDESCRIBED
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Described} the deserialised proton.Data.Described.
+ */
+_Data_['getDESCRIBED'] = function() {
+    if (this['enter']()) {
+        this['next']();
+        var descriptor = this['getObject']();
+        this['next']();
+        var value = this['getObject']();
+        this['exit']();
+        return new Data['Described'](value, descriptor);
+    }
+};
+
+/**
+ * Serialise a proton.Data.Array or JavaScript TypedArray into an AMQP Array.
+ * @method putARRAY
+ * @memberof! proton.Data#
+ * @param {object} a the proton.Data.Array or TypedArray that we wish to serialise.
+ */
+_Data_['putARRAY'] = function(a) {
+    var type = 1;
+    var descriptor = 'TypedArray';
+    var array = a;
+
+    if (a instanceof Data['Array']) { // Array is a proton.Data.Array
+        type = Data[a['type']]; // Find the integer type from its name string.
+        descriptor = a['descriptor'];
+        array = a['elements'];
+    } else { // Array is a Native JavaScript TypedArray so work out the right type.
+        if (a instanceof Int8Array) {
+            type = Data['BYTE'];
+        } else if (a instanceof Uint8Array || a instanceof Uint8ClampedArray) {
+            type = Data['UBYTE'];
+        } else if (a instanceof Int16Array) {
+            type = Data['SHORT'];
+        } else if (a instanceof Uint16Array) {
+            type = Data['USHORT'];
+        } else if (a instanceof Int32Array) {
+            type = Data['INT'];
+        } else if (a instanceof Uint32Array) {
+            type = Data['UINT'];
+        } else if (a instanceof Float32Array) {
+            type = Data['FLOAT'];
+        } else if (a instanceof Float64Array) {
+            type = Data['DOUBLE'];
+        }
+    }
+
+    var described = descriptor != null;
+
+    this['putARRAYNODE'](described, type);
+    this['enter']();
+    if (described) {
+        this['putObject'](descriptor);
+    }
+    var putter = 'put' + Data['TypeNames'][type];
+    for (var i = 0, len = array.length; i < len; i++) {
+        var value = array[i];
+        value = (value instanceof Data.TypedNumber) ? value.value : value;
+        this[putter](value);
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Array into a proton.Data.Array.
+ * @method getARRAY
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Array} the deserialised proton.Data.Array.
+ */
+_Data_['getARRAY'] = function() {
+    var metadata = this['getARRAYNODE']();
+    var count = metadata['count'];
+    var described = metadata['described'];
+    var type = metadata['type'];
+
+    if (type === null) {
+        return null;
+    }
+
+    var elements = null;
+    if (typeof ArrayBuffer === 'function') {
+        if (type === Data['BYTE']) {
+            elements = new Int8Array(count);
+        } else if (type === Data['UBYTE']) {
+            elements = new Uint8Array(count);
+        } else if (type === Data['SHORT']) {
+            elements = new Int16Array(count);
+        } else if (type === Data['USHORT']) {
+            elements = new Uint16Array(count);
+        } else if (type === Data['INT']) {
+            elements = new Int32Array(count);
+        } else if (type === Data['UINT']) {
+            elements = new Uint32Array(count);
+        } else if (type === Data['FLOAT']) {
+            elements = new Float32Array(count);
+        } else if (type === Data['DOUBLE']) {
+            elements = new Float64Array(count);
+        } else {
+            elements = new Array(count);
+        }
+    } else {
+        elements = new Array(count);
+    }
+
+    if (this['enter']()) {
+        var descriptor; // Deliberately initialised as undefined not null.
+        if (described) {
+            this['next']();
+            descriptor = this['getObject']();
+        }
+
+        for (var i = 0; i < count; i++) {
+            this['next']();
+            elements[i] = this['getObject']();
+        }
+
+        this['exit']();
+        if (descriptor === 'TypedArray') {
+            return elements;
+        } else {
+            return new Data['Array'](type, elements, descriptor);
+        }
+    }
+};
+
+/**
+ * This method is the entry point for serialising native JavaScript types into
+ * AMQP types. In an ideal world there would be a nice clean one to one mapping
+ * and we could employ a look-up table but in practice the JavaScript type system
+ * doesn't really lend itself to that and we have to employ extra checks,
+ * heuristics and inferences.
+ * @method putObject
+ * @memberof! proton.Data#
+ * @param {object} obj the JavaScript Object or primitive to be serialised.
+ */
+_Data_['putObject'] = function(obj) {
+//console.log("Data.putObject " + obj);
+
+    if (obj == null) { // == Checks for null and undefined.
+        this['putNULL']();
+    } else if (Data.isString(obj)) {
+        var quoted = obj.match(/(['"])[^'"]*\1/);
+        if (quoted) { // If a quoted string extract the string inside the quotes.
+            obj = quoted[0].slice(1, -1);
+        }
+        this['putSTRING'](obj);
+    } else if (obj instanceof Date) {
+        this['putTIMESTAMP'](obj);
+    } else if (obj instanceof Data['Uuid']) {
+        this['putUUID'](obj);
+    } else if (obj instanceof Data['Binary']) {
+        this['putBINARY'](obj);
+    } else if (obj instanceof Data['Symbol']) {
+        this['putSYMBOL'](obj);
+    } else if (obj instanceof Data['Described']) {
+        this['putDESCRIBED'](obj);
+    } else if (obj instanceof Data['Array']) {
+        this['putARRAY'](obj);
+    } else if (obj.buffer && (typeof ArrayBuffer === 'function') && 
+               obj.buffer instanceof ArrayBuffer) {
+        this['putARRAY'](obj);
+    } else if (obj instanceof Data.TypedNumber) { // Dot notation used for "protected" inner class.
+        // Call the appropriate serialisation method based upon the numerical type.
+        this['put' + obj.type](obj.value);
+    } else if (Data.isNumber(obj)) {
+        /**
+         * This block encodes standard JavaScript numbers by making some inferences.
+         * Encoding JavaScript numbers is surprisingly complex and has several
+         * gotchas. The code here tries to do what the author believes is the
+         * most "intuitive" encoding of the native JavaScript Number. It first
+         * tries to identify if the number is an integer or floating point type
+         * by checking if the number modulo 1 is zero (i.e. if it has a remainder
+         * then it's a floating point type, which is encoded here as a double).
+         * If the number is an integer type a test is made to check if it is a
+         * 32 bit Int value. N.B. gotcha - JavaScript automagically coerces floating
+         * point numbers with a zero Fractional Part into an *exact* integer so
+         * numbers like 1.0, 100.0 etc. will be encoded as int or long here,
+         * which is unlikely to be what is wanted. There's no easy "transparent"
+         * way around this. The TypedNumber approach above allows applications
+         * to express more explicitly what is required, for example (1.0).float()
+         * (1).ubyte(), (5).long() etc.
+         */
+        if (obj % 1 === 0) {
+            if (obj === (obj|0)) { // the |0 coerces to a 32 bit value.
+                // 32 bit integer - encode as an INT.
+                this['putINT'](obj);
+            } else { // Longer than 32 bit - encode as a Long.
+                this['putLONG'](obj);
+            }
+        } else { // Floating point type - encode as a Double
+            this['putDOUBLE'](obj);
+        }
+    } else if (Data.isBoolean(obj)) {
+        this['putBOOL'](obj);
+    } else if (Data.isArray(obj)) { // Native JavaScript Array
+        this['putLIST'](obj);
+    } else {
+        this['putMAP'](obj);
+    }
+};
+
+/**
+ * @method getObject
+ * @memberof! proton.Data#
+ * @returns {object} the JavaScript Object or primitive being deserialised.
+ */
+_Data_['getObject'] = function() {
+    var type = Data['TypeNames'][this.type()];
+    type = type ? type : 'NULL';
+    var getter = 'get' + type;
+    return this[getter]();
+};
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/error.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/error.js b/proton-c/bindings/javascript/error.js
new file mode 100644
index 0000000..a1553b0
--- /dev/null
+++ b/proton-c/bindings/javascript/error.js
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                   Status                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Export Status Enum, avoiding minification.
+ * @enum
+ * @alias Status
+ * @memberof proton
+ */
+Module['Status'] = {
+    /** PN_STATUS_UNKNOWN */  'UNKNOWN':  0, // The tracker is unknown.
+    /** PN_STATUS_PENDING */  'PENDING':  1, // The message is in flight.
+                                             // For outgoing messages, use messenger.isBuffered()
+                                             // to see if it has been sent or not.
+    /** PN_STATUS_ACCEPTED */ 'ACCEPTED': 2, // The message was accepted.
+    /** PN_STATUS_REJECTED */ 'REJECTED': 3, // The message was rejected.
+    /** PN_STATUS_RELEASED */ 'RELEASED': 4, // The message was released.
+    /** PN_STATUS_MODIFIED */ 'MODIFIED': 5, // The message was modified.
+    /** PN_STATUS_ABORTED */  'ABORTED':  6, // The message was aborted.
+    /** PN_STATUS_SETTLED */  'SETTLED':  7  // The remote party has settled the message.
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                   Error                                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Export Error Enum, avoiding minification.
+ * @enum
+ * @alias Error
+ * @memberof proton
+ */
+Module['Error'] = {
+    /** PN_EOS */        'EOS':        -1,
+    /** PN_ERR */        'ERR':        -2,
+    /** PN_OVERFLOW */   'OVERFLOW':   -3,
+    /** PN_UNDERFLOW */  'UNDERFLOW':  -4,
+    /** PN_STATE_ERR */  'STATE_ERR':  -5,
+    /** PN_ARG_ERR */    'ARG_ERR':    -6,
+    /** PN_TIMEOUT */    'TIMEOUT':    -7,
+    /** PN_INTR */       'INTR':       -8,
+    /** PN_INPROGRESS */ 'INPROGRESS': -9
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                               MessengerError                              */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.MessengerError instance.
+ * @classdesc This class is a subclass of Error.
+ * @constructor proton.MessengerError
+ * @param {string} message the error message.
+ */
+Module['MessengerError'] = function(message) { // MessengerError constructor.
+    this.name = "MessengerError";
+    this.message = (message || "");
+};
+
+Module['MessengerError'].prototype = new Error();
+Module['MessengerError'].prototype.constructor = Module['MessengerError'];
+
+Module['MessengerError'].prototype.toString = function() {
+    return this.name + ': ' + this.message
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                MessageError                               */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.MessageError instance.
+ * @classdesc This class is a subclass of Error.
+ * @constructor proton.MessageError
+ * @param {string} message the error message.
+ */
+Module['MessageError'] = function(message) { // MessageError constructor.
+    this.name = "MessageError";
+    this.message = (message || "");
+};
+
+Module['MessageError'].prototype = new Error();
+Module['MessageError'].prototype.constructor = Module['MessageError'];
+
+Module['MessageError'].prototype.toString = function() {
+    return this.name + ': ' + this.message
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                  DataError                                */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.DataError instance.
+ * @classdesc This class is a subclass of Error.
+ * @constructor proton.DataError
+ * @param {string} message the error message.
+ */
+Module['DataError'] = function(message) { // DataError constructor.
+    this.name = "DataError";
+    this.message = (message || "");
+};
+
+Module['DataError'].prototype = new Error();
+Module['DataError'].prototype.constructor = Module['DataError'];
+
+Module['DataError'].prototype.toString = function() {
+    return this.name + ': ' + this.message
+};
+


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


[07/51] [abbrv] qpid-proton git commit: Pulling in changes from proton r1590241

Posted by rh...@apache.org.
Pulling in changes from proton r1590241

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1590242 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/33c895ec
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/33c895ec
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/33c895ec

Branch: refs/heads/master
Commit: 33c895ec6a569aa93def2e42fd7b4bcbb5b49250
Parents: aa766d0
Author: fadams <fa...@unknown>
Authored: Sat Apr 26 15:37:34 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sat Apr 26 15:37:34 2014 +0000

----------------------------------------------------------------------
 CMakeLists.txt                                  |  81 +--
 README                                          | 297 ++++----
 examples/CMakeLists.txt                         |  22 +
 examples/ProtonConfig.cmake                     |  23 +
 examples/include/pncompat/misc_funcs.inc        |   2 +-
 examples/messenger/c/CMakeLists.txt             |  24 +-
 examples/messenger/c/recv.c                     |  17 +-
 examples/messenger/c/send.c                     |   7 +-
 examples/messenger/ruby/passive_recv.rb         | 140 ++++
 proton-c/CMakeLists.txt                         | 130 ++--
 proton-c/bindings/CMakeLists.txt                |  27 +
 proton-c/bindings/javascript/binding.js         | 140 ++--
 proton-c/bindings/javascript/drain.js           |   6 +-
 proton-c/bindings/javascript/spout.js           |   2 +
 proton-c/bindings/perl/CMakeLists.txt           |  57 +-
 proton-c/bindings/perl/perl.i                   |   4 +-
 proton-c/bindings/php/CMakeLists.txt            |  44 +-
 proton-c/bindings/php/compat.swg                |  50 ++
 proton-c/bindings/php/php.i                     |   3 +
 proton-c/bindings/php/proton.ini.in             |  21 +
 proton-c/bindings/php/proton.php                |   2 +-
 proton-c/bindings/python/CMakeLists.txt         |  35 +-
 proton-c/bindings/python/proton.py              |  16 +-
 proton-c/bindings/ruby/CMakeLists.txt           |  23 +-
 proton-c/bindings/ruby/lib/qpid_proton.rb       |   3 +-
 .../bindings/ruby/lib/qpid_proton/filters.rb    |  67 ++
 .../bindings/ruby/lib/qpid_proton/messenger.rb  |  61 +-
 .../bindings/ruby/lib/qpid_proton/selectable.rb | 126 ++++
 .../ruby/spec/qpid/proton/messenger_spec.rb     |  10 +
 proton-c/include/proton/codec.h                 |   5 -
 proton-c/include/proton/condition.h             |   4 +-
 proton-c/include/proton/connection.h            |   4 +-
 proton-c/include/proton/container.h             |   4 +-
 proton-c/include/proton/delivery.h              |   4 +-
 proton-c/include/proton/disposition.h           |   4 +-
 proton-c/include/proton/event.h                 |  36 +-
 proton-c/include/proton/framing.h               |   4 -
 proton-c/include/proton/io.h                    |   3 -
 proton-c/include/proton/link.h                  |   4 +-
 proton-c/include/proton/message.h               | 684 ++++++++++++++++++-
 proton-c/include/proton/object.h                |   5 -
 proton-c/include/proton/sasl.h                  |   4 +-
 proton-c/include/proton/selectable.h            |   4 +-
 proton-c/include/proton/selector.h              |   4 +-
 proton-c/include/proton/session.h               |   4 +-
 proton-c/include/proton/ssl.h                   |   4 +-
 proton-c/include/proton/terminus.h              |   4 +-
 proton-c/include/proton/transport.h             |   4 +-
 proton-c/include/proton/type_compat.h           |  84 ++-
 proton-c/include/proton/types.h                 |  83 ++-
 proton-c/src/ProtonConfig.cmake.in              |  30 +
 proton-c/src/ProtonConfigVersion.cmake.in       |  30 +
 proton-c/src/engine/engine.c                    |  68 +-
 proton-c/src/engine/event.c                     |  23 +-
 proton-c/src/libqpid-proton.cmake.in            |  29 -
 proton-c/src/messenger/messenger.c              |  15 +-
 proton-c/src/object/object.c                    |  10 +-
 proton-c/src/platform.h                         |   8 +-
 proton-c/src/platform_fmt.h                     |  19 +
 proton-c/src/posix/io.c                         |  18 +-
 proton-c/src/proton.c                           |  21 +-
 proton-c/src/ssl/openssl.c                      |  10 +-
 proton-c/src/tests/CMakeLists.txt               |   6 +-
 proton-c/src/tests/parse-url.c                  |  22 +-
 proton-c/src/transport/transport.c              |  21 +-
 proton-c/src/util.c                             |  54 +-
 proton-j/CMakeLists.txt                         |   4 +
 .../org/apache/qpid/proton/engine/Event.java    |  34 +-
 .../qpid/proton/engine/impl/ConnectionImpl.java |  12 +-
 .../qpid/proton/engine/impl/EndpointImpl.java   |   4 +
 .../qpid/proton/engine/impl/EventImpl.java      |   5 +
 .../qpid/proton/engine/impl/FrameParser.java    |   2 +-
 .../qpid/proton/engine/impl/LinkImpl.java       |   9 +
 .../qpid/proton/engine/impl/SenderImpl.java     |   1 -
 .../qpid/proton/engine/impl/SessionImpl.java    |   9 +
 .../qpid/proton/engine/impl/TransportImpl.java  |  51 +-
 .../qpid/proton/message/impl/MessageImpl.java   |  26 +-
 .../qpid/proton/messenger/impl/Address.java     |  24 +-
 proton-j/src/main/resources/cengine.py          |  20 +-
 .../qpid/proton/messenger/impl/AddressTest.java |  15 +-
 tests/python/proton_tests/common.py             |   8 +
 tests/python/proton_tests/engine.py             |  30 +-
 tests/python/proton_tests/soak.py               |  26 +-
 tests/python/proton_tests/ssl.py                |   7 +-
 tools/cmake/Modules/FindJava.cmake              |   2 +-
 85 files changed, 2338 insertions(+), 731 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c8d0b03..a503467 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,26 +69,31 @@ set (SYSCONF_INSTALL_DIR etc CACHE PATH "System read only configuration director
 set (SHARE_INSTALL_DIR share CACHE PATH "Shared read only data directory")
 set (MAN_INSTALL_DIR share/man CACHE PATH "Manpage directory")
 
+mark_as_advanced (INCLUDE_INSTALL_DIR LIB_INSTALL_DIR SYSCONF_INSTALL_DIR SHARE_INSTALL_DIR MAN_INSTALL_DIR)
+
 ## LANGUAGE BINDINGS
-#  If ASK_$LANG is 1 then the language is queried for the directory into which
-#  those language bindings are to be installed. If it is 0 then the bindings
-#  are installed to $CMAKE_INSTALL_PREFIX/bindings/$LANG
-#
-set (BINDINGS_DIR bindings CACHE PATH "Default directory for language bindings")
-set (ASK_PERL 0 CACHE INTEGER "Ask Perl for install directories")
-set (ASK_PHP 0 CACHE INTEGER "Ask PHP for install directories")
-set (ASK_PYTHON 0 CACHE INTEGER "Ask Python for install directories")
-set (ASK_RUBY 0 CACHE INTEGER "Ask Ruby for install directories")
-set (ASK_ALL 0 CACHE INTEGER "If 1 then ask all languages for their directory")
-
-if (ASK_ALL)
-  set (ASK_PERL 1)
-  set (ASK_PHP 1)
-  set (ASK_PYTHON 1)
-  set (ASK_RUBY 1)
-endif (ASK_ALL)
-
-message(STATUS "PYTHON_ARCHLIB_DIR=${PYTHON_ARCHLIB_DIR}")
+
+# Default directory for language bindings not being installed into
+# system specified locations.
+set (BINDINGS_DIR ${LIB_INSTALL_DIR}/proton/bindings)
+
+set (SYSINSTALL_BINDINGS "*UNSPECIFIED*" CACHE BOOL "If SYSINSTALL_BINDINGS is OFF then proton bindings will be installed underneath ${BINDINGS_DIR} and each user will need to modify their interpreter configuration to load the appropriate binding. If SYSINSTALL_BINDINGS is ON, then each language interpreter will be queried for the appropriate directory and proton bindings will be installed and available system wide with no additional per user configuration.")
+
+if (SYSINSTALL_BINDINGS STREQUAL "*UNSPECIFIED*")
+  message(WARNING "SYSINSTALL_BINDINGS is unspecified, defaulting it to OFF. Please note that the default install behaviour of proton has changed. Proton bindings by default will now be installed under ${BINDINGS_DIR} and will no longer be found by system interpreters. This means that every user will be required to manually configure their interpreters to locate the proton bindings. If you wish proton bindings to be installed into the interpreter specified locations as was the default in prior releases, please specify -DSYSINSTALL_BINDINGS=ON")
+  set (SYSINSTALL_BINDINGS OFF)
+endif ()
+
+set (BINDING_LANGS PERL PHP PYTHON RUBY)
+
+foreach (LANG ${BINDING_LANGS})
+  set (SYSINSTALL_${LANG} OFF CACHE BOOL "Install ${LANG} bindings into interpreter specified location.")
+  if (SYSINSTALL_BINDINGS OR SYSINSTALL_${LANG})
+    set (CHECK_SYSINSTALL_${LANG} ON)
+  else ()
+    set (CHECK_SYSINSTALL_${LANG} OFF)
+  endif ()
+endforeach()
 
 if (WIN32)
   set (EXAMPLES_INSTALL_DIR proton/examples)
@@ -98,32 +103,29 @@ if (UNIX)
   set (EXAMPLES_INSTALL_DIR ${SHARE_INSTALL_DIR}/proton/examples)
 endif (UNIX)
 
-set (JAVA_INSTALL_DIR ${SHARE_INSTALL_DIR}/java CACHE PATH "Installation directory for all JARs except those using JNI")
-set (JNI_INSTALL_DIR ${LIB_INSTALL_DIR}/java CACHE PATH "Installation directory for all JARs utilising JNI")
-set (JNI_SHARED_LIB_INSTALL_DIR ${LIB_INSTALL_DIR} CACHE PATH "Installation directory for shared objects used by JNI JARs")
-
 set (PROTON_SHARE ${SHARE_INSTALL_DIR}/proton-${PN_VERSION})
 # End of variables used during install
 
-set (PROTON_JAR_DEPEND_DIR /usr/share/java/ CACHE PATH
-      "When locating compile-time dependencies, the build system searches this location in addition to the default ones provided by find_jar")
-
 # Pull in local cmake modules
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/tools/cmake/Modules/")
 
-set (java_default ON)
-option(GEN_JAVA "Include java-related artifacts" ${java_default})
-if (GEN_JAVA)
-  find_package( Java )
+if (NOBUILD_JAVA)
+  set (DEFAULT_JAVA OFF)
+else()
+  find_package(Java)
   if (JAVA_FOUND)
-    message(STATUS "Java version: ${Java_VERSION}. javac is at: ${Java_JAVAC_EXECUTABLE}")
-    include(UseJava)
-    include(ProtonUseJava)
-
-    add_subdirectory(proton-j)
+    set (DEFAULT_JAVA ON)
+  else()
+    set (DEFAULT_JAVA OFF)
   endif()
 endif()
 
+option (BUILD_JAVA "Build proton-j." ${DEFAULT_JAVA})
+
+if (BUILD_JAVA)
+  add_subdirectory(proton-j)
+endif()
+
 add_subdirectory(proton-c)
 
 install (FILES LICENSE README TODO
@@ -143,9 +145,10 @@ install (FILES examples/include/pncompat/internal/LICENSE
          DESTINATION ${EXAMPLES_INSTALL_DIR}/messenger/pncompat)
 
 # add relevant CTest support
-find_program (MAVEN_EXECUTABLE mvn DOC "Location of the maven program")
-if (JAVA_FOUND AND MAVEN_EXECUTABLE)
+find_program (MAVEN_EXE mvn DOC "Location of the maven program")
+mark_as_advanced (MAVEN_EXE)
+if (JAVA_FOUND AND MAVEN_EXE)
   add_test (proton-java mvn test --file ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml)
-else (JAVA_FOUND AND MAVEN_EXECUTABLE)
+else (JAVA_FOUND AND MAVEN_EXE)
   message (STATUS "Cannot find both Java and Maven: testing disabled for Proton-J")
-endif (JAVA_FOUND AND MAVEN_EXECUTABLE)
+endif (JAVA_FOUND AND MAVEN_EXE)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/README
----------------------------------------------------------------------
diff --git a/README b/README
index eca7f08..72f824f 100644
--- a/README
+++ b/README
@@ -1,3 +1,6 @@
+Proton Project
+==============
+
 Proton is a library for speaking AMQP, including:
 
   + The AMQP Messenger API, a simple but powerful interface to send and receive
@@ -17,171 +20,204 @@ Proton is designed to scale up and down:
 
 Proton is multi-lingual:
 
-  + Proton-C - a C implementation with lanuage bindings in Python, Php, Perl,
-    Ruby, and Java (via JNI).
+  + Proton-C - a C implementation with language bindings in Python,
+               Php, Perl, and Ruby
   + Proton-J - a pure Java implementation
 
 Please see http://qpid.apache.org/proton for a more info.
 
-==== Build Instructions ====
-
-Proton has two separate build systems reflecting the nature of its
-two implementations.
+Build Instructions
+==================
 
-   + Proton-C and the language bindings use CMake.
-   + Proton-J uses Maven.
+Proton comes with two separate build systems. The CMake build system
+builds the entire codebase including the C implementation, all the
+bindings of the C implementation, and the pure Java implementation.
 
-The two build systems are independent of one and other, that is, Proton-C
-may be built independently of Proton-J, and vice-versa.
+The maven build system builds only the Java portions of the code.
+Developers wishing to work across multiple languages should become
+familiar with the cmake build system as this will build and run all
+available tests and code whereas the maven build system only runs Java
+tests.
 
-=== Proton-C ===
+CMake (Linux)
+-------------
 
-== Build Instructions (Linux) ==
+The following prerequisites are required to do a full build. If you do
+not wish to build a given language binding you can omit the devel
+package for that language:
 
-The following prerequesuites are required to do a full build. If you do not
-wish to build a given language binding you can omit the package for that
-language:
+    # required dependencies
+    yum install gcc cmake libuuid-devel
 
-  # required dependencies
-  yum install gcc cmake libuuid-devel
+    # dependencies needed for ssl support
+    yum install openssl-devel
 
-  # dependencies needed for ssl support
-  yum install openssl-devel
+    # dependencies needed for bindings
+    yum install swig python-devel ruby-devel php-devel perl-devel
 
-  # dependencies needed for bindings
-  yum install swig python-devel ruby-devel php-devel perl-devel \
-              java-1.6.0-openjdk
+    # dependencies needed for java (note that any non-ancient jvm will
+    # work, 1.8.0 is just what is current for fedora 20)
+    yum install java-1.8.0-openjdk-devel
 
-  # dependencies needed for python docs
-  yum install epydoc
+    # dependencies needed for python docs
+    yum install epydoc
 
 From the directory where you found this README file:
 
-  mkdir build
-  cd build
-
-  # Set the install prefix. You may need to adjust depending on your
-  # system.
-  cmake -DCMAKE_INSTALL_PREFIX=/usr ..
+    mkdir build
+    cd build
 
-  # Omit the docs target if you do not wish to build or install
-  # documentation.
-  make all docs
+    # Set the install prefix. You may need to adjust depending on your
+    # system.
+    cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DSYSINSTALL_BINDINGS=ON
 
-  # Note that this step will require root privileges.
-  make install
+    # Omit the docs target if you do not wish to build or install
+    # documentation.
+    make all docs
 
-Note that all installed files are stored in the install_manifest.txt
-file.
+    # Note that this step will require root privileges.
+    make install
 
-NOTE: The CMAKE_INSTALL_PREFIX does not affect the location for where the language
-bindings (Ruby, Perl, PHP, Ruby) are installed. For those elements, the location is
-determined by the language itself; i.e., each one is interrogated for the proper
-location for extensions.
+When make install completes, all installed files are listed in the
+install_manifest.txt file. The contents of this file may be used to
+uninstall.
 
-NOTE: If you want to constrain where the Proton code is installed, you have to use
-the DESTDIR argument to make:
+Note: When SYSINSTALL_BINDINGS is enabled (ON), the
+CMAKE_INSTALL_PREFIX does not affect the location for where the
+language bindings (Python, Perl, PHP, Ruby) are installed. For those
+elements, the location is determined by the language interpreter
+itself; i.e., each interpreter is queried for the proper location for
+extensions. If you want to constrain where the Proton code is
+installed, set SYSINSTALL_BINDINGS to OFF. This will install all
+bindings to a common location under ${CMAKE_INSTALL_PREFIX}. When
+installed like this, each user will need to manually configure their
+interpreters with the respective binding location.
 
-  make install DESTDIR=[location]
+Installing Language Bindings
+----------------------------
 
-This will install all components (including the language bindings) in locations
-relative to the specified location. So, for example, if the Perl language bindings
-would normally install to /usr/lib/perl5/vendor_perl/ then, if you use:
+Most dynamic languages provide a way for asking where to install
+libraries in order to place them in a default search path.
 
-  make install DESTDIR=/opt
+When SYSINSTALL_BINDINGS is disabled (OFF), Proton installs all
+dynamic language bindings into a central, default location:
 
-the bindings would install to /opt/usr/lib/perl5/vendor_perl/ instead.
+    BINDINGS=${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/proton/bindings
 
-NOTE: The paths in libqpid-proton.pc are not updated if, when installing, DESTDIR
-is used. The contents of that file are based on the values provided when the
-CMake environment was created.
+In order to use these bindings, you'll need to configure your
+interpreter to load the bindings from the appropriate directory:
 
-For more on the use of DESTDIR, see the following:
+ * Perl   - Add ${BINDINGS}/perl to PERL5LIB
+ * PHP    - Set the PHPRC environment variable to point to
+            ${BINDINGS}/php/proton.ini
+ * Python - Add ${BINDINGS}/python to PYTHONPATH
+ * Ruby   - Add ${BINDINGS}/ruby to RUBYLIB
 
-http://www.gnu.org/prep/standards/html_node/DESTDIR.html
+You can configure the build to install a specific binding to the
+location specified by the system interpreter with the
+SYSINSTALL_[LANGUAGE] options, where [LANGUAGE] is one of JAVA, PERL,
+PHP, PYTHON, or RUBY.:
 
-== Disable Building The Language Bindings ==
+    cmake .. -DSYSINSTALL_PHP=ON
 
-To disable any language bindings, you can disable them individually with:
+Disabling Language Bindings
+---------------------------
 
-  cmake -DBUILD_[LANGUAGE]=OFF .
+To disable any given language bindings, you can use the
+BUILD_[LANGUAGE] option where [LANGUAGE] is one of JAVA, PERL, PHP,
+PYTHON or RUBY, e.g.:
 
-where [LANGUAGE] is one of JAVA, PERL, PHP, PYTHON or RUBY. To disable building all
-language bindings then include a separate argument for each.
+    cmake .. -DBUILD_PHP=OFF
 
-== Build Instructions (Windows) ==
+CMake (Windows)
+---------------
 
-This describes how to build the Proton library on Windows using Microsoft
-Visual C++.
+This describes how to build the Proton library on Windows using
+Microsoft Visual C++.
 
-The Proton build uses the cmake tool to generate the Visual Studio project
-files.  These project files can then be loaded into Visual Studio and used to
-build the Proton library.
+The Proton build uses the cmake tool to generate the Visual Studio
+project files. These project files can then be loaded into Visual
+Studio and used to build the Proton library.
 
-These instructions assume use of a command shell.  If you use the Visual
-Studio supplied Command Prompt, cmake is even more likely to guess the
-intended compiler.
+These instructions assume use of a command shell. If you use the
+Visual Studio supplied Command Prompt, cmake is even more likely to
+guess the intended compiler.
 
 The following packages must be installed:
 
-    Visual Studio 2005 or newer (regular or C++ Express)
-    Python (www.python.org)
-    Cmake (www.cmake.org)
+  - Visual Studio 2005 or newer (regular or C++ Express)
+  - Python (www.python.org)
+  - Cmake (www.cmake.org)
+
+The following packages are optionally required in order to run the
+python or java driven test suites:
+
+  - swig (www.swig.org)
 
-Optional: to run the python or java driven test suites
+Notes:
 
-    swig (www.swig.org)
+  - be sure to install relevant Microsoft Service Packs and updates
+  - python.exe _must_ be in your path
+  - cmake.exe _must_ be in your path
+  - swig.exe optional (but should be in your path for building test
+    modules)
 
-    Notes:
-        - Be sure to install relevant Microsoft Service Packs and updates
-        - python.exe _must_ be in your path
-        - cmake.exe _must_ be in your path
-        - swig.exe optional (but should be in your path for building test modules)
+### Step 1:
 
+Create a 'build' directory - this must be at the same level as the
+'proton-c' directory. For example, from the directory where you found
+this README file:
 
-Step 1: Create a 'build' directory - this must be at the same level as the
-        'proton-c' directory.  Example:
+    > mkdir build
 
-     From the directory where you found this README file:
-     > mkdir build
+### Step 2:
 
-Step 2: cd into the build directory
+  cd into the build directory
 
-     > cd build
+    > cd build
 
-Step 3: Generate the Visual Studio project files using cmake.  The command contains
+### Step 3:
 
-        1) the name of the compiler you are using (if cmake guesses wrongly)
-        2) the path (required) to the _directory_ that contains the top level
-           "CMakeLists.txt" file (the parent directory, in this case).
-     Example:
+Generate the Visual Studio project files using cmake. The command
+contains:
 
-     > cmake ..
+  1. the name of the compiler you are using (if cmake guesses wrongly)
+  2. the path (required) to the _directory_ that contains the top
+     level "CMakeLists.txt" file (the parent directory, in this case).
 
-     If cmake doesn't guess things correctly, useful additional arguments are:
+  Example:
 
-        -G "Visual Studio 10"
-        -DSWIG_EXECUTABLE=C:\swigwin-2.0.7\swig.exe
+    > cmake ..
 
-     Refer to the cmake documentation for more information.
+  If cmake doesn't guess things correctly, useful additional arguments
+  are:
 
-Step 4: Load the ALL_BUILD project into Visual Studio
+    -G "Visual Studio 10"
+    -DSWIG_EXECUTABLE=C:\swigwin-2.0.7\swig.exe
 
-     4a: Run the Microsoft Visual Studio IDE
-     4b: From within the IDE, open the ALL_BUILD project file or proton solution
-         file - it should be in the 'build' directory you created above.
-     4c: select the appropriate configuration.  RelWithDebInfo works best with
-         the included CMake/CTest scripts
+  Refer to the cmake documentation for more information.
 
-Step 5: Build the ALL_BUILD project.
+### Step 4:
 
-Note that if you wish to build debug version of proton for use with swig
-bindings on Windows, you must have the appropriate debug target libraries to
-link against.
+Load the ALL_BUILD project into Visual Studio
 
-=== Proton-J ===
+  a. Run the Microsoft Visual Studio IDE
+  b. From within the IDE, open the ALL_BUILD project file or proton
+     solution file - it should be in the 'build' directory you created
+     above.
+  c. select the appropriate configuration. RelWithDebInfo works best
+     with the included CMake/CTest scripts
 
-== Build Instructions (All platforms) ==
+### Step 5:
+
+Build the ALL_BUILD project.
+
+Note that if you wish to build debug version of proton for use with
+swig bindings on Windows, you must have the appropriate debug target
+libraries to link against.
+
+Maven (All platforms)
+---------------------
 
 The following prerequesuites are required to do a full build.
 
@@ -189,42 +225,35 @@ The following prerequesuites are required to do a full build.
 
 From the directory where you found this README file:
 
-  # To compile and package all Java modules (omitting the tests)
-  mvn -DskipTests package
-
-  # To install the packages in the local Maven repository (usually ~/.m2/repo)
-  mvn -DskipTests install
-
-=== Testing ===
+    # To compile and package all Java modules (omitting the tests)
+    mvn -DskipTests package
 
-To test Proton, run the system tests (located in the tests subdirectory).
-The system tests are applicable to both the Proton-C and Proton-J
-implementations.
+    # To install the packages in the local Maven repository (usually ~/.m2/repo)
+    mvn -DskipTests install
 
-== Test Instructions (Proton-C only) ==
+Testing
+=======
 
-To run the system tests against Proton-C, from your build directory above:
+Additional packages required for testing:
 
-   # to run all the tests, summary mode
-   ctest
+    yum install rubygem-minitest rubygem-rspec rubygem-simplecov
 
-   # to run a single test, full output
-   ctest -V -R proton-c
+On non-RPM based systems, you can install them using:
 
-== Test Instructions (Proton-J and Proton-C) ==
+    gem install minitest rspec simplecov
 
-To run the system tests, execute Maven specifying profile 'proton-j' to
-test Proton-J, and 'proton-jni' to test the Proton-C implementation via the
-JNI bindings.  (To test Proton-C via the JNI Bindings the JNI Binding must have
-been built with Cmake as described above).
+To test Proton, use the cmake build and run 'make test'. Note that
+this will invoke the maven tests as well, so the maven prerequisites
+are required in addition to the cmake prerequisites.
 
-  # To test Proton-J
-  mvn test -P proton-j
+Running Tests
+-------------
 
-  # To test Proton-C via the JNI Bindings
-  mvn test -P proton-jni
+To run the system tests using the CMake build system, cd into your
+build directory and use the following commands:
 
-  # To produce a nicely formated report containing the test results
-  # (in tests/target/site/surefire-report.html)
-  mvn surefire-report:report
+    # to run all the tests, summary mode
+    ctest
 
+    # to run a single test, full output
+    ctest -V -R proton-c

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..4f7f948
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+set (Proton_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+add_subdirectory(messenger/c)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/examples/ProtonConfig.cmake
----------------------------------------------------------------------
diff --git a/examples/ProtonConfig.cmake b/examples/ProtonConfig.cmake
new file mode 100644
index 0000000..0269c77
--- /dev/null
+++ b/examples/ProtonConfig.cmake
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+set (Proton_VERSION       ${PN_VERSION})
+set (Proton_INCLUDE_DIRS  ${CMAKE_SOURCE_DIR}/proton-c/include)
+set (Proton_LIBRARIES     qpid-proton)
+set (Proton_FOUND True)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/examples/include/pncompat/misc_funcs.inc
----------------------------------------------------------------------
diff --git a/examples/include/pncompat/misc_funcs.inc b/examples/include/pncompat/misc_funcs.inc
index 921d1d3..166cc97 100644
--- a/examples/include/pncompat/misc_funcs.inc
+++ b/examples/include/pncompat/misc_funcs.inc
@@ -47,8 +47,8 @@
 pn_timestamp_t time_now(void)
 {
   FILETIME now;
-  GetSystemTimeAsFileTime(&now);
   ULARGE_INTEGER t;
+  GetSystemTimeAsFileTime(&now);
   t.u.HighPart = now.dwHighDateTime;
   t.u.LowPart = now.dwLowDateTime;
   // Convert to milliseconds and adjust base epoch

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/examples/messenger/c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/messenger/c/CMakeLists.txt b/examples/messenger/c/CMakeLists.txt
index 5d03c79..4f40924 100644
--- a/examples/messenger/c/CMakeLists.txt
+++ b/examples/messenger/c/CMakeLists.txt
@@ -17,28 +17,12 @@
 # under the License.
 #
 
-cmake_minimum_required (VERSION 2.6)
-
-find_path(PROTON_INCLUDE_DIR proton/types.h)
-find_library(PROTON_LIBRARY
-             NAMES qpid-proton)
+find_package(Proton REQUIRED)
 
 add_executable(recv recv.c)
 add_executable(send send.c)
-add_executable(recv-async recv-async.c)
-add_executable(send-async send-async.c)
-
-target_link_libraries(recv qpid-proton)
-target_link_libraries(send qpid-proton)
-target_link_libraries(recv-async qpid-proton)
-target_link_libraries(send-async qpid-proton)
 
-set_target_properties (
-  recv send recv-async send-async
-  PROPERTIES
-  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS}"
-)
+include_directories(${Proton_INCLUDE_DIRS})
 
-if (BUILD_WITH_CXX)
-  set_source_files_properties (recv.c send.c recv-async.c send-async.c PROPERTIES LANGUAGE CXX)
-endif (BUILD_WITH_CXX)
+target_link_libraries(recv ${Proton_LIBRARIES})
+target_link_libraries(send ${Proton_LIBRARIES})

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/examples/messenger/c/recv.c
----------------------------------------------------------------------
diff --git a/examples/messenger/c/recv.c b/examples/messenger/c/recv.c
index f3d84c2..16e8321 100644
--- a/examples/messenger/c/recv.c
+++ b/examples/messenger/c/recv.c
@@ -57,6 +57,13 @@ int main(int argc, char** argv)
   char* password = NULL;
   char* address = (char *) "amqp://~0.0.0.0";
   int c;
+
+  pn_message_t * message;
+  pn_messenger_t * messenger;
+
+  message = pn_message();
+  messenger = pn_messenger(NULL);
+
   opterr = 0;
 
   while((c = getopt(argc, argv, "hc:k:p:")) != -1)
@@ -97,12 +104,6 @@ int main(int argc, char** argv)
     address = argv[optind];
   }
 
-  pn_message_t * message;
-  pn_messenger_t * messenger;
-
-  message = pn_message();
-  messenger = pn_messenger(NULL);
-
   /* load the various command line options if they're set */
   if(certificate)
   {
@@ -135,15 +136,17 @@ int main(int argc, char** argv)
       pn_messenger_get(messenger, message);
       check(messenger);
 
+      {
       char buffer[1024];
       size_t buffsize = sizeof(buffer);
+      const char* subject = pn_message_get_subject(message);
       pn_data_t *body = pn_message_body(message);
       pn_data_format(body, buffer, &buffsize);
 
       printf("Address: %s\n", pn_message_get_address(message));
-      const char* subject = pn_message_get_subject(message);
       printf("Subject: %s\n", subject ? subject : "(no subject)");
       printf("Content: %s\n", buffer);
+      }
     }
   }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/examples/messenger/c/send.c
----------------------------------------------------------------------
diff --git a/examples/messenger/c/send.c b/examples/messenger/c/send.c
index d8460bc..11b47ff 100644
--- a/examples/messenger/c/send.c
+++ b/examples/messenger/c/send.c
@@ -52,9 +52,9 @@ void usage(void)
 int main(int argc, char** argv)
 {
   int c;
-  opterr = 0;
   char * address = (char *) "amqp://0.0.0.0";
   char * msgtext = (char *) "Hello World!";
+  opterr = 0;
 
   while((c = getopt(argc, argv, "ha:b:c:")) != -1)
   {
@@ -84,8 +84,10 @@ int main(int argc, char** argv)
 
   if (optind < argc) msgtext = argv[optind];
 
+  {
   pn_message_t * message;
   pn_messenger_t * messenger;
+  pn_data_t * body;
 
   message = pn_message();
   messenger = pn_messenger(NULL);
@@ -93,7 +95,7 @@ int main(int argc, char** argv)
   pn_messenger_start(messenger);
 
   pn_message_set_address(message, address);
-  pn_data_t *body = pn_message_body(message);
+  body = pn_message_body(message);
   pn_data_put_string(body, pn_bytes(strlen(msgtext), msgtext));
   pn_messenger_put(messenger, message);
   check(messenger);
@@ -103,6 +105,7 @@ int main(int argc, char** argv)
   pn_messenger_stop(messenger);
   pn_messenger_free(messenger);
   pn_message_free(message);
+  }
 
   return 0;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/examples/messenger/ruby/passive_recv.rb
----------------------------------------------------------------------
diff --git a/examples/messenger/ruby/passive_recv.rb b/examples/messenger/ruby/passive_recv.rb
new file mode 100644
index 0000000..a3625ac
--- /dev/null
+++ b/examples/messenger/ruby/passive_recv.rb
@@ -0,0 +1,140 @@
+#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+require 'qpid_proton'
+require 'optparse'
+
+addresses = []
+
+OptionParser.new do |opts|
+  opts.banner = "Usage: recv.rb <addr1> ... <addrn>"
+  opts.parse!
+
+  addresses = ARGV
+end
+
+addresses = ["~0.0.0.0"] if addresses.empty?
+
+messenger = Qpid::Proton::Messenger.new
+messenger.passive = true
+
+begin
+  messenger.start
+rescue ProtonError => error
+  puts "ERROR: #{error.message}"
+  puts error.backtrace.join("\n")
+  exit
+end
+
+addresses.each do |address|
+  begin
+    messenger.subscribe(address)
+  rescue Qpid::Proton::ProtonError => error
+    puts "ERROR: #{error.message}"
+    exit
+  end
+end
+
+msg = Qpid::Proton::Message.new
+
+read_array = []
+write_array = []
+selectables = {}
+
+loop do
+
+  # wait for incoming messages
+  sel = messenger.selectable
+  while !sel.nil?
+    if sel.terminal?
+      selectables.delete(sel.fileno)
+      read_array.delete(sel)
+      write_array.delete(sel)
+      sel.free
+    else
+      sel.capacity
+      sel.pending
+      if !sel.registered?
+        read_array << sel
+        write_array << sel
+        selectables[sel.fileno] = sel
+        sel.registered = true
+      end
+    end
+    sel = messenger.selectable
+  end
+
+  unless selectables.empty?
+    rarray = []; read_array.each {|fd| rarray << fd.to_io }
+    warray = []; write_array.each {|fd| warray << fd.to_io }
+
+    if messenger.deadline > 0.0
+      result = IO.select(rarray, warray, nil, messenger.deadline)
+    else
+      result = IO.select(rarray, warray)
+    end
+
+    unless result.nil? && result.empty?
+      result.flatten.each do |io|
+        sel = selectables[io.fileno]
+
+        sel.writable if sel.pending > 0
+        sel.readable if sel.capacity > 0
+      end
+    end
+
+    begin
+      messenger.receive(10)
+    rescue Qpid::Proton::ProtonError => error
+      puts "ERROR: #{error.message}"
+      exit
+    end
+
+    while messenger.incoming.nonzero?
+      begin
+        messenger.get(msg)
+      rescue Qpid::Proton::Error => error
+        puts "ERROR: #{error.message}"
+        exit
+      end
+
+      puts "Address: #{msg.address}"
+      subject = msg.subject || "(no subject)"
+      puts "Subject: #{subject}"
+      puts "Body: #{msg.body}"
+      puts "Properties: #{msg.properties}"
+      puts "Instructions: #{msg.instructions}"
+      puts "Annotations: #{msg.annotations}"
+
+      if msg.reply_to
+        puts "=== Sending a reply to #{msg.reply_to}"
+        reply = Qpid::Proton::Message.new
+        reply.address = msg.reply_to
+        reply.subject = "RE: #{msg.subject}"
+        reply.content = "Thanks for the message!"
+
+        messenger.put(reply)
+        messenger.send
+      end
+    end
+  end
+end
+
+messenger.stop
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index f70e9c4..76b082b 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -51,6 +51,7 @@ if (OPENSSL_FOUND)
   set(ssl_impl openssl)
 endif(OPENSSL_FOUND)
 set(SSL_IMPL ${ssl_impl} CACHE STRING "Library to use for SSL/TLS support. Valid values: 'none','openssl'")
+mark_as_advanced (SSL_IMPL)
 
 configure_file (
   "${CMAKE_CURRENT_SOURCE_DIR}/include/proton/version.h.in"
@@ -222,6 +223,17 @@ if (MSVC)
 	set(CMAKE_DEBUG_POSTFIX "d")
 endif (MSVC)
 
+macro (pn_absolute_install_dir NAME VALUE PREFIX)
+  if(IS_ABSOLUTE ${VALUE})
+    set(${NAME} "${VALUE}")
+  elseif(IS_ABSOLUTE ${PREFIX})
+    set(${NAME} "${PREFIX}/${VALUE}")
+  else()
+    set(${NAME} "${CMAKE_BINARY_DIR}/${PREFIX}/${VALUE}")
+  endif(IS_ABSOLUTE ${VALUE})
+  get_filename_component(${NAME} ${${NAME}} ABSOLUTE)
+endmacro()
+
 find_package(SWIG)
 if (SWIG_FOUND)
   add_subdirectory(bindings)
@@ -242,7 +254,6 @@ endif (BUILD_JAVASCRIPT)
 
 add_subdirectory(docs/api)
 add_subdirectory(docs/man)
-add_subdirectory(../examples/messenger/c examples/messenger/c)
 add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c)
 
 set (qpid-proton-platform
@@ -349,12 +360,12 @@ pn_c_files (${qpid-proton-core} ${qpid-proton-platform} src/proton.c src/proton-
 # Install executables and libraries
 install (TARGETS proton proton-dump
   RUNTIME DESTINATION bin
-  ARCHIVE DESTINATION bin
+  ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
   LIBRARY DESTINATION ${LIB_INSTALL_DIR})
 install (TARGETS qpid-proton
   EXPORT  proton
   RUNTIME DESTINATION bin
-  ARCHIVE DESTINATION bin
+  ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
   LIBRARY DESTINATION ${LIB_INSTALL_DIR})
 
 # Install header files
@@ -363,24 +374,12 @@ install (FILES ${headers} DESTINATION ${INCLUDE_INSTALL_DIR}/proton)
 install (FILES  ${CMAKE_CURRENT_BINARY_DIR}/include/proton/version.h
          DESTINATION ${INCLUDE_INSTALL_DIR}/proton)
 
-# Pkg config file
-# make sure the install prefix is absolute
-set(INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
-
-macro (pn_pkgconfig_dir NAME VALUE PREFIX)
-  if(IS_ABSOLUTE ${VALUE})
-    set(${NAME} "${VALUE}")
-  else(IS_ABSOLUTE ${VALUE})
-    set(${NAME} "${PREFIX}/${VALUE}")
-  endif(IS_ABSOLUTE ${VALUE})
-  get_filename_component(${NAME} ${${NAME}} ABSOLUTE)
-endmacro(pn_pkgconfig_dir)
-
-pn_pkgconfig_dir(PREFIX ${INSTALL_PREFIX} ${INSTALL_PREFIX})
-pn_pkgconfig_dir(EXEC_PREFIX ${INSTALL_PREFIX} ${INSTALL_PREFIX})
-pn_pkgconfig_dir(LIBDIR ${LIB_INSTALL_DIR} ${INSTALL_PREFIX})
-pn_pkgconfig_dir(INCLUDEDIR ${INCLUDE_INSTALL_DIR} ${INSTALL_PREFIX})
+pn_absolute_install_dir(PREFIX "." ${CMAKE_INSTALL_PREFIX})
+pn_absolute_install_dir(EXEC_PREFIX "." ${CMAKE_INSTALL_PREFIX})
+pn_absolute_install_dir(LIBDIR ${LIB_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX})
+pn_absolute_install_dir(INCLUDEDIR ${INCLUDE_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX})
 
+# Pkg config file
 configure_file(
   ${CMAKE_CURRENT_SOURCE_DIR}/src/libqpid-proton.pc.in
   ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.pc @ONLY)
@@ -388,23 +387,24 @@ install (FILES
   ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.pc
   DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
 
-configure_file(
-  ${CMAKE_CURRENT_SOURCE_DIR}/src/libqpid-proton.cmake.in
-  ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.cmake @ONLY)
-install (FILES 
-  ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.cmake
-  DESTINATION ${LIB_INSTALL_DIR}/proton.cmake)
-
-install (EXPORT proton 
-  FILE proton-config.cmake 
-  DESTINATION ${LIB_INSTALL_DIR}/proton.cmake)
+if (DEFINED CMAKE_IMPORT_LIBRARY_PREFIX)
+set(PROTONLIB ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton${CMAKE_IMPORT_LIBRARY_SUFFIX})
+set(PROTONLIBDEBUG ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton${CMAKE_DEBUG_POSTFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX})
+else ()
+set(PROTONLIB ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton${CMAKE_SHARED_LIBRARY_SUFFIX})
+set(PROTONLIBDEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton${CMAKE_DEBUG_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
+endif ()
 
-file(WRITE 
-  ${CMAKE_CURRENT_BINARY_DIR}/proton.cmake/proton-config-version.cmake
-  "set(PACKAGE_VERSION ${PN_VERSION})\n")
-install (FILES 
-  ${CMAKE_CURRENT_BINARY_DIR}/proton.cmake/proton-config-version.cmake
-  DESTINATION ${LIB_INSTALL_DIR}/proton.cmake)
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/src/ProtonConfig.cmake.in
+  ${CMAKE_CURRENT_BINARY_DIR}/ProtonConfig.cmake @ONLY)
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/src/ProtonConfigVersion.cmake.in
+  ${CMAKE_CURRENT_BINARY_DIR}/ProtonConfigVersion.cmake @ONLY)
+install (FILES
+  ${CMAKE_CURRENT_BINARY_DIR}/ProtonConfig.cmake
+  ${CMAKE_CURRENT_BINARY_DIR}/ProtonConfigVersion.cmake
+  DESTINATION ${LIB_INSTALL_DIR}/cmake/Proton)
 
 # CTest
 
@@ -441,16 +441,18 @@ endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
 
 set (env_py "${CMAKE_CURRENT_SOURCE_DIR}/env.py" )
 
-find_program(VALGRIND valgrind DOC "Location of the valgrind program")
+find_program(VALGRIND_EXE valgrind DOC "Location of the valgrind program")
 option(ENABLE_VALGRIND "Use valgrind to detect run-time problems" ON)
 if (ENABLE_VALGRIND)
-  if (VALGRIND STREQUAL VALGRIND-NOTFOUND)
+  if (NOT VALGRIND_EXE)
     message(STATUS "Can't locate the valgrind command; no run-time error detection")
-  else (VALGRIND STREQUAL VALGRIND-NOTFOUND)
-    set (VALGRIND_ENV "VALGRIND=${VALGRIND}")
-  endif (VALGRIND STREQUAL VALGRIND-NOTFOUND)
+  else ()
+    set (VALGRIND_ENV "VALGRIND=${VALGRIND_EXE}")
+  endif ()
 endif (ENABLE_VALGRIND)
 
+mark_as_advanced (VALGRIND_EXE)
+
 # c tests:
 
 add_subdirectory(src/tests)
@@ -472,8 +474,8 @@ add_test (python-test ${PYTHON_EXECUTABLE} ${env_py}
          ${PYTHON_EXECUTABLE} "${py_root}/proton-test")
 set_tests_properties(python-test PROPERTIES PASS_REGULAR_EXPRESSION "Totals: .* 0 failed")
 
-find_program(ruby_exe "ruby")
-if (ruby_exe)
+find_program(RUBY_EXE "ruby")
+if (RUBY_EXE)
   set (rb_root "${pn_test_root}/ruby")
   set (rb_src "${CMAKE_CURRENT_SOURCE_DIR}/bindings/ruby")
   set (rb_lib "${CMAKE_CURRENT_SOURCE_DIR}/bindings/ruby/lib")
@@ -483,20 +485,30 @@ if (ruby_exe)
   set (rb_rubylib "${rb_root}:${rb_src}:${rb_bin}:${rb_bld}:${rb_lib}")
 
   # ruby unit tests:  tests/ruby/proton-test
-  add_test (ruby-unit-test ${PYTHON_EXECUTABLE} ${env_py} "PATH=${rb_path}" "RUBYLIB=${rb_rubylib}"
-    "${rb_root}/proton-test")
-
-  # ruby spec tests
-  find_program(rspec_exe rspec)
-  if (rspec_exe)
-    add_test (NAME ruby-spec-test
-              WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bindings/ruby
-              COMMAND ${PYTHON_EXECUTABLE} ${env_py} "PATH=${rb_path}" "RUBYLIB=${rb_rubylib}"
-                      ${rspec_exe})
-
-  else(rspec_exe)
-    message (STATUS "Cannot find rspec, skipping rspec tests")
-  endif(rspec_exe)
-else (ruby_exe)
+  # only enable the tests if the Ruby gem dependencies were found
+  if (DEFAULT_RUBY_TESTING)
+    add_test (ruby-unit-test ${PYTHON_EXECUTABLE} ${env_py} "PATH=${rb_path}" "RUBYLIB=${rb_rubylib}"
+      "${rb_root}/proton-test")
+
+    # ruby spec tests
+    find_program(RSPEC_EXE rspec)
+    if (RSPEC_EXE)
+      add_test (NAME ruby-spec-test
+                WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bindings/ruby
+                COMMAND ${PYTHON_EXECUTABLE} ${env_py} "PATH=${rb_path}" "RUBYLIB=${rb_rubylib}"
+                        ${RSPEC_EXE})
+
+    else(RSPEC_EXE)
+      message (STATUS "Cannot find rspec, skipping rspec tests")
+    endif(RSPEC_EXE)
+  else (DEFAULT_RUBY_TESTING)
+    message(STATUS "Skipping Ruby tests: missing dependencies")
+  endif (DEFAULT_RUBY_TESTING)
+else (RUBY_EXE)
   message (STATUS "Cannot find ruby, skipping ruby tests")
-endif (ruby_exe)
+endif (RUBY_EXE)
+
+mark_as_advanced (RUBY_EXE RSPEC_EXE)
+
+# build examples to make sure they still work
+add_subdirectory(../examples ../examples)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/CMakeLists.txt b/proton-c/bindings/CMakeLists.txt
index 56bbd71..70cc552 100644
--- a/proton-c/bindings/CMakeLists.txt
+++ b/proton-c/bindings/CMakeLists.txt
@@ -36,9 +36,34 @@ if (PYTHONLIBS_FOUND)
 endif (PYTHONLIBS_FOUND)
 
 # Prerequisites for Ruby:
+find_program(GEM_EXE "gem")
+macro(CheckRubyGem varname gemname)
+  execute_process(COMMAND ${GEM_EXE} list --local ${gemname}
+    OUTPUT_VARIABLE CHECK_OUTPUT)
+
+  set (${varname} OFF)
+
+  if (CHECK_OUTPUT MATCHES "${gemname}[ ]+\(.*\)")
+    message(STATUS "Found Ruby gem: ${gemname}")
+    set (${varname} ON)
+  else()
+    message(STATUS "Missing Ruby gem dependency: ${gemname}")
+    set (${varname} OFF)
+  endif()
+endmacro()
+
 find_package(Ruby)
 if (RUBY_FOUND)
   set (DEFAULT_RUBY ON)
+
+  CheckRubyGem("HAS_RUBY_GEM_RSPEC"     "rspec")
+  CheckRubyGem("HAS_RUBY_GEM_SIMPLECOV" "simplecov")
+
+  if (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV)
+    set (DEFAULT_RUBY_TESTING ON CACHE INTERNAL "")
+  else()
+    set (DEFAULT_RUBY_TESTING OFF CACHE INTERNAL "")
+  endif (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV)
 endif (RUBY_FOUND)
 
 # Prerequites for PHP:
@@ -47,10 +72,12 @@ endif (RUBY_FOUND)
 find_program(PHP_CONFIG_EXE php-config)
 if (PHP_CONFIG_EXE)
   find_program(PHP_EXE php)
+  mark_as_advanced (PHP_EXE)
   if (PHP_EXE)
     set (DEFAULT_PHP ON)
   endif (PHP_EXE)
 endif (PHP_CONFIG_EXE)
+mark_as_advanced (PHP_CONFIG_EXE)
 
 # Prerequisites for Perl:
 include(FindPerl)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index 41020e6..269ee27 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -48,7 +48,6 @@ var Module = {
     'noExitRuntime' : true
 };
 
-
 /*****************************************************************************/
 /*                                                                           */
 /*                                   Status                                  */
@@ -116,7 +115,7 @@ Module['Error'] = {
  * @param {string} name the name of this Messenger instance.
  */
 Module['Messenger'] = function(name) { // Messenger Constructor.
-    /*
+    /**
      * The emscripten idiom below is used in a number of places in the JavaScript
      * bindings to map JavaScript Strings to C style strings. ALLOC_STACK will
      * increase the stack and place the item there. When the stack is next restored
@@ -761,8 +760,6 @@ Subscription.prototype['getAddress'] = function() {
 };
 
 
-
-
 /*****************************************************************************/
 /*                                                                           */
 /*                                  Message                                  */
@@ -1406,38 +1403,7 @@ Data.Long.prototype.toString = function() {
     return this.high + ":" + this.getLowBitsUnsigned();
 };
 
-// ---------------------------- proton.Data.Binary ---------------------------- 
-
-/*
-    function freeBuffer() {
-        if (ptr !== 0) {
-            _free(ptr);
-        }
-    };
-
-    // Public methods
-    _public.destroy = function() {
-        freeBuffer();
-    };
-
-    _public.setSize = function(size) {
-        if (size > asize) {
-            freeBuffer();
-            ptr = _malloc(size); // Get output buffer from emscripten.
-            asize = size;
-        }
-        _public.size = size;
-    };
-
-    _public.getRaw = function() {
-        return ptr;
-    };
-
-    _public.getBuffer = function() {
-        // Get a Uint8Array view on the input buffer.
-        return new Uint8Array(HEAPU8.buffer, ptr, _public.size);
-*/
-
+// ---------------------------- proton.Data.Binary ----------------------------
 /**
  * Create a proton.Data.Binary. This constructor takes one or two parameters,
  * size specifies the size in bytes of the Binary buffer, start is a pointer
@@ -1461,11 +1427,16 @@ Data.Long.prototype.toString = function() {
  * {@link proton.Messenger.get} call then the client must explicitly *copy* the
  * bytes into a new buffer via copyBuffer().
  * @constructor proton.Data.Binary
- * @param {number} size the size of the Binary data buffer.
+ * @param {object} data. If data is a number then it represents the size of the
+ *        Binary data buffer, if it is a string then we copy the string to the
+ *        buffer, if it is an Array or a TypedArray then we copy the data to
+ *        the buffer. N.B. although convenient do bear in mind that every method
+ *        other than constructing with a size followed by a call to getBuffer will
+ *        result in some form of additional data copy.
  * @param {number} start an optional data pointer to the start of the Binary data buffer.
  */
-Data['Binary'] = function(size, start) { // Data.Binary Constructor.
-    /*
+Data['Binary'] = function(data, start) { // Data.Binary Constructor.
+    /**
      * If the start pointer is specified then the underlying binary data is owned
      * by another object, so we set the call to free to be a null function. If
      * the start pointer is not passed then we allocate storage of the specified
@@ -1477,10 +1448,30 @@ Data['Binary'] = function(size, start) { // Data.Binary Constructor.
      * turn take responsibility for calling free once it has taken ownership of
      * the underlying binary data.
      */
+    var size = data;
     if (start) {
         this.free = function() {};
-    } else {
-        start = _malloc(size); // Allocate storage from emscripten heap.
+    } else { // Create Binary from Array, ArrayBuffer or TypedArray
+        if (Data.isArray(data) ||
+            (data instanceof ArrayBuffer) || 
+            (data.buffer && data.buffer instanceof ArrayBuffer)) {
+            data = new Uint8Array(data);
+            size = data.length;
+            start = _malloc(size); // Allocate storage from emscripten heap.
+            Module.HEAPU8.set(data, start);
+        } else if (Data.isString(data)) { // Create Binary from native string
+            data = unescape(encodeURIComponent(data)); // Create a C-like UTF representation.
+            size = data.length;
+            start = _malloc(size); // Allocate storage from emscripten heap.
+            for (var i = 0; i < size; i++) {
+                setValue(start + i, data.charCodeAt(i), 'i8', 1);
+            }
+        } else { // Create unpopulated Binary of specified size.
+            // If the type is not a number by this point then an unrecognised data
+            // type has been passed so we create a zero length Binary.
+            size = Data.isNumber(size) ? size : 0;
+            start = _malloc(size); // Allocate storage from emscripten heap.
+        }
         this.free = function() {_free(start);};
     }
 
@@ -1488,7 +1479,7 @@ Data['Binary'] = function(size, start) { // Data.Binary Constructor.
     this.start = start;
 };
 
-/*
+/**
  * Get a Uint8Array view of the data. N.B. this is just a *view* of the data,
  * which will go out of scope on the next call to {@link proton.Messenger.get}. If
  * a client wants to retain the data then copyBuffer should be used to explicitly
@@ -1500,7 +1491,7 @@ Data['Binary'].prototype['getBuffer'] = function() {
     return new Uint8Array(HEAPU8.buffer, this.start, this.size);
 };
 
-/*
+/**
  * Explicitly create a *copy* of the underlying binary data and present a Uint8Array
  * view of that copy. This method should be used if a client application wishes to
  * retain an interest in the binary data for longer than it wishes to retain an
@@ -1921,8 +1912,6 @@ _Data_['putUUID'] = function(u) {
  * @param {proton.Data.Binary} b a binary value.
  */
 _Data_['putBinary'] = function(b) {
-console.log("putBinary");
-
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -1933,8 +1922,7 @@ console.log("putBinary");
     // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
     // the low-level code handles this *by pointer* so we first need to allocate
     // 8 bytes storage for {size, start} on the emscripten stack and then we
-    // pass the pointer to that storage as the first parameter to the compiled
-    // pn_bytes.
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
     var bytes = allocate(8, 'i8', ALLOC_STACK);
     _pn_bytes(bytes, b.size, b.start);
 
@@ -1965,18 +1953,16 @@ _Data_['putString'] = function(s) {
     // First create an array from the JavaScript String using the intArrayFromString
     // helper function (from emscripten/src/preamble.js). We use this idiom in a
     // few places but here we create array as a separate var as we need its length.
-    var array = intArrayFromString(s);
+    var array = intArrayFromString(s, true); // The true means don't add NULL.
     // Allocate temporary storage for the array on the emscripten stack.
     var str = allocate(array, 'i8', ALLOC_STACK);
 
     // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
     // the low-level code handles this *by pointer* so we first need to allocate
     // 8 bytes storage for {size, start} on the emscripten stack and then we
-    // pass the pointer to that storage as the first parameter to the compiled
-    // pn_bytes. The second parameter is the length of the array - 1 because it
-    // is a NULL terminated C style string at this point.
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
     var bytes = allocate(8, 'i8', ALLOC_STACK);
-    _pn_bytes(bytes, array.length - 1, str);
+    _pn_bytes(bytes, array.length, str);
 
     // The compiled pn_data_put_string takes the pn_bytes_t by reference not value.
     this._check(_pn_data_put_string(this._data, bytes));
@@ -2004,53 +1990,22 @@ _Data_['putSymbol'] = function(s) {
     // First create an array from the JavaScript String using the intArrayFromString
     // helper function (from emscripten/src/preamble.js). We use this idiom in a
     // few places but here we create array as a separate var as we need its length.
-    var array = intArrayFromString(s);
+    var array = intArrayFromString(s, true); // The true means don't add NULL.
     // Allocate temporary storage for the array on the emscripten stack.
     var str = allocate(array, 'i8', ALLOC_STACK);
 
     // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
     // the low-level code handles this *by pointer* so we first need to allocate
     // 8 bytes storage for {size, start} on the emscripten stack and then we
-    // pass the pointer to that storage as the first parameter to the compiled
-    // pn_bytes. The second parameter is the length of the array - 1 because it
-    // is a NULL terminated C style string at this point.
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
     var bytes = allocate(8, 'i8', ALLOC_STACK);
-    _pn_bytes(bytes, array.length - 1, str);
+    _pn_bytes(bytes, array.length, str);
 
     // The compiled pn_data_put_symbol takes the pn_bytes_t by reference not value.
     this._check(_pn_data_put_symbol(this._data, bytes));
     Runtime.stackRestore(sp);
 };
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 // TODO getArray and isDescribed
 
 /**
@@ -2267,7 +2222,6 @@ _Data_['getUUID'] = function() {
  * @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise.
  */
 _Data_['getBinary'] = function() {
-console.log("getBinary");
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2377,8 +2331,6 @@ _Data_['getSymbol'] = function() {
 // TODO copy, format and dump
 
 
-
-
 /**
  * Serialise a Native JavaScript Object into an AMQP Map.
  * @method putDictionary
@@ -2419,7 +2371,6 @@ _Data_['getDictionary'] = function() {
     }
 };
 
-
 /**
  * Serialise a Native JavaScript Array into an AMQP List.
  * @method putJSArray
@@ -2452,14 +2403,6 @@ _Data_['getJSArray'] = function() {
     }
 };
 
-
-
-
-
-
-
-
-
 /**
  * This method is the entry point for serialising native JavaScript types into
  * AMQP types. In an ideal world there would be a nice clean one to one mapping
@@ -2539,7 +2482,6 @@ console.log(obj + " is Float Type");
 };
 _Data_.putObject = _Data_['putObject'];
 
-
 /**
  * @method getObject
  * @memberof! proton.Data#

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/javascript/drain.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/drain.js b/proton-c/bindings/javascript/drain.js
index e93ba2e..9d9c726 100644
--- a/proton-c/bindings/javascript/drain.js
+++ b/proton-c/bindings/javascript/drain.js
@@ -48,12 +48,14 @@ console.log("tracker = " + tracker);
     };
 
     //messenger.setIncomingWindow(1024);
-
+console.log("Break A");
     messenger.setNetworkCallback(_process);
     messenger.start();
-
+console.log("Break B");
     messenger.subscribe(address);
+console.log("Break C");
     messenger.recv(); // Receive as many messages as messenger can buffer.
+console.log("Break D");
 } catch(e) {
     console.log("Caught Exception " + e);
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/javascript/spout.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/spout.js b/proton-c/bindings/javascript/spout.js
index 7d3cc58..254b948 100644
--- a/proton-c/bindings/javascript/spout.js
+++ b/proton-c/bindings/javascript/spout.js
@@ -70,6 +70,8 @@ console.log("exiting");
     //message.body = msgtext;
     //message.body = new proton.Data.UUID();
     //message.body = new proton.Data.Symbol("My Symbol");
+    //message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
+
     message.body = new proton.Data.Binary(4);
     var buffer = message.body.getBuffer();
     buffer[0] = 65;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/perl/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/CMakeLists.txt b/proton-c/bindings/perl/CMakeLists.txt
index 158fdc6..365439b 100644
--- a/proton-c/bindings/perl/CMakeLists.txt
+++ b/proton-c/bindings/perl/CMakeLists.txt
@@ -23,28 +23,24 @@ include_directories("${PERL_INCLUDE_PATH}")
 execute_process(COMMAND perl -MConfig -e "print \$Config{ccflags}"
                 OUTPUT_VARIABLE PERLCFLAGS)
 
-if (ASK_PERL)
+if (CHECK_SYSINSTALL_PERL)
+  execute_process(COMMAND perl -V:installvendorarch
+    OUTPUT_VARIABLE PERL_VENDORARCH_OUTPUT_VARIABLE
+    RESULT_VARIABLE PERL_VENDORARCH_RESULT_VARIABLE)
 
-  execute_process(COMMAND perl -V:installvendorlib
-    OUTPUT_VARIABLE PERL_ARCHLIB_OUTPUT_VARIABLE
-    RESULT_VARIABLE PERL_ARCHLIB_RESULT_VARIABLE)
-  if (NOT PERL_ARCHLIB_RESULT_VARIABLE)
-    string(REGEX REPLACE "install[a-z]+='([^']+)'.*" "\\1" PERL_ARCHLIB ${PERL_ARCHLIB_OUTPUT_VARIABLE})
-    file(TO_CMAKE_PATH "${PERL_ARCHLIB}" PERL_ARCHLIB_DIR)
-  endif (NOT PERL_ARCHLIB_RESULT_VARIABLE)
+  if (NOT PERL_VENDORARCH_RESULT_VARIABLE)
+    string(REGEX REPLACE "install[a-z]+='([^']+)'.*" "\\1" PERL_VENDORARCH ${PERL_VENDORARCH_OUTPUT_VARIABLE})
+    file(TO_CMAKE_PATH "${PERL_VENDORARCH}" PERL_VENDORARCH_DIR_DEFAULT)
+  else ()
+    set (PERL_VENDORARCH_DIR_DEFAULT ${PERL_VENDORARCH_RESULT_VARIABLE})
+  endif ()
+else (CHECK_SYSINSTALL_PERL)
+  set (PERL_VENDORARCH_DIR_DEFAULT ${BINDINGS_DIR}/perl)
+endif (CHECK_SYSINSTALL_PERL)
 
-  execute_process(COMMAND perl -V:installsitelib
-    OUTPUT_VARIABLE PERL_SITELIB_OUTPUT_VARIABLE
-    RESULT_VARIABLE PERL_SITELIB_RESULT_VARIABLE)
-  if (NOT PERL_SITELIB_RESULT_VARIABLE)
-    string(REGEX REPLACE "install[a-z]+='([^']+)'.*" "\\1" PERL_SITELIB ${PERL_SITELIB_OUTPUT_VARIABLE})
-    file(TO_CMAKE_PATH "${PERL_SITELIB}" PERL_SITELIB_DIR)
-  endif (NOT PERL_SITELIB_RESULT_VARIABLE)
-
-else (ASK_PERL)
-  set (PERL_ARCHLIB_DIR ${BINDINGS_DIR}/perl/lib${LIB_SUFFIX} CACHE PATH "Perl platform code")
-  set (PERL_SITELIB_DIR ${BINDINGS_DIR}/perl/ CACHE PATH "Perl code")
-endif (ASK_PERL)
+if (NOT PERL_VENDORARCH_DIR)
+  set (PERL_VENDORARCH_DIR ${PERL_VENDORARCH_DIR_DEFAULT})
+endif()
 
 set (CMAKE_C_FLAGS ${PERLCFLAGS})
 
@@ -53,32 +49,25 @@ swig_link_libraries(cproton_perl ${BINDING_DEPS} ${PERL_LIBRARY})
 
 if ((${CMAKE_MAJOR_VERSION} EQUAL 2) AND (${CMAKE_MINOR_VERSION} LESS 8))
   install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton_perl.so
-        DESTINATION ${PERL_ARCHLIB_DIR}
-        COMPONENT ${QPID_COMPONENT_CLIENT}
+        DESTINATION ${PERL_VENDORARCH_DIR}
+        COMPONENT Perl
         )
 else()
   install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcproton_perl.so
         RENAME cproton_perl.so
-        DESTINATION ${PERL_ARCHLIB_DIR}
-        COMPONENT ${QPID_COMPONENT_CLIENT}
+        DESTINATION ${PERL_VENDORARCH_DIR}
+        COMPONENT Perl
         )
 endif ((${CMAKE_MAJOR_VERSION} EQUAL 2) AND (${CMAKE_MINOR_VERSION} LESS 8))
 
-# get the perl vendor library if it's not already defined
-#if (NOT PERL_ARCHLIB)
-#  execute_process(COMMAND ${PERL_EXECUTABLE} "-V:installvendorlib"
-#                  OUTPUT_VARIABLE PERL_ARCHLIB_OUTPUT_VARIABLE
-#                  RESULT_VARIABLE PERL_ARCHLIB_RESULT_VARIABLE)
-#endif (!DEFINED PERL_ARCHLIB)
-
 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton_perl.pm
-        DESTINATION ${PERL_ARCHLIB_DIR}
+        DESTINATION ${PERL_VENDORARCH_DIR}
         COMPONENT Perl)
 
 install(FILES lib/qpid_proton.pm
-        DESTINATION ${PERL_SITELIB_DIR}
+        DESTINATION ${PERL_VENDORARCH_DIR}
         COMPONENT Perl)
 
 INSTALL(DIRECTORY lib/qpid
-        DESTINATION ${PERL_SITELIB_DIR}
+        DESTINATION ${PERL_VENDORARCH_DIR}
         COMPONENT Perl)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/perl/perl.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/perl.i b/proton-c/bindings/perl/perl.i
index 914623b..cc6a4d7 100644
--- a/proton-c/bindings/perl/perl.i
+++ b/proton-c/bindings/perl/perl.i
@@ -137,7 +137,9 @@ typedef int int32_t;
 
 %typemap(in) pn_uuid_t
 {
-  AV* tmpav = SvRV($input);
+  // XXX: I believe there is a typemap or something similar for
+  // typechecking the input. We should probably use it.
+  AV* tmpav = (AV *) SvRV($input);
   int index = 0;
 
   for(index = 0; index < 16; index++)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/php/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/php/CMakeLists.txt b/proton-c/bindings/php/CMakeLists.txt
index 9b6ee2c..762e05b 100644
--- a/proton-c/bindings/php/CMakeLists.txt
+++ b/proton-c/bindings/php/CMakeLists.txt
@@ -39,7 +39,7 @@ set_target_properties(cproton
     PREFIX ""
     LINK_FLAGS "${ALLOW_UNDEFINED}")
 
-if (ASK_PHP)
+if (CHECK_SYSINSTALL_PHP)
   execute_process(COMMAND ${PHP_CONFIG_EXE} --extension-dir
     OUTPUT_VARIABLE PHP_EXT_DIR_DEFAULT
     OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -65,18 +65,36 @@ if (ASK_PHP)
   if ("${PHP_INI_DIR_DEFAULT}" STREQUAL "")
     set(PHP_INI_DIR_DEFAULT "/etc/php.d")
   endif()
+else (CHECK_SYSINSTALL_PHP)
+  set (PHP_EXT_DIR_DEFAULT ${BINDINGS_DIR}/php)
+  set (PHP_INI_DIR_DEFAULT ${BINDINGS_DIR}/php)
+  set (PHP_INCLUDE_DIR_DEFAULT ${BINDINGS_DIR}/php)
+endif (CHECK_SYSINSTALL_PHP)
 
-  set(PHP_EXT_DIR ${PHP_EXT_DIR_DEFAULT} CACHE PATH "PHP extensions directory.")
-  set(PHP_INI_DIR ${PHP_INI_DIR_DEFAULT} CACHE PATH "Directory scanned for PHP ini files.")
-  set(PHP_INCLUDE_DIR ${PHP_INCLUDE_DIR_DEFAULT} CACHE PATH "PHP include directory.")
+# PHP extensions directory
+if (NOT PHP_EXT_DIR)
+  set (PHP_EXT_DIR ${PHP_EXT_DIR_DEFAULT})
+endif()
+# PHP ini directory
+if (NOT PHP_INI_DIR)
+  set (PHP_INI_DIR ${PHP_INI_DIR_DEFAULT})
+endif()
+# PHP include directory
+if (NOT PHP_INCLUDE_DIR)
+  set (PHP_INCLUDE_DIR ${PHP_INCLUDE_DIR_DEFAULT})
+endif()
 
-else (ASK_PHP)
+if (CHECK_SYSINSTALL_PHP)
+  set (PROTON_INI "extension=cproton.so")
+else ()
+  pn_absolute_install_dir(PHP_INCLUDE_PATH ${PHP_INCLUDE_DIR} ${CMAKE_INSTALL_PREFIX})
+  pn_absolute_install_dir(PHP_EXTENSION_LIB ${PHP_EXT_DIR}/cproton.so ${CMAKE_INSTALL_PREFIX})
+  set (PROTON_INI "include_path=${PHP_INCLUDE_PATH}\nextension=${PHP_EXTENSION_LIB}")
+endif()
 
-  set (PHP_EXT_DIR ${BINDINGS_DIR}/php CACHE PATH "PHP extensions directory")
-  set (PHP_INCLUDE_DIR ${BINDINGS_DIR}/php/include CACHE PATH "PHP include directory")
-  set (PHP_INI_DIR ${BINDINGS_DIR}/php/ini CACHE PATH "PHP ini directory")
-
-endif (ASK_PHP)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/proton.ini.in
+                ${CMAKE_CURRENT_BINARY_DIR}/proton.ini
+                @ONLY)
 
 install(TARGETS cproton
         DESTINATION ${PHP_EXT_DIR}
@@ -89,7 +107,7 @@ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/proton.php
         COMPONENT PHP)
 
 if (NOT ${PHP_INI_DIR} STREQUAL "")
-  install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cproton.ini
-          DESTINATION ${PHP_INI_DIR}
-          COMPONENT PHP)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/proton.ini
+    DESTINATION ${PHP_INI_DIR}
+    COMPONENT PHP)
 endif ()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/php/compat.swg
----------------------------------------------------------------------
diff --git a/proton-c/bindings/php/compat.swg b/proton-c/bindings/php/compat.swg
new file mode 100644
index 0000000..d7ffce0
--- /dev/null
+++ b/proton-c/bindings/php/compat.swg
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+%define CONVERT_LONG_LONG_IN(lvar,t,invar)
+  switch ((*(invar))->type) {
+      case IS_DOUBLE:
+          lvar = (t) (*(invar))->value.dval;
+          break;
+      case IS_STRING: {
+          char * endptr;
+          errno = 0;
+          lvar = (t) strtoll((*(invar))->value.str.val, &endptr, 10);
+          if (*endptr && !errno) break;
+          /* FALL THRU */
+      }
+      default:
+          convert_to_long_ex(invar);
+          lvar = (t) (*(invar))->value.lval;
+  }
+%enddef
+
+%pass_by_val(long long, CONVERT_LONG_LONG_IN);
+
+%typemap(out) long long
+%{
+  if ((long long)LONG_MIN <= $1 && $1 <= (long long)LONG_MAX) {
+    return_value->value.lval = (long)($1);
+    return_value->type = IS_LONG;
+  } else {
+    char temp[256];
+    sprintf(temp, "%lld", (long long)$1);
+    ZVAL_STRING(return_value, temp, 1);
+  }
+%}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/php/php.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/php/php.i b/proton-c/bindings/php/php.i
index b31014d..7cf4f5f 100644
--- a/proton-c/bindings/php/php.i
+++ b/proton-c/bindings/php/php.i
@@ -22,6 +22,9 @@
 // provided by SWIG development libraries
 %include php.swg
 
+#if SWIG_VERSION < 0x020000
+%include compat.swg
+#endif
 
 %header %{
 /* Include the headers needed by the code in this wrapper file */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/php/proton.ini.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/php/proton.ini.in b/proton-c/bindings/php/proton.ini.in
new file mode 100644
index 0000000..51a774e
--- /dev/null
+++ b/proton-c/bindings/php/proton.ini.in
@@ -0,0 +1,21 @@
+;;
+; Licensed to the Apache Software Foundation (ASF) under one
+; or more contributor license agreements.  See the NOTICE file
+; distributed with this work for additional information
+; regarding copyright ownership.  The ASF licenses this file
+; to you under the Apache License, Version 2.0 (the
+; "License"); you may not use this file except in compliance
+; with the License.  You may obtain a copy of the License at
+;
+;   http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing,
+; software distributed under the License is distributed on an
+; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+; KIND, either express or implied.  See the License for the
+; specific language governing permissions and limitations
+; under the License.
+;;
+
+; Enable cproton extension module
+@PROTON_INI@

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/php/proton.php
----------------------------------------------------------------------
diff --git a/proton-c/bindings/php/proton.php b/proton-c/bindings/php/proton.php
index 30c6675..4c3e4ef 100644
--- a/proton-c/bindings/php/proton.php
+++ b/proton-c/bindings/php/proton.php
@@ -280,7 +280,7 @@ class Message {
     $body = new Data(pn_message_body($this->impl));
 
     if ($inst->next())
-      $this->instructions = $inst.get_object();
+      $this->instructions = $inst->get_object();
     else
       $this->instructions = null;
     if ($ann->next())

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt
index b63b6fd..7853e18 100644
--- a/proton-c/bindings/python/CMakeLists.txt
+++ b/proton-c/bindings/python/CMakeLists.txt
@@ -30,19 +30,18 @@ set_target_properties(_cproton
 
 find_package(PythonInterp REQUIRED)
 
-if (ASK_PYTHON)
+if (CHECK_SYSINSTALL_PYTHON)
+  execute_process(COMMAND ${PYTHON_EXECUTABLE}
+    -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True)"
+    OUTPUT_VARIABLE PYTHON_SITEARCH_PACKAGES_DEFAULT
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+else ()
+  set (PYTHON_SITEARCH_PACKAGES_DEFAULT ${BINDINGS_DIR}/python)
+endif ()
 
-  if (NOT PYTHON_SITEARCH_PACKAGES)
-    execute_process(COMMAND ${PYTHON_EXECUTABLE}
-      -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True)"
-      OUTPUT_VARIABLE PYTHON_ARCHLIB_DIR
-      OUTPUT_STRIP_TRAILING_WHITESPACE)
-  else (NOT PYTHON_SITEARCH_PACKAGES)
-    set (PYTHON_ARCHLIB_DIR "${PYTHON_SITEARCH_PACKAGES}")
-  endif ()
-else (ASK_PYTHON)
-  set (PYTHON_ARCHLIB_DIR ${BINDINGS_DIR}/python/lib${LIB_SUFFIX} CACHE PATH "Python platform code")
-endif (ASK_PYTHON)
+if (NOT PYTHON_SITEARCH_PACKAGES)
+  set (PYTHON_SITEARCH_PACKAGES ${PYTHON_SITEARCH_PACKAGES_DEFAULT})
+endif()
 
 install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cproton.py
                               WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
@@ -54,10 +53,12 @@ install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile prot
                               WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
 
 find_program(EPYDOC_EXE epydoc)
+mark_as_advanced (EPYDOC_EXE)
 if (EPYDOC_EXE)
-   add_custom_target(docs-py COMMAND ${EPYDOC_EXE} -v --no-private --html
-                     -o ${CMAKE_CURRENT_BINARY_DIR}/html
-                     ${CMAKE_CURRENT_SOURCE_DIR}/proton.py)
+   add_custom_target(docs-py COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../../env.py --
+     PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_CURRENT_SOURCE_DIR}
+     ${EPYDOC_EXE} -v --no-private --html -o ${CMAKE_CURRENT_BINARY_DIR}/html
+     ${CMAKE_CURRENT_SOURCE_DIR}/proton.py)
    add_dependencies(docs docs-py)
    install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html/"
            DESTINATION "${PROTON_SHARE}/docs/api-py"
@@ -71,8 +72,8 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton.py
               ${CMAKE_CURRENT_SOURCE_DIR}/proton.py
               ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyc
               ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyo
-        DESTINATION ${PYTHON_ARCHLIB_DIR}
+        DESTINATION ${PYTHON_SITEARCH_PACKAGES}
         COMPONENT Python)
 install(TARGETS _cproton
-        DESTINATION ${PYTHON_ARCHLIB_DIR}
+        DESTINATION ${PYTHON_SITEARCH_PACKAGES}
         COMPONENT Python)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/python/proton.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton.py b/proton-c/bindings/python/proton.py
index c85a5b2..12da599 100644
--- a/proton-c/bindings/python/proton.py
+++ b/proton-c/bindings/python/proton.py
@@ -3277,6 +3277,7 @@ class Collector:
     else:
       tp = None
     return Event(type=pn_event_type(event),
+                 category=pn_event_category(event),
                  connection=Connection._wrap_connection(pn_event_connection(event)),
                  session=Session._wrap_session(pn_event_session(event)),
                  link=Link._wrap_link(pn_event_link(event)),
@@ -3291,15 +3292,22 @@ class Collector:
 
 class Event:
 
-  CONNECTION_STATE = PN_CONNECTION_STATE
-  SESSION_STATE = PN_SESSION_STATE
-  LINK_STATE = PN_LINK_STATE
+  CATEGORY_PROTOCOL = PN_EVENT_CATEGORY_PROTOCOL
+
+  CONNECTION_LOCAL_STATE = PN_CONNECTION_LOCAL_STATE
+  CONNECTION_REMOTE_STATE = PN_CONNECTION_REMOTE_STATE
+  SESSION_LOCAL_STATE = PN_SESSION_LOCAL_STATE
+  SESSION_REMOTE_STATE = PN_SESSION_REMOTE_STATE
+  LINK_LOCAL_STATE = PN_LINK_LOCAL_STATE
+  LINK_REMOTE_STATE = PN_LINK_REMOTE_STATE
   LINK_FLOW = PN_LINK_FLOW
   DELIVERY = PN_DELIVERY
   TRANSPORT = PN_TRANSPORT
 
-  def __init__(self, type, connection, session, link, delivery, transport):
+  def __init__(self, type, category,
+               connection, session, link, delivery, transport):
     self.type = type
+    self.category = category
     self.connection = connection
     self.session = session
     self.link = link

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/ruby/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/CMakeLists.txt b/proton-c/bindings/ruby/CMakeLists.txt
index 5768907..9336abf 100644
--- a/proton-c/bindings/ruby/CMakeLists.txt
+++ b/proton-c/bindings/ruby/CMakeLists.txt
@@ -17,6 +17,10 @@
 # under the License.
 #
 
+if (NOT DEFAULT_RUBY_TESTING)
+  message(FATAL_ERROR "Ruby bindings cannot be tested while missing dependencies")
+endif (NOT DEFAULT_RUBY_TESTING)
+
 include_directories (${RUBY_INCLUDE_PATH})
 swig_add_module(cproton-ruby ruby ruby.i)
 swig_link_libraries(cproton-ruby ${BINDING_DEPS} ${RUBY_LIBRARY})
@@ -26,8 +30,7 @@ set_target_properties(cproton-ruby
     OUTPUT_NAME "cproton"
     LINK_FLAGS "${CATCH_UNDEFINED}" )
 
-if (ASK_RUBY)
-
+if (CHECK_SYSINSTALL_RUBY)
   execute_process(COMMAND ${RUBY_EXECUTABLE}
     -r rbconfig -e "print RbConfig::CONFIG['vendorarchdir'] || ''"
     RESULT_VARIABLE RESULT_RUBY_ARCHLIB_DIR
@@ -38,18 +41,16 @@ if (ASK_RUBY)
       -r rbconfig -e "print RbConfig::CONFIG['archdir'] || ''"
       RESULT_VARIABLE RESULT_RUBY_ARCHLIB_DIR
       OUTPUT_VARIABLE OUTPUT_RUBY_ARCHLIB_DIR)
-
   endif()
 
-  set(RUBY_ARCHLIB_DIR "${OUTPUT_RUBY_ARCHLIB_DIR}")
-
-else (ASK_RUBY)
-
-  set (RUBY_SITELIB_DIR ${BINDINGS_DIR}/ruby CACHE PATH "Ruby portable code")
-  set (RUBY_ARCHLIB_DIR ${BINDINGS_DIR}/ruby/lib${LIB_SUFFIX} CACHE PATH "Ruby platform code")
-
-endif (ASK_RUBY)
+  set(RUBY_ARCHLIB_DIR_DEFAULT "${OUTPUT_RUBY_ARCHLIB_DIR}")
+else (CHECK_SYSINSTALL_RUBY)
+  set (RUBY_ARCHLIB_DIR_DEFAULT ${BINDINGS_DIR}/ruby)
+endif (CHECK_SYSINSTALL_RUBY)
 
+if (NOT RUBY_ARCHLIB_DIR)
+  set (RUBY_ARCHLIB_DIR ${RUBY_ARCHLIB_DIR_DEFAULT})
+endif()
 
 install(TARGETS cproton-ruby
         DESTINATION ${RUBY_ARCHLIB_DIR}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/ruby/lib/qpid_proton.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton.rb b/proton-c/bindings/ruby/lib/qpid_proton.rb
index 41904b1..cf044f6 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton.rb
@@ -26,11 +26,12 @@ require "qpid_proton/array"
 require "qpid_proton/hash"
 require "qpid_proton/exceptions"
 require "qpid_proton/exception_handling"
+require "qpid_proton/filters"
 require "qpid_proton/message_format"
 require "qpid_proton/data"
 require "qpid_proton/message"
 require "qpid_proton/subscription"
 require "qpid_proton/tracker_status"
 require "qpid_proton/tracker"
+require "qpid_proton/selectable"
 require "qpid_proton/messenger"
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/ruby/lib/qpid_proton/filters.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/filters.rb b/proton-c/bindings/ruby/lib/qpid_proton/filters.rb
new file mode 100644
index 0000000..46c9bf7
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/qpid_proton/filters.rb
@@ -0,0 +1,67 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+module Qpid
+
+  module Proton
+
+    module Filters
+
+      def self.included(base)
+        base.class_eval do
+          extend ClassMethods
+        end
+      end
+
+      module ClassMethods
+
+        def method_added(method_name)
+          @@hooked_methods ||= []
+          return if @@hooked_methods.include?(method_name)
+          @@hooked_methods << method_name
+          hooks = @@before_hooks[method_name]
+          return if hooks.nil?
+          orig_method = instance_method(method_name)
+          define_method(method_name) do |*args, &block|
+            hooks = @@before_hooks[method_name]
+            hooks.each do |hook|
+              method(hook).call
+            end
+
+            orig_method.bind(self).call(*args, &block)
+          end
+        end
+
+        def call_before(before_method, *methods)
+          @@before_hooks ||= {}
+          methods.each do |method|
+            hooks = @@before_hooks[method] || []
+            raise "Repeat filter: #{before_method}" if hooks.include? before_method
+            hooks << before_method
+            @@before_hooks[method] = hooks
+          end
+        end
+
+      end
+
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
index b16c8e7..dfc5717 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
@@ -36,19 +36,19 @@ module Qpid
     #
     # The Messenger class works in conjuction with the Message class. The
     # Message class is a mutable holder of message content.
-    # 
-    # The put method copies its Message to the outgoing queue, and may 
+    #
+    # The put method copies its Message to the outgoing queue, and may
     # send queued messages if it can do so without blocking.  The send
     # method blocks until it has sent the requested number of messages,
     # or until a timeout interrupts the attempt.
-    # 
+    #
     # Similarly, the recv method receives messages into the incoming
     # queue, and may block as it attempts to receive the requested number
     # of messages,  or until timeout is reached. It may receive fewer
     # than the requested number.  The get method pops the
     # eldest Message off the incoming queue and copies it into the Message
     # object that you supply.  It will not block.
-    # 
+    #
     # The blocking attribute allows you to turn off blocking behavior entirely,
     # in which case send and recv will do whatever they can without
     # blocking, and then return.  You can then look at the number
@@ -70,6 +70,7 @@ module Qpid
       #
       def initialize(name = nil)
         @impl = Cproton.pn_messenger(name)
+        @selectables = {}
         ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
       end
 
@@ -121,20 +122,45 @@ module Qpid
         Cproton.pn_messenger_get_timeout(@impl)
       end
 
-      # Blocking Attribute
+      # Returns true if blocking mode is enabled.
       #
       # Enable or disable blocking behavior during message sending
       # and receiving.  This affects every blocking call, with the
       # exception of work().  Currently, the affected calls are
       # send, recv, and stop.
-      def blocking
-        Cproton.pn_mesenger_is_blocking(@impl)
+      def blocking?
+        Cproton.pn_messenger_is_blocking(@impl)
       end
 
+      # Sets the blocking mode.
       def blocking=(blocking)
         Cproton.pn_messenger_set_blocking(@impl, blocking)
       end
 
+      # Returns true if passive mode is enabled.
+      #
+      def passive?
+        Cproton.pn_messenger_is_passive(@impl)
+      end
+
+      # Turns passive mode on or off.
+      #
+      # When set to passive mode, Messenger will not attempt to perform I/O
+      # operations internally. In this mode it is necesssary to use the
+      # Selectable type to drive any I/O needed to perform requestioned
+      # actions.
+      #
+      # In this mode Messenger will never block.
+      #
+      def passive=(mode)
+        Cproton.pn_messenger_set_passive(@impl, mode)
+      end
+
+      def deadline
+        tstamp = Cproton.pn_messenger_deadline(@impl)
+        return tstamp / 1000.0 unless tstamp.nil?
+      end
+
       # Reports whether an error occurred.
       #
       def error?
@@ -456,6 +482,22 @@ module Qpid
         check_for_error(Cproton.pn_messenger_rewrite(@impl, pattern, address))
       end
 
+      def selectable
+        impl = Cproton.pn_messenger_selectable(@impl)
+
+        # if we don't have any selectables, then return
+        return nil if impl.nil?
+
+        fd = Cproton.pn_selectable_fd(impl)
+
+        selectable = @selectables[fd]
+        if selectable.nil?
+          selectable = Selectable.new(self, impl)
+          @selectables[fd] = selectable
+        end
+        return selectable
+      end
+
       # Returns a +Tracker+ for the message most recently sent via the put
       # method.
       #
@@ -600,6 +642,11 @@ module Qpid
         Cproton.pn_messenger_get_outgoing_window(@impl)
       end
 
+      # Unregisters a selectable object.
+      def unregister_selectable(fileno) # :nodoc:
+        @selectables.delete(fileno)
+      end
+
       private
 
       def valid_tracker?(tracker)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb b/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
new file mode 100644
index 0000000..34a030f
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
@@ -0,0 +1,126 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+module Qpid
+
+  module Proton
+
+    # Selectable enables accessing the underlying file descriptors
+    # for Messenger.
+    class Selectable
+
+      include Qpid::Proton::Filters
+
+      call_before :check_is_initialized,
+      :fileno, :capacity, :pending, :deadline,
+      :readable, :writable, :expired,
+      :registered=, :registered?
+
+      def initialize(messenger, impl) # :nodoc:
+        @messenger = messenger
+        @impl = impl
+        @io = nil
+        @freed = false
+      end
+
+      # Returns the underlying file descriptor.
+      #
+      # This can be used in conjunction with the IO class.
+      #
+      def fileno
+        Cproton.pn_selectable_fd(@impl)
+      end
+
+      def to_io
+        @io ||= IO.new(fileno)
+      end
+
+      # The number of bytes the selectable is capable of consuming.
+      #
+      def capacity
+        Cproton.pn_selectable_capacity(@impl)
+      end
+
+      # The number of bytes waiting to be written to the file descriptor.
+      #
+      def pending
+        Cproton.pn_selectable_pending(@impl)
+      end
+
+      # The future expiry time at which control will be returned to the
+      # selectable.
+      #
+      def deadline
+        tstamp = Cproton.pn_selectable_deadline(@impl)
+        tstamp.nil? ? nil : tstamp / 1000
+      end
+
+      def readable
+        Cproton.pn_selectable_readable(@impl)
+      end
+
+      def writable
+        Cproton.pn_selectable_writable(@impl)
+      end
+
+      def expired?
+        Cproton.pn_selectable_expired(@impl)
+      end
+
+      def registered=(registered)
+        Cproton.pn_selectable_set_registered(@impl, registered)
+      end
+
+      def registered?
+        Cproton.pn_selectable_is_registered(@impl)
+      end
+
+      def terminal?
+        return true if @impl.nil?
+        Cproton.pn_selectable_is_terminal(@impl)
+      end
+
+      def to_s
+        "fileno=#{self.fileno} registered=#{self.registered?} terminal=#{self.terminal?}"
+      end
+
+      def free
+        return if @freed
+        @freed = true
+        @messenger.unregister_selectable(fileno)
+        @io.close unless @io.nil?
+        Cproton.pn_selectable_free(@impl)
+        @impl = nil
+      end
+
+      def freed? # :nodoc:
+        @freed
+      end
+
+      private
+
+      def check_is_initialized
+        raise RuntimeError.new("selectable freed") if @impl.nil?
+      end
+
+    end
+
+  end
+
+end


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


[24/51] [abbrv] qpid-proton git commit: Update with merge of latest proton codebase and checked against latest emscripten incoming branch

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/TransportState.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/TransportState.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/TransportState.java
new file mode 100644
index 0000000..4ebf21a
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/TransportState.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.api;
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public enum TransportState {
+    CREATED,
+    CONNECTING,
+    CONNECTED,
+    DISCONNECTING,
+    DISCONNECTED
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpHeader.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpHeader.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpHeader.java
new file mode 100644
index 0000000..de8a2cd
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpHeader.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.hawtdispatch.impl;
+
+import org.fusesource.hawtbuf.Buffer;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class AmqpHeader {
+
+    static final Buffer PREFIX = new Buffer(new byte[]{
+      'A', 'M', 'Q', 'P'
+    });
+
+    private Buffer buffer;
+
+    public AmqpHeader(){
+        this(new Buffer(new byte[]{
+          'A', 'M', 'Q', 'P', 0, 1, 0, 0
+        }));
+    }
+
+    public AmqpHeader(Buffer buffer){
+        setBuffer(buffer);
+    }
+
+    public int getProtocolId() {
+        return buffer.get(4) & 0xFF;
+    }
+    public void setProtocolId(int value) {
+        buffer.data[buffer.offset+4] = (byte) value;
+    }
+
+    public int getMajor() {
+        return buffer.get(5) & 0xFF;
+    }
+    public void setMajor(int value) {
+        buffer.data[buffer.offset+5] = (byte) value;
+    }
+
+    public int getMinor() {
+        return buffer.get(6) & 0xFF;
+    }
+    public void setMinor(int value) {
+        buffer.data[buffer.offset+6] = (byte) value;
+    }
+
+    public int getRevision() {
+        return buffer.get(7) & 0xFF;
+    }
+    public void setRevision(int value) {
+        buffer.data[buffer.offset+7] = (byte) value;
+    }
+
+    public Buffer getBuffer() {
+        return buffer;
+    }
+    public void setBuffer(Buffer value) {
+        if( !value.startsWith(PREFIX) || value.length()!=8 ) {
+            throw new IllegalArgumentException("Not an AMQP header buffer");
+        }
+        buffer = value.buffer();
+    }
+
+
+    @Override
+    public String toString() {
+        return buffer.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpListener.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpListener.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpListener.java
new file mode 100644
index 0000000..f372d99
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpListener.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.impl;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.transport.ErrorCondition;
+import org.apache.qpid.proton.engine.*;
+import org.fusesource.hawtdispatch.Task;
+
+import java.io.IOException;
+
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public class AmqpListener {
+
+    public Sasl processSaslConnect(ProtonJTransport protonTransport) {
+        return null;
+    }
+
+    public Sasl processSaslEvent(Sasl sasl) {
+        return sasl;
+    }
+
+    public void processRemoteOpen(Endpoint endpoint, Task onComplete) {
+        ErrorCondition condition = endpoint.getCondition();
+        condition.setCondition(Symbol.valueOf("error"));
+        condition.setDescription("Not supported");
+        endpoint.close();
+        onComplete.run();
+    }
+
+    public void processRemoteClose(Endpoint endpoint, Task onComplete) {
+        endpoint.close();
+        onComplete.run();
+    }
+
+    public void processDelivery(Delivery delivery){
+    }
+
+    public void processTransportConnected() {
+    }
+
+    public void processTransportFailure(IOException e) {
+        this.processFailure(e);
+    }
+
+    public void processFailure(Throwable e) {
+        e.printStackTrace();
+    }
+
+    public void processRefill() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpProtocolCodec.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpProtocolCodec.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpProtocolCodec.java
new file mode 100644
index 0000000..13ed1e3
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpProtocolCodec.java
@@ -0,0 +1,109 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.impl;
+
+import org.fusesource.hawtbuf.Buffer;
+import org.fusesource.hawtdispatch.transport.AbstractProtocolCodec;
+
+import java.io.IOException;
+
+/**
+ * A HawtDispatch protocol codec that encodes/decodes AMQP 1.0 frames.
+ *
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class AmqpProtocolCodec extends AbstractProtocolCodec {
+
+    int maxFrameSize = 4*1024*1024;
+
+    @Override
+    protected void encode(Object object) throws IOException {
+        nextWriteBuffer.write((Buffer) object);
+    }
+
+    @Override
+    protected Action initialDecodeAction() {
+        return new Action() {
+            public Object apply() throws IOException {
+                Buffer magic = readBytes(8);
+                if (magic != null) {
+                    nextDecodeAction = readFrameSize;
+                    return new AmqpHeader(magic);
+                } else {
+                    return null;
+                }
+            }
+        };
+    }
+
+    private final Action readFrameSize = new Action() {
+        public Object apply() throws IOException {
+            Buffer sizeBytes = peekBytes(4);
+            if (sizeBytes != null) {
+                int size = sizeBytes.bigEndianEditor().readInt();
+                if (size < 8) {
+                    throw new IOException(String.format("specified frame size %d is smaller than minimum frame size", size));
+                }
+                if( size > maxFrameSize ) {
+                    throw new IOException(String.format("specified frame size %d is larger than maximum frame size", size));
+                }
+
+                // TODO: check frame min and max size..
+                nextDecodeAction = readFrame(size);
+                return nextDecodeAction.apply();
+            } else {
+                return null;
+            }
+        }
+    };
+
+
+    private final Action readFrame(final int size) {
+        return new Action() {
+            public Object apply() throws IOException {
+                Buffer frameData = readBytes(size);
+                if (frameData != null) {
+                    nextDecodeAction = readFrameSize;
+                    return frameData;
+                } else {
+                    return null;
+                }
+            }
+        };
+    }
+
+    public int getReadBytesPendingDecode() {
+        return readBuffer.position() - readStart;
+    }
+
+    public void skipProtocolHeader() {
+        nextDecodeAction = readFrameSize;
+    }
+
+    public void readProtocolHeader() {
+        nextDecodeAction = initialDecodeAction();
+    }
+
+    public int getMaxFrameSize() {
+        return maxFrameSize;
+    }
+
+    public void setMaxFrameSize(int maxFrameSize) {
+        this.maxFrameSize = maxFrameSize;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpTransport.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpTransport.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpTransport.java
new file mode 100644
index 0000000..9ea048b
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpTransport.java
@@ -0,0 +1,587 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.hawtdispatch.impl;
+
+import org.apache.qpid.proton.hawtdispatch.api.AmqpConnectOptions;
+import org.apache.qpid.proton.hawtdispatch.api.Callback;
+import org.apache.qpid.proton.hawtdispatch.api.ChainedCallback;
+import org.apache.qpid.proton.hawtdispatch.api.TransportState;
+import org.apache.qpid.proton.engine.*;
+import org.apache.qpid.proton.engine.impl.ByteBufferUtils;
+import org.apache.qpid.proton.engine.impl.ProtocolTracer;
+import org.fusesource.hawtbuf.Buffer;
+import org.fusesource.hawtbuf.DataByteArrayOutputStream;
+import org.fusesource.hawtbuf.UTF8Buffer;
+import org.fusesource.hawtdispatch.*;
+import org.fusesource.hawtdispatch.transport.DefaultTransportListener;
+import org.fusesource.hawtdispatch.transport.SslTransport;
+import org.fusesource.hawtdispatch.transport.TcpTransport;
+import org.fusesource.hawtdispatch.transport.Transport;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+import static org.apache.qpid.proton.hawtdispatch.api.TransportState.*;
+import static org.fusesource.hawtdispatch.Dispatch.NOOP;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class AmqpTransport extends WatchBase {
+
+    private TransportState state = CREATED;
+
+    final DispatchQueue queue;
+    final ProtonJConnection connection;
+    Transport hawtdispatchTransport;
+    ProtonJTransport protonTransport;
+    Throwable failure;
+    CustomDispatchSource<Defer,LinkedList<Defer>> defers;
+
+    public static final EnumSet<EndpointState> ALL_SET = EnumSet.allOf(EndpointState.class);
+
+    private AmqpTransport(DispatchQueue queue) {
+        this.queue = queue;
+        this.connection = (ProtonJConnection) Connection.Factory.create();
+
+        defers = Dispatch.createSource(EventAggregators.<Defer>linkedList(), this.queue);
+        defers.setEventHandler(new Task(){
+            public void run() {
+                for( Defer defer: defers.getData() ) {
+                    assert defer.defered = true;
+                    defer.defered = false;
+                    defer.run();
+                }
+            }
+        });
+        defers.resume();
+    }
+
+    static public AmqpTransport connect(AmqpConnectOptions options) {
+        AmqpConnectOptions opts = options.clone();
+        if( opts.getDispatchQueue() == null ) {
+            opts.setDispatchQueue(Dispatch.createQueue());
+        }
+        if( opts.getBlockingExecutor() == null ) {
+            opts.setBlockingExecutor(AmqpConnectOptions.getBlockingThreadPool());
+        }
+        return new AmqpTransport(opts.getDispatchQueue()).connecting(opts);
+    }
+
+    private AmqpTransport connecting(final AmqpConnectOptions options) {
+        assert state == CREATED;
+        try {
+            state = CONNECTING;
+            if( options.getLocalContainerId()!=null ) {
+                connection.setLocalContainerId(options.getLocalContainerId());
+            }
+            if( options.getRemoteContainerId()!=null ) {
+                connection.setContainer(options.getRemoteContainerId());
+            }
+            connection.setHostname(options.getHost().getHost());
+            Callback<Void> onConnect = new Callback<Void>() {
+                @Override
+                public void onSuccess(Void value) {
+                    if( state == CONNECTED ) {
+                        hawtdispatchTransport.setTransportListener(new AmqpTransportListener());
+                        fireWatches();
+                    }
+                }
+
+                @Override
+                public void onFailure(Throwable value) {
+                    if( state == CONNECTED || state == CONNECTING ) {
+                        failure = value;
+                        disconnect();
+                        fireWatches();
+                    }
+                }
+            };
+            if( options.getUser()!=null ) {
+                onConnect = new SaslClientHandler(options, onConnect);
+            }
+            createTransport(options, onConnect);
+        } catch (Throwable e) {
+            failure = e;
+        }
+        fireWatches();
+        return this;
+    }
+
+    public TransportState getState() {
+        return state;
+    }
+
+    /**
+     * Creates and start a transport to the AMQP server.  Passes it to the onConnect
+     * once the transport is connected.
+     *
+     * @param onConnect
+     * @throws Exception
+     */
+    void createTransport(AmqpConnectOptions options, final Callback<Void> onConnect) throws Exception {
+        final TcpTransport transport;
+        if( options.getSslContext() !=null ) {
+            SslTransport ssl = new SslTransport();
+            ssl.setSSLContext(options.getSslContext());
+            transport = ssl;
+        } else {
+            transport = new TcpTransport();
+        }
+
+        URI host = options.getHost();
+        if( host.getPort() == -1 ) {
+            if( options.getSslContext()!=null ) {
+                host = new URI(host.getScheme()+"://"+host.getHost()+":5672");
+            } else {
+                host = new URI(host.getScheme()+"://"+host.getHost()+":5671");
+            }
+        }
+
+
+        transport.setBlockingExecutor(options.getBlockingExecutor());
+        transport.setDispatchQueue(options.getDispatchQueue());
+
+        transport.setMaxReadRate(options.getMaxReadRate());
+        transport.setMaxWriteRate(options.getMaxWriteRate());
+        transport.setReceiveBufferSize(options.getReceiveBufferSize());
+        transport.setSendBufferSize(options.getSendBufferSize());
+        transport.setTrafficClass(options.getTrafficClass());
+        transport.setUseLocalHost(options.isUseLocalHost());
+        transport.connecting(host, options.getLocalAddress());
+
+        transport.setTransportListener(new DefaultTransportListener(){
+            public void onTransportConnected() {
+                if(state==CONNECTING) {
+                    state = CONNECTED;
+                    onConnect.onSuccess(null);
+                    transport.resumeRead();
+                }
+            }
+
+            public void onTransportFailure(final IOException error) {
+                if(state==CONNECTING) {
+                    onConnect.onFailure(error);
+                }
+            }
+
+        });
+        transport.connecting(host, options.getLocalAddress());
+        bind(transport);
+        transport.start(NOOP);
+    }
+
+    class SaslClientHandler extends ChainedCallback<Void, Void> {
+
+        private final AmqpConnectOptions options;
+
+        public SaslClientHandler(AmqpConnectOptions options, Callback<Void> next) {
+            super(next);
+            this.options = options;
+        }
+
+        public void onSuccess(final Void value) {
+            final Sasl s = protonTransport.sasl();
+            s.client();
+            pumpOut();
+            hawtdispatchTransport.setTransportListener(new AmqpTransportListener() {
+
+                Sasl sasl = s;
+
+                @Override
+                void process() {
+                    if (sasl != null) {
+                        sasl = processSaslEvent(sasl);
+                        if (sasl == null) {
+                            // once sasl handshake is done.. we need to read the protocol header again.
+                            ((AmqpProtocolCodec) hawtdispatchTransport.getProtocolCodec()).readProtocolHeader();
+                        }
+                    }
+                }
+
+                @Override
+                public void onTransportFailure(IOException error) {
+                    next.onFailure(error);
+                }
+
+                @Override
+                void onFailure(Throwable error) {
+                    next.onFailure(error);
+                }
+
+                boolean authSent = false;
+
+                private Sasl processSaslEvent(Sasl sasl) {
+                    if (sasl.getOutcome() == Sasl.SaslOutcome.PN_SASL_OK) {
+                        next.onSuccess(null);
+                        return null;
+                    }
+                    HashSet<String> mechanisims = new HashSet<String>(Arrays.asList(sasl.getRemoteMechanisms()));
+                    if (!authSent && !mechanisims.isEmpty()) {
+                        if (mechanisims.contains("PLAIN")) {
+                            authSent = true;
+                            DataByteArrayOutputStream os = new DataByteArrayOutputStream();
+                            try {
+                                os.writeByte(0);
+                                os.write(new UTF8Buffer(options.getUser()));
+                                os.writeByte(0);
+                                if (options.getPassword() != null) {
+                                    os.write(new UTF8Buffer(options.getPassword()));
+                                }
+                            } catch (IOException e) {
+                                throw new RuntimeException(e);
+                            }
+                            Buffer buffer = os.toBuffer();
+                            sasl.setMechanisms(new String[]{"PLAIN"});
+                            sasl.send(buffer.data, buffer.offset, buffer.length);
+                        } else if (mechanisims.contains("ANONYMOUS")) {
+                            authSent = true;
+                            sasl.setMechanisms(new String[]{"ANONYMOUS"});
+                            sasl.send(new byte[0], 0, 0);
+                        } else {
+                            next.onFailure(Support.illegalState("Remote does not support plain password authentication."));
+                            return null;
+                        }
+                    }
+                    return sasl;
+                }
+            });
+        }
+    }
+
+    class SaslServerListener extends AmqpTransportListener {
+        Sasl sasl;
+
+        @Override
+        public void onTransportCommand(Object command) {
+            try {
+                if (command.getClass() == AmqpHeader.class) {
+                    AmqpHeader header = (AmqpHeader)command;
+                    switch( header.getProtocolId() ) {
+                        case 3: // Client will be using SASL for auth..
+                            if( listener!=null ) {
+                                sasl = listener.processSaslConnect(protonTransport);
+                                break;
+                            }
+                        default:
+                            AmqpTransportListener listener = new AmqpTransportListener();
+                            hawtdispatchTransport.setTransportListener(listener);
+                            listener.onTransportCommand(command);
+                            return;
+                    }
+                    command = header.getBuffer();
+                }
+            } catch (Exception e) {
+                onFailure(e);
+            }
+            super.onTransportCommand(command);
+        }
+
+        @Override
+        void process() {
+            if (sasl != null) {
+                sasl = listener.processSaslEvent(sasl);
+            }
+            if (sasl == null) {
+                // once sasl handshake is done.. we need to read the protocol header again.
+                ((AmqpProtocolCodec) hawtdispatchTransport.getProtocolCodec()).readProtocolHeader();
+                hawtdispatchTransport.setTransportListener(new AmqpTransportListener());
+            }
+        }
+    }
+
+    static public AmqpTransport accept(Transport transport) {
+        return new AmqpTransport(transport.getDispatchQueue()).accepted(transport);
+    }
+
+    private AmqpTransport accepted(final Transport transport) {
+        state = CONNECTED;
+        bind(transport);
+        hawtdispatchTransport.setTransportListener(new SaslServerListener());
+        return this;
+    }
+
+    private void bind(final Transport transport) {
+        this.hawtdispatchTransport = transport;
+        this.protonTransport = (ProtonJTransport) org.apache.qpid.proton.engine.Transport.Factory.create();
+        this.protonTransport.bind(connection);
+        if( transport.getProtocolCodec()==null ) {
+            try {
+                transport.setProtocolCodec(new AmqpProtocolCodec());
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public void defer(Defer defer) {
+        if( !defer.defered ) {
+            defer.defered = true;
+            defers.merge(defer);
+        }
+    }
+
+    public void pumpOut() {
+        assertExecuting();
+        defer(deferedPumpOut);
+    }
+
+    private Defer deferedPumpOut = new Defer() {
+        public void run() {
+            doPumpOut();
+        }
+    };
+
+    private void doPumpOut() {
+        switch(state) {
+            case CONNECTING:
+            case CONNECTED:
+                break;
+            default:
+                return;
+        }
+
+        int size = hawtdispatchTransport.getProtocolCodec().getWriteBufferSize();
+        byte data[] = new byte[size];
+        boolean done = false;
+        int pumped = 0;
+        while( !done && !hawtdispatchTransport.full() ) {
+            int count = protonTransport.output(data, 0, size);
+            if( count > 0 ) {
+                pumped += count;
+                boolean accepted = hawtdispatchTransport.offer(new Buffer(data, 0, count));
+                assert accepted: "Should be accepted since the transport was not full";
+            } else {
+                done = true;
+            }
+        }
+        if( pumped > 0 && !hawtdispatchTransport.full() ) {
+            listener.processRefill();
+        }
+    }
+
+    public Sasl sasl;
+    public void fireListenerEvents() {
+        fireWatches();
+
+        if( sasl!=null ) {
+            sasl = listener.processSaslEvent(sasl);
+            if( sasl==null ) {
+                // once sasl handshake is done.. we need to read the protocol header again.
+                ((AmqpProtocolCodec)this.hawtdispatchTransport.getProtocolCodec()).readProtocolHeader();
+            }
+        }
+
+        context(connection).fireListenerEvents(listener);
+
+        Session session = connection.sessionHead(ALL_SET, ALL_SET);
+        while(session != null)
+        {
+            context(session).fireListenerEvents(listener);
+            session = session.next(ALL_SET, ALL_SET);
+        }
+
+        Link link = connection.linkHead(ALL_SET, ALL_SET);
+        while(link != null)
+        {
+            context(link).fireListenerEvents(listener);
+            link = link.next(ALL_SET, ALL_SET);
+        }
+
+        Delivery delivery = connection.getWorkHead();
+        while(delivery != null)
+        {
+            listener.processDelivery(delivery);
+            delivery = delivery.getWorkNext();
+        }
+
+        listener.processRefill();
+    }
+
+
+    public ProtonJConnection connection() {
+        return connection;
+    }
+
+    AmqpListener listener = new AmqpListener();
+    public AmqpListener getListener() {
+        return listener;
+    }
+
+    public void setListener(AmqpListener listener) {
+        this.listener = listener;
+    }
+
+    public EndpointContext context(Endpoint endpoint) {
+        EndpointContext context = (EndpointContext) endpoint.getContext();
+        if( context == null ) {
+            context = new EndpointContext(this, endpoint);
+            endpoint.setContext(context);
+        }
+        return context;
+    }
+
+    class AmqpTransportListener extends DefaultTransportListener {
+
+        @Override
+        public void onTransportConnected() {
+            if( listener!=null ) {
+                listener.processTransportConnected();
+            }
+        }
+
+        @Override
+        public void onRefill() {
+            if( listener!=null ) {
+                listener.processRefill();
+            }
+        }
+
+        @Override
+        public void onTransportCommand(Object command) {
+            if( state != CONNECTED ) {
+                return;
+            }
+            try {
+                Buffer buffer;
+                if (command.getClass() == AmqpHeader.class) {
+                    buffer = ((AmqpHeader) command).getBuffer();
+                } else {
+                    buffer = (Buffer) command;
+                }
+                ByteBuffer bbuffer = buffer.toByteBuffer();
+                do {
+                  ByteBuffer input = protonTransport.getInputBuffer();
+                  ByteBufferUtils.pour(bbuffer, input);
+                  protonTransport.processInput();
+                } while (bbuffer.remaining() > 0);
+                process();
+                pumpOut();
+            } catch (Exception e) {
+                onFailure(e);
+            }
+        }
+
+        void process() {
+            fireListenerEvents();
+        }
+
+        @Override
+        public void onTransportFailure(IOException error) {
+            if( state==CONNECTED ) {
+                failure = error;
+                if( listener!=null ) {
+                    listener.processTransportFailure(error);
+                    fireWatches();
+                }
+            }
+        }
+
+        void onFailure(Throwable error) {
+            failure = error;
+            if( listener!=null ) {
+                listener.processFailure(error);
+                fireWatches();
+            }
+        }
+    }
+
+    public void disconnect() {
+        assertExecuting();
+        if( state == CONNECTING || state==CONNECTED) {
+            state = DISCONNECTING;
+            if( hawtdispatchTransport!=null ) {
+                hawtdispatchTransport.stop(new Task(){
+                    public void run() {
+                        state = DISCONNECTED;
+                        hawtdispatchTransport = null;
+                        protonTransport = null;
+                        fireWatches();
+                    }
+                });
+            }
+        }
+    }
+
+    public DispatchQueue queue() {
+        return queue;
+    }
+
+    public void assertExecuting() {
+        queue().assertExecuting();
+    }
+
+    public void onTransportConnected(final Callback<Void> cb) {
+        addWatch(new Watch() {
+            @Override
+            public boolean execute() {
+                if( failure !=null ) {
+                    cb.onFailure(failure);
+                    return true;
+                }
+                if( state!=CONNECTING ) {
+                    cb.onSuccess(null);
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    public void onTransportDisconnected(final Callback<Void> cb) {
+        addWatch(new Watch() {
+            @Override
+            public boolean execute() {
+                if( state==DISCONNECTED ) {
+                    cb.onSuccess(null);
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    public void onTransportFailure(final Callback<Throwable> cb) {
+        addWatch(new Watch() {
+            @Override
+            public boolean execute() {
+                if( failure!=null ) {
+                    cb.onSuccess(failure);
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    public Throwable getFailure() {
+        return failure;
+    }
+
+    public void setProtocolTracer(ProtocolTracer protocolTracer) {
+        protonTransport.setProtocolTracer(protocolTracer);
+    }
+
+    public ProtocolTracer getProtocolTracer() {
+        return protonTransport.getProtocolTracer();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Defer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Defer.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Defer.java
new file mode 100644
index 0000000..eee8241
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Defer.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.impl;
+
+import org.fusesource.hawtdispatch.Task;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+abstract public class Defer extends Task {
+    boolean defered;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/EndpointContext.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/EndpointContext.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/EndpointContext.java
new file mode 100644
index 0000000..c12a849
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/EndpointContext.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.impl;
+
+import org.apache.qpid.proton.engine.Endpoint;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.fusesource.hawtdispatch.Task;
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public class EndpointContext {
+
+    private final AmqpTransport transport;
+    private final Endpoint endpoint;
+    private Object attachment;
+    boolean listenerProcessing;
+
+    public EndpointContext(AmqpTransport transport, Endpoint endpoint) {
+        this.transport = transport;
+        this.endpoint = endpoint;
+    }
+
+    class ProcessedTask extends Task {
+        @Override
+        public void run() {
+            transport.assertExecuting();
+            listenerProcessing = false;
+            transport.pumpOut();
+        }
+    }
+
+    public void fireListenerEvents(AmqpListener listener) {
+        if( listener!=null && !listenerProcessing ) {
+            if( endpoint.getLocalState() == EndpointState.UNINITIALIZED &&
+                endpoint.getRemoteState() != EndpointState.UNINITIALIZED ) {
+                listenerProcessing = true;
+                listener.processRemoteOpen(endpoint, new ProcessedTask());
+            } else if( endpoint.getLocalState() == EndpointState.ACTIVE &&
+                endpoint.getRemoteState() == EndpointState.CLOSED ) {
+                listenerProcessing = true;
+                listener.processRemoteClose(endpoint, new ProcessedTask());
+            }
+        }
+        if( attachment !=null && attachment instanceof Task ) {
+            ((Task) attachment).run();
+        }
+    }
+
+    public Object getAttachment() {
+        return attachment;
+    }
+
+    public <T> T getAttachment(Class<T> clazz) {
+        return clazz.cast(getAttachment());
+    }
+
+    public void setAttachment(Object attachment) {
+        this.attachment = attachment;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Support.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Support.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Support.java
new file mode 100644
index 0000000..8d6f83b
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Support.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.impl;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class Support {
+
+    public static IllegalStateException illegalState(String msg) {
+        return (IllegalStateException) new IllegalStateException(msg).fillInStackTrace();
+    }
+
+    public static IllegalStateException createUnhandledEventError() {
+        return illegalState("Unhandled event.");
+    }
+
+    public static IllegalStateException createListenerNotSetError() {
+        return illegalState("No connection listener set to handle message received from the server.");
+    }
+
+    public static IllegalStateException createDisconnectedError() {
+        return illegalState("Disconnected");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Watch.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Watch.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Watch.java
new file mode 100644
index 0000000..6bb7603
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/Watch.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.impl;
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public abstract class Watch {
+    /* returns true if the watch has been triggered */
+    public abstract boolean execute();
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/WatchBase.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/WatchBase.java b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/WatchBase.java
new file mode 100644
index 0000000..a4b1591
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/WatchBase.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.proton.hawtdispatch.impl;
+
+import org.fusesource.hawtdispatch.Dispatch;
+import org.fusesource.hawtdispatch.Task;
+
+import java.util.LinkedList;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+abstract public class WatchBase {
+
+    private LinkedList<Watch> watches = new LinkedList<Watch>();
+    protected void addWatch(final Watch task) {
+        watches.add(task);
+        fireWatches();
+    }
+
+    protected void fireWatches() {
+        if( !this.watches.isEmpty() ) {
+            Dispatch.getCurrentQueue().execute(new Task(){
+                @Override
+                public void run() {
+                    // Lets see if any of the watches are triggered.
+                    LinkedList<Watch> tmp = watches;
+                    watches = new LinkedList<Watch>();
+                    for (Watch task : tmp) {
+                        if( !task.execute() ) {
+                            watches.add(task);
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/test/java/org/apache/qpid/proton/hawtdispatch/api/SampleTest.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/test/java/org/apache/qpid/proton/hawtdispatch/api/SampleTest.java b/contrib/proton-hawtdispatch/src/test/java/org/apache/qpid/proton/hawtdispatch/api/SampleTest.java
new file mode 100644
index 0000000..7cbed14
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/test/java/org/apache/qpid/proton/hawtdispatch/api/SampleTest.java
@@ -0,0 +1,292 @@
+package org.apache.qpid.proton.hawtdispatch.api;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.net.URISyntaxException;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.qpid.proton.amqp.messaging.Source;
+import org.apache.qpid.proton.amqp.messaging.Target;
+import org.apache.qpid.proton.amqp.transport.DeliveryState;
+import org.apache.qpid.proton.amqp.transport.ErrorCondition;
+import org.apache.qpid.proton.hawtdispatch.test.MessengerServer;
+import org.apache.qpid.proton.message.Message;
+import org.fusesource.hawtdispatch.Task;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+/**
+ * Hello world!
+ *
+ */
+
+public class SampleTest {
+
+	private static final Logger _logger = Logger.getLogger(SampleTest.class.getName());
+
+	private MessengerServer server;
+
+	@Before
+	public void startServer() {
+		server = new MessengerServer();
+		server.start();
+	}
+
+	@After
+	public void stopServer() {
+		server.stop();
+	}
+
+	@Test
+	public void test() throws Exception {
+		int expected = 10;
+		final AtomicInteger countdown = new AtomicInteger(expected);
+		AmqpConnectOptions options = new AmqpConnectOptions();
+		final String container = UUID.randomUUID().toString();
+		try {
+			options.setHost(server.getHost(), server.getPort());
+			options.setLocalContainerId(container);
+			options.setUser("anonymous");
+			options.setPassword("changeit");
+		} catch (URISyntaxException e) {
+			e.printStackTrace();
+		}
+		final AmqpConnection conn = AmqpConnection.connect(options );
+		_logger.fine("connection queue");
+		conn.queue().execute(new Task() {
+
+			@Override
+			public void run() {
+				_logger.fine("connection running, setup callbacks");
+				conn.onTransportFailure(new Callback<Throwable>() {
+
+					@Override
+					public void onSuccess(Throwable value) {
+						_logger.fine("transportFailure Success? " + str(value));
+						conn.close();
+					}
+
+					@Override
+					public void onFailure(Throwable value) {
+						_logger.fine("transportFailure Trouble! " + str(value));
+						conn.close();
+					}
+				});
+
+				conn.onConnected(new Callback<Void>() {
+
+					@Override
+					public void onSuccess(Void value) {
+						_logger.fine("on connect Success! in container " + container);
+						final AmqpSession session = conn.createSession();
+						Target rqtarget = new Target();
+						rqtarget.setAddress("rq-tgt");
+						final AmqpSender sender = session.createSender(rqtarget, QoS.AT_LEAST_ONCE, "request-yyy");
+						Source rqsource = new Source();
+						rqsource.setAddress("rs-src");
+						sender.getEndpoint().setSource(rqsource);
+						Source rssource = new Source();
+						rssource.setAddress("rs-src");
+						final AmqpReceiver receiver = session.createReceiver(rssource , QoS.AT_LEAST_ONCE, 10, "response-yyy");
+						Target rstarget = new Target();
+						final String address = "rs-tgt";
+						rstarget.setAddress(address);
+						receiver.getEndpoint().setTarget(rstarget);
+						sender.onRemoteClose(new Callback<ErrorCondition>() {
+
+							@Override
+							public void onSuccess(ErrorCondition value) {
+								_logger.fine("sender remote close!" + str(value));
+							}
+
+							@Override
+							public void onFailure(Throwable value) {
+								_logger.fine("sender remote close Trouble!" + str(value));
+								conn.close();
+
+							}
+
+						});
+						receiver.onRemoteClose(new Callback<ErrorCondition>() {
+
+							@Override
+							public void onSuccess(ErrorCondition value) {
+								_logger.fine("receiver remote close!" + str(value));
+							}
+
+							@Override
+							public void onFailure(Throwable value) {
+								_logger.fine("receiver remote close Trouble!" + str(value));
+								conn.close();
+
+							}
+
+						});
+
+						final Task work = new Task() {
+
+							private AtomicInteger count = new AtomicInteger();
+
+							@Override
+							public void run() {
+								Message message = session.createTextMessage("hello world! " + String.valueOf(count.incrementAndGet()));
+								message.setAddress("amqp://joze/rq-src");
+								String reply_to = "amqp://" + container + "/" + address;
+								message.setReplyTo(reply_to);
+								message.setCorrelationId("correlator");
+								final MessageDelivery md = sender.send(message);
+								md.onRemoteStateChange(new Callback<DeliveryState>() {
+
+									@Override
+									public void onSuccess(DeliveryState value) {
+										_logger.fine("delivery remote state change! " + str(value) +
+												" local: "+ str(md.getLocalState()) +
+												" remote: " + str(md.getRemoteState()));
+									}
+
+									@Override
+									public void onFailure(Throwable value) {
+										_logger.fine("remote state change Trouble!" + str(value));
+										conn.close();
+									}
+
+								});
+								md.onSettle(new Callback<DeliveryState>() {
+
+									@Override
+									public void onSuccess(DeliveryState value) {
+										_logger.fine("delivery settled! " + str(value) +
+												" local: "+ str(md.getLocalState()) +
+												" remote: " + str(md.getRemoteState()));
+										_logger.fine("sender settle mode state " +
+												" local receiver " + str(sender.getEndpoint().getReceiverSettleMode()) +
+												" local sender " + str(sender.getEndpoint().getSenderSettleMode()) +
+												" remote receiver " + str(sender.getEndpoint().getRemoteReceiverSettleMode()) +
+												" remote sender " + str(sender.getEndpoint().getRemoteSenderSettleMode()) +
+												""
+												);
+									}
+
+									@Override
+									public void onFailure(Throwable value) {
+										_logger.fine("delivery sending Trouble!" + str(value));
+										conn.close();
+									}
+								});
+							}
+
+						};
+						receiver.setDeliveryListener(new AmqpDeliveryListener() {
+
+							@Override
+							public void onMessageDelivery(
+									MessageDelivery delivery) {
+								Message message = delivery.getMessage();
+								_logger.fine("incoming message delivery! " +
+										" local " + str(delivery.getLocalState()) +
+										" remote " + str(delivery.getRemoteState()) +
+										" message " + str(message.getBody()) +
+										"");
+								delivery.onSettle(new Callback<DeliveryState>() {
+
+									@Override
+									public void onSuccess(DeliveryState value) {
+										_logger.fine("incoming message settled! ");
+										int i = countdown.decrementAndGet();
+										if ( i > 0 ) {
+											_logger.fine("More work " + str(i));
+											work.run();
+										} else {
+											conn.queue().executeAfter(100, TimeUnit.MILLISECONDS, new Task() {
+
+												@Override
+												public void run() {
+													_logger.fine("stopping sender");
+													sender.close();												
+												}
+											});
+											conn.queue().executeAfter(200, TimeUnit.MILLISECONDS, new Task() {
+
+												@Override
+												public void run() {
+													_logger.fine("stopping receiver");
+													receiver.close();
+
+												}
+											});
+											conn.queue().executeAfter(300, TimeUnit.MILLISECONDS, new Task() {
+
+												@Override
+												public void run() {
+													_logger.fine("stopping session");
+													session.close();
+
+												}
+											});
+											conn.queue().executeAfter(400, TimeUnit.MILLISECONDS, new Task() {
+
+												@Override
+												public void run() {
+													_logger.fine("stopping connection");
+													conn.close();
+
+												}
+											});
+										}
+									}
+
+									@Override
+									public void onFailure(Throwable value) {
+										_logger.fine("trouble settling incoming message " + str(value));
+										conn.close();
+									}
+								});
+								delivery.settle();
+							}
+
+						});
+
+						// start the receiver
+						receiver.resume();
+
+						// send first message
+						conn.queue().execute(work);
+					}
+
+					@Override
+					public void onFailure(Throwable value) {
+						_logger.fine("on connect Failure?" + str(value));
+						conn.close();
+					}
+				});
+				_logger.fine("connection setup done");
+
+
+			}
+
+		});
+		try {
+			_logger.fine("Waiting...");
+			Future<Void> disconnectedFuture = conn.getDisconnectedFuture();
+			disconnectedFuture.await(10, TimeUnit.SECONDS);
+			_logger.fine("done");
+			assertEquals(expected, server.getMessagesReceived());
+		} catch (Exception e) {
+			_logger.log(Level.SEVERE, "Test failed, possibly due to timeout", e);
+			throw e;
+		}
+	}
+
+	private String str(Object value) {
+		if (value == null)
+			return "null";
+		return value.toString();
+	}
+
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-hawtdispatch/src/test/java/org/apache/qpid/proton/hawtdispatch/test/MessengerServer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-hawtdispatch/src/test/java/org/apache/qpid/proton/hawtdispatch/test/MessengerServer.java b/contrib/proton-hawtdispatch/src/test/java/org/apache/qpid/proton/hawtdispatch/test/MessengerServer.java
new file mode 100644
index 0000000..dae68b6
--- /dev/null
+++ b/contrib/proton-hawtdispatch/src/test/java/org/apache/qpid/proton/hawtdispatch/test/MessengerServer.java
@@ -0,0 +1,135 @@
+package org.apache.qpid.proton.hawtdispatch.test;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.qpid.proton.InterruptException;
+import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.messenger.Messenger;
+import org.apache.qpid.proton.messenger.Tracker;
+
+public class MessengerServer {
+	public static final String REJECT_ME = "*REJECT-ME*";
+	private int timeout = 1000;
+	private String host = "127.0.0.1";
+	private int port = 55555;
+	private Messenger msgr;
+	private AtomicInteger messagesReceived = new AtomicInteger(0);
+	private AtomicInteger messagesSent = new AtomicInteger(0);
+	private AtomicBoolean serverShouldRun = new AtomicBoolean();
+	private AtomicReference<Throwable> issues = new AtomicReference<Throwable>();
+	private Thread thread;
+	private CountDownLatch serverStart;
+
+	public MessengerServer() {
+	}
+	public void start() {
+		if (!serverShouldRun.compareAndSet(false, true)) {
+			throw new IllegalStateException("started twice");
+		}
+		msgr = Proton.messenger();
+		serverStart = new CountDownLatch(1);
+		thread = new Thread(new Runnable() {
+
+			@Override
+			public void run() {
+				try {
+					msgr.start();
+					msgr.subscribe("amqp://~"+host+":"+String.valueOf(port));
+					serverStart.countDown();
+					try {
+						while(serverShouldRun.get()) {
+							msgr.recv(100);
+							while (msgr.incoming() > 0) {
+								Message msg = msgr.get();
+								messagesReceived.incrementAndGet();
+								Tracker tracker = msgr.incomingTracker();
+								if (REJECT_ME.equals(msg.getBody())) {
+									msgr.reject(tracker , 0);
+								} else {
+									msgr.accept(tracker, 0);
+								}
+								String reply_to = msg.getReplyTo();
+								if (reply_to != null) {
+									msg.setAddress(reply_to);
+									msgr.put(msg);
+									msgr.settle(msgr.outgoingTracker(), 0);
+								}
+							}
+						}
+					} finally {
+						msgr.stop();
+					}
+				} catch (InterruptException ex) {
+					// we're done
+				} catch (Exception ex) {
+					issues.set(ex);
+				}
+			}
+
+		});
+		thread.setName("MessengerServer");
+		thread.setDaemon(true);
+		thread.start();
+		try {
+			serverStart.await();
+		} catch (InterruptedException e) {
+			msgr.interrupt();
+		}
+	}
+
+	public void stop() {
+		if (!serverShouldRun.compareAndSet(true, false)) {
+			return;
+		}
+		if (serverStart.getCount() == 0)
+			msgr.interrupt();
+		try {
+			thread.join(timeout);
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		thread = null;
+		if (!msgr.stopped())
+			msgr.stop();
+		Throwable throwable = issues.get();
+		if (throwable != null)
+			throw new RuntimeException("Messenger server had problems", throwable);
+	}
+
+	public String getHost() {
+		return host;
+	}
+
+	public int getPort() {
+		return port;
+	}
+
+	public void setHost(String host) {
+		this.host = host;
+	}
+
+	public void setPort(int port) {
+		this.port = port;
+	}
+	public int getTimeout() {
+		return timeout;
+	}
+	public void setTimeout(int timeout) {
+		this.timeout = timeout;
+	}
+
+	public int getMessagesReceived() {
+		return messagesReceived.get();
+	}
+
+	public int getMessagesSent() {
+		return messagesSent.get();
+	}
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/pom.xml b/contrib/proton-jms/pom.xml
new file mode 100644
index 0000000..4515cbb
--- /dev/null
+++ b/contrib/proton-jms/pom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>proton-project</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <relativePath>../..</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>proton-jms</artifactId>
+  <name>proton-jms</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>proton-j</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jms_1.1_spec</artifactId>
+      <version>1.1.1</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build> 
+  </build>
+  <scm>
+    <url>http://svn.apache.org/viewvc/qpid/proton/</url>
+  </scm>
+
+</project>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeInboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeInboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeInboundTransformer.java
new file mode 100644
index 0000000..4beb401
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeInboundTransformer.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.jms;
+
+import javax.jms.Message;
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public class AMQPNativeInboundTransformer extends AMQPRawInboundTransformer {
+
+
+    public AMQPNativeInboundTransformer(JMSVendor vendor) {
+        super(vendor);
+    }
+
+    @Override
+    public Message transform(EncodedMessage amqpMessage) throws Exception {
+        org.apache.qpid.proton.message.Message amqp = amqpMessage.decode();
+
+        Message rc = super.transform(amqpMessage);
+
+        populateMessage(rc, amqp);
+        return rc;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java
new file mode 100644
index 0000000..66ff0b1
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.jms;
+
+import org.apache.qpid.proton.codec.CompositeWritableBuffer;
+import org.apache.qpid.proton.codec.DroppingWritableBuffer;
+import org.apache.qpid.proton.codec.WritableBuffer;
+import org.apache.qpid.proton.amqp.UnsignedInteger;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageFormatException;
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.proton.message.ProtonJMessage;
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public class AMQPNativeOutboundTransformer extends OutboundTransformer {
+
+    public AMQPNativeOutboundTransformer(JMSVendor vendor) {
+        super(vendor);
+    }
+
+    @Override
+    public EncodedMessage transform(Message msg) throws Exception {
+        if( msg == null )
+            return null;
+        if( !(msg instanceof BytesMessage) )
+            return null;
+        try {
+            if( !msg.getBooleanProperty(prefixVendor + "NATIVE") ) {
+                return null;
+            }
+        } catch (MessageFormatException e) {
+            return null;
+        }
+        return transform(this, (BytesMessage) msg);
+    }
+
+    static EncodedMessage transform(OutboundTransformer options, BytesMessage msg) throws JMSException {
+        long messageFormat;
+        try {
+            messageFormat = msg.getLongProperty(options.prefixVendor + "MESSAGE_FORMAT");
+        } catch (MessageFormatException e) {
+            return null;
+        }
+        byte data[] = new byte[(int) msg.getBodyLength()];
+        int dataSize = data.length;
+        msg.readBytes(data);
+        msg.reset();
+
+        try {
+            int count = msg.getIntProperty("JMSXDeliveryCount");
+            if( count > 1 ) {
+
+                // decode...
+                ProtonJMessage amqp = (ProtonJMessage) org.apache.qpid.proton.message.Message.Factory.create();
+                int offset = 0;
+                int len = data.length;
+                while( len > 0 ) {
+                    final int decoded = amqp.decode(data, offset, len);
+                    assert decoded > 0: "Make progress decoding the message";
+                    offset += decoded;
+                    len -= decoded;
+                }
+
+                // Update the DeliveryCount header...
+                amqp.getHeader().setDeliveryCount(new UnsignedInteger(count));
+
+                // Re-encode...
+                ByteBuffer buffer = ByteBuffer.wrap(new byte[1024*4]);
+                final DroppingWritableBuffer overflow = new DroppingWritableBuffer();
+                int c = amqp.encode(new CompositeWritableBuffer(new WritableBuffer.ByteBufferWrapper(buffer), overflow));
+                if( overflow.position() > 0 ) {
+                    buffer = ByteBuffer.wrap(new byte[1024*4+overflow.position()]);
+                    c = amqp.encode(new WritableBuffer.ByteBufferWrapper(buffer));
+                }
+                data = buffer.array();
+                dataSize = c;
+            }
+        } catch (JMSException e) {
+        }
+
+        return new EncodedMessage(messageFormat, data, 0, dataSize);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPRawInboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPRawInboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPRawInboundTransformer.java
new file mode 100644
index 0000000..9baabdf
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPRawInboundTransformer.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.jms;
+
+import javax.jms.BytesMessage;
+import javax.jms.Message;
+
+public class AMQPRawInboundTransformer extends InboundTransformer {
+
+    public AMQPRawInboundTransformer(JMSVendor vendor) {
+        super(vendor);
+    }
+
+    @Override
+    public Message transform(EncodedMessage amqpMessage) throws Exception {
+        BytesMessage rc = vendor.createBytesMessage();
+        rc.writeBytes(amqpMessage.getArray(), amqpMessage.getArrayOffset(), amqpMessage.getLength());
+
+        rc.setJMSDeliveryMode(defaultDeliveryMode);
+        rc.setJMSPriority(defaultPriority);
+
+        final long now = System.currentTimeMillis();
+        rc.setJMSTimestamp(now);
+        if( defaultTtl > 0 ) {
+            rc.setJMSExpiration(now + defaultTtl);
+        }
+
+        rc.setLongProperty(prefixVendor + "MESSAGE_FORMAT", amqpMessage.getMessageFormat());
+        rc.setBooleanProperty(prefixVendor + "NATIVE", true);
+
+        return rc;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AutoOutboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AutoOutboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AutoOutboundTransformer.java
new file mode 100644
index 0000000..a72198b
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AutoOutboundTransformer.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.jms;
+
+import javax.jms.BytesMessage;
+import javax.jms.Message;
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public class AutoOutboundTransformer extends JMSMappingOutboundTransformer {
+
+    public AutoOutboundTransformer(JMSVendor vendor) {
+        super(vendor);
+    }
+
+    @Override
+    public EncodedMessage transform(Message msg) throws Exception {
+        if( msg == null )
+            return null;
+        if( msg.getBooleanProperty(prefixVendor + "NATIVE") ) {
+            if( msg instanceof BytesMessage ) {
+                return AMQPNativeOutboundTransformer.transform(this, (BytesMessage)msg);
+            } else {
+                return null;
+            }
+        } else {
+            return JMSMappingOutboundTransformer.transform(this, msg);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/EncodedMessage.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/EncodedMessage.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/EncodedMessage.java
new file mode 100644
index 0000000..19602c9
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/EncodedMessage.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.jms;
+
+import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.amqp.Binary;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+public class EncodedMessage
+{
+
+    private final Binary data;
+    final long messageFormat;
+
+    public EncodedMessage(long messageFormat, byte[] data, int offset, int length) {
+        this.data = new Binary(data, offset, length);
+        this.messageFormat = messageFormat;
+    }
+
+    public long getMessageFormat() {
+        return messageFormat;
+    }
+
+    public Message decode() throws Exception {
+        Message amqp = Message.Factory.create();
+
+        int offset = getArrayOffset();
+        int len = getLength();
+        while( len > 0 ) {
+            final int decoded = amqp.decode(getArray(), offset, len);
+            assert decoded > 0: "Make progress decoding the message";
+            offset += decoded;
+            len -= decoded;
+        }
+
+        return amqp;
+    }
+
+    public int getLength()
+    {
+        return data.getLength();
+    }
+
+    public int getArrayOffset()
+    {
+        return data.getArrayOffset();
+    }
+
+    public byte[] getArray()
+    {
+        return data.getArray();
+    }
+
+    @Override
+    public String toString()
+    {
+        return data.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/InboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/InboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/InboundTransformer.java
new file mode 100644
index 0000000..0374e6a
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/InboundTransformer.java
@@ -0,0 +1,314 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.jms;
+
+import org.apache.qpid.proton.amqp.*;
+import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
+import org.apache.qpid.proton.amqp.messaging.DeliveryAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Footer;
+import org.apache.qpid.proton.amqp.messaging.Header;
+import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Properties;
+
+import javax.jms.*;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Queue;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public abstract class InboundTransformer {
+
+    JMSVendor vendor;
+
+    public static final String TRANSFORMER_NATIVE = "native";
+    public static final String TRANSFORMER_RAW = "raw";
+    public static final String TRANSFORMER_JMS = "jms";
+
+    String prefixVendor = "JMS_AMQP_";
+    String prefixDeliveryAnnotations = "DA_";
+    String prefixMessageAnnotations= "MA_";
+    String prefixFooter = "FT_";
+
+    int defaultDeliveryMode = javax.jms.Message.DEFAULT_DELIVERY_MODE;
+    int defaultPriority = javax.jms.Message.DEFAULT_PRIORITY;
+    long defaultTtl = javax.jms.Message.DEFAULT_TIME_TO_LIVE;
+
+    public InboundTransformer(JMSVendor vendor) {
+        this.vendor = vendor;
+    }
+
+    abstract public Message transform(EncodedMessage amqpMessage) throws Exception;
+
+    public int getDefaultDeliveryMode() {
+        return defaultDeliveryMode;
+    }
+
+    public void setDefaultDeliveryMode(int defaultDeliveryMode) {
+        this.defaultDeliveryMode = defaultDeliveryMode;
+    }
+
+    public int getDefaultPriority() {
+        return defaultPriority;
+    }
+
+    public void setDefaultPriority(int defaultPriority) {
+        this.defaultPriority = defaultPriority;
+    }
+
+    public long getDefaultTtl() {
+        return defaultTtl;
+    }
+
+    public void setDefaultTtl(long defaultTtl) {
+        this.defaultTtl = defaultTtl;
+    }
+
+    public String getPrefixVendor() {
+        return prefixVendor;
+    }
+
+    public void setPrefixVendor(String prefixVendor) {
+        this.prefixVendor = prefixVendor;
+    }
+
+    public JMSVendor getVendor() {
+        return vendor;
+    }
+
+    public void setVendor(JMSVendor vendor) {
+        this.vendor = vendor;
+    }
+
+    protected void populateMessage(Message jms, org.apache.qpid.proton.message.Message amqp) throws Exception {
+        Header header = amqp.getHeader();
+        if( header==null ) {
+            header = new Header();
+        }
+
+        if( header.getDurable()!=null ) {
+            jms.setJMSDeliveryMode(header.getDurable().booleanValue() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
+        } else {
+            jms.setJMSDeliveryMode(defaultDeliveryMode);
+        }
+        if( header.getPriority()!=null ) {
+            jms.setJMSPriority(header.getPriority().intValue());
+        } else {
+            jms.setJMSPriority(defaultPriority);
+        }
+        if( header.getFirstAcquirer() !=null ) {
+            jms.setBooleanProperty(prefixVendor + "FirstAcquirer", header.getFirstAcquirer());
+        }
+        if( header.getDeliveryCount()!=null ) {
+            vendor.setJMSXDeliveryCount(jms, header.getDeliveryCount().longValue());
+        }
+
+        final DeliveryAnnotations da = amqp.getDeliveryAnnotations();
+        if( da!=null ) {
+            for (Map.Entry<?,?> entry : da.getValue().entrySet()) {
+                String key = entry.getKey().toString();
+                setProperty(jms, prefixVendor + prefixDeliveryAnnotations + key, entry.getValue());
+            }
+        }
+
+        Class<? extends Destination> toAttributes = Destination.class;
+        Class<? extends Destination> replyToAttributes = Destination.class;
+
+        final MessageAnnotations ma = amqp.getMessageAnnotations();
+        if( ma!=null ) {
+            for (Map.Entry<?,?> entry : ma.getValue().entrySet()) {
+                String key = entry.getKey().toString();
+                if( "x-opt-jms-type".equals(key.toString()) && entry.getValue() != null ) {
+                    jms.setJMSType(entry.getValue().toString());
+                } else if( "x-opt-to-type".equals(key.toString()) ) {
+                    toAttributes = toClassFromAttributes(entry.getValue().toString());
+                } else if( "x-opt-reply-type".equals(key.toString()) ) {
+                    replyToAttributes = toClassFromAttributes(entry.getValue().toString());
+                } else {
+                    setProperty(jms, prefixVendor + prefixMessageAnnotations + key, entry.getValue());
+                }
+            }
+        }
+
+        final ApplicationProperties ap = amqp.getApplicationProperties();
+        if( ap !=null ) {
+            for (Map.Entry entry : (Set<Map.Entry>)ap.getValue().entrySet()) {
+                String key = entry.getKey().toString();
+                if( "JMSXGroupID".equals(key) ) {
+                    vendor.setJMSXGroupID(jms, entry.getValue().toString());
+                } else if( "JMSXGroupSequence".equals(key) ) {
+                    vendor.setJMSXGroupSequence(jms, ((Number)entry.getValue()).intValue());
+                } else if( "JMSXUserID".equals(key) ) {
+                    vendor.setJMSXUserID(jms, entry.getValue().toString());
+                } else {
+                    setProperty(jms, key, entry.getValue());
+                }
+            }
+        }
+
+        final Properties properties = amqp.getProperties();
+        if( properties!=null ) {
+            if( properties.getMessageId()!=null ) {
+                jms.setJMSMessageID(properties.getMessageId().toString());
+            }
+            Binary userId = properties.getUserId();
+            if( userId!=null ) {
+                vendor.setJMSXUserID(jms, new String(userId.getArray(), userId.getArrayOffset(), userId.getLength(), "UTF-8"));
+            }
+            if( properties.getTo()!=null ) {
+                jms.setJMSDestination(vendor.createDestination(properties.getTo(), toAttributes));
+            }
+            if( properties.getSubject()!=null ) {
+                jms.setStringProperty(prefixVendor + "Subject", properties.getSubject());
+            }
+            if( properties.getReplyTo() !=null ) {
+                jms.setJMSReplyTo(vendor.createDestination(properties.getReplyTo(), replyToAttributes));
+            }
+            if( properties.getCorrelationId() !=null ) {
+                jms.setJMSCorrelationID(properties.getCorrelationId().toString());
+            }
+            if( properties.getContentType() !=null ) {
+                jms.setStringProperty(prefixVendor + "ContentType", properties.getContentType().toString());
+            }
+            if( properties.getContentEncoding() !=null ) {
+                jms.setStringProperty(prefixVendor + "ContentEncoding", properties.getContentEncoding().toString());
+            }
+            if( properties.getCreationTime()!=null ) {
+                jms.setJMSTimestamp(properties.getCreationTime().getTime());
+            }
+            if( properties.getGroupId()!=null ) {
+                vendor.setJMSXGroupID(jms, properties.getGroupId());
+            }
+            if( properties.getGroupSequence()!=null ) {
+                vendor.setJMSXGroupSequence(jms, properties.getGroupSequence().intValue());
+            }
+            if( properties.getReplyToGroupId()!=null ) {
+                jms.setStringProperty(prefixVendor + "ReplyToGroupID", properties.getReplyToGroupId());
+            }
+            if( properties.getAbsoluteExpiryTime()!=null ) {
+                jms.setJMSExpiration(properties.getAbsoluteExpiryTime().getTime());
+            }
+        }
+
+        // If the jms expiration has not yet been set...
+        if( jms.getJMSExpiration()==0 ) {
+            // Then lets try to set it based on the message ttl.
+            long ttl = defaultTtl;
+            if( header.getTtl()!=null ) {
+                ttl = header.getTtl().longValue();
+            }
+            if( ttl == 0 ) {
+              jms.setJMSExpiration(0);
+            } else {
+                jms.setJMSExpiration(System.currentTimeMillis()+ttl);
+            }
+        }
+
+        final Footer fp = amqp.getFooter();
+        if( fp !=null ) {
+            for (Map.Entry entry : (Set<Map.Entry>)fp.getValue().entrySet()) {
+                String key = entry.getKey().toString();
+                setProperty(jms, prefixVendor + prefixFooter + key, entry.getValue());
+            }
+        }
+    }
+
+    private static final Set<String> QUEUE_ATTRIBUTES = createSet("queue");
+    private static final Set<String> TOPIC_ATTRIBUTES = createSet("topic");
+    private static final Set<String> TEMP_QUEUE_ATTRIBUTES = createSet("queue", "temporary");
+    private static final Set<String> TEMP_TOPIC_ATTRIBUTES = createSet("topic", "temporary");
+
+    private static Set<String> createSet(String ... args) {
+        HashSet<String> s = new HashSet<String>();
+        for (String arg : args)
+        {
+            s.add(arg);
+        }
+        return Collections.unmodifiableSet(s);
+    }
+
+    Class<? extends Destination> toClassFromAttributes(String value)
+    {
+        if( value ==null ) {
+            return null;
+        }
+        HashSet<String> attributes = new HashSet<String>();
+        for( String x: value.split("\\s*,\\s*") ) {
+            attributes.add(x);
+        }
+
+        if( QUEUE_ATTRIBUTES.equals(attributes) ) {
+            return Queue.class;
+        }
+        if( TOPIC_ATTRIBUTES.equals(attributes) ) {
+            return Topic.class;
+        }
+        if( TEMP_QUEUE_ATTRIBUTES.equals(attributes) ) {
+            return TemporaryQueue.class;
+        }
+        if( TEMP_TOPIC_ATTRIBUTES.equals(attributes) ) {
+            return TemporaryTopic.class;
+        }
+        return Destination.class;
+    }
+
+
+    private void setProperty(Message msg, String key, Object value) throws JMSException {
+        if( value instanceof UnsignedLong) {
+            long v = ((UnsignedLong) value).longValue();
+            msg.setLongProperty(key, v);
+        } else if( value instanceof UnsignedInteger) {
+            long v = ((UnsignedInteger) value).longValue();
+            if( Integer.MIN_VALUE <= v && v <= Integer.MAX_VALUE ) {
+                msg.setIntProperty(key, (int) v);
+            } else {
+                msg.setLongProperty(key, v);
+            }
+        } else if( value instanceof UnsignedShort) {
+            int v = ((UnsignedShort) value).intValue();
+            if( Short.MIN_VALUE <= v && v <= Short.MAX_VALUE ) {
+                msg.setShortProperty(key, (short) v);
+            } else {
+                msg.setIntProperty(key, v);
+            }
+        } else if( value instanceof UnsignedByte) {
+            short v = ((UnsignedByte) value).shortValue();
+            if( Byte.MIN_VALUE <= v && v <= Byte.MAX_VALUE ) {
+                msg.setByteProperty(key, (byte) v);
+            } else {
+                msg.setShortProperty(key, v);
+            }
+        } else if( value instanceof Symbol) {
+            msg.setStringProperty(key, value.toString());
+        } else if( value instanceof Decimal128 ) {
+            msg.setDoubleProperty(key, ((Decimal128)value).doubleValue());
+        } else if( value instanceof Decimal64 ) {
+            msg.setDoubleProperty(key, ((Decimal64)value).doubleValue());
+        } else if( value instanceof Decimal32 ) {
+            msg.setFloatProperty(key, ((Decimal32)value).floatValue());
+        } else if( value instanceof Binary ) {
+            msg.setStringProperty(key, value.toString());
+        } else {
+            msg.setObjectProperty(key, value);
+        }
+    }
+}


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


[41/51] [abbrv] qpid-proton git commit: Sync with proton trunk revision 1627945 and update CMakeLists.txt

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/tests/python/proton_tests/url.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/url.py b/tests/python/proton_tests/url.py
new file mode 100644
index 0000000..477497e
--- /dev/null
+++ b/tests/python/proton_tests/url.py
@@ -0,0 +1,125 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+import common
+from proton import Url
+
+class UrlTest(common.Test):
+    def assertEqual(self, a, b):
+        assert a == b, "%s != %s" % (a, b)
+
+    def assertNotEqual(self, a, b):
+        assert a != b, "%s == %s" % (a, b)
+
+    def assertUrl(self, u, scheme, username, password, host, port, path):
+        self.assertEqual((u.scheme, u.username, u.password, u.host, u.port, u.path),
+                         (scheme, username, password, host, port, path))
+
+    def testUrl(self):
+        url = Url('amqp://me:secret@myhost:1234/foobar')
+        self.assertEqual(str(url), "amqp://me:secret@myhost:1234/foobar")
+        self.assertUrl(url, 'amqp', 'me', 'secret', 'myhost', 1234, 'foobar')
+        self.assertEqual(str(url), "amqp://me:secret@myhost:1234/foobar")
+
+    def testDefaults(self):
+        # Check that we allow None for scheme, port
+        url = Url(username='me', password='secret', host='myhost', path='foobar')
+        self.assertEqual(str(url), "me:secret@myhost/foobar")
+        self.assertUrl(url, None, 'me', 'secret', 'myhost', None, 'foobar')
+
+        self.assertEqual(str(Url("amqp://me:secret@myhost/foobar").defaults()),
+                         "amqp://me:secret@myhost:amqp/foobar")
+
+        # Empty string vs. None for path
+        self.assertEqual(Url("myhost/").path, "")
+        assert Url("myhost").path is None
+
+    def assertPort(self, port, portint, portstr):
+        self.assertEqual((port, port), (portint, portstr))
+        self.assertEqual((int(port), str(port)), (portint, portstr))
+
+    def testPort(self):
+        self.assertPort(Url.Port('amqp'), 5672, 'amqp')
+        self.assertPort(Url.Port(5672), 5672, '5672')
+        self.assertPort(Url.Port(5671), 5671, '5671')
+        self.assertEqual(Url.Port(5671)+1, 5672) # Treat as int
+        self.assertEqual(str(Url.Port(5672)), '5672')
+
+        self.assertPort(Url.Port(Url.Port('amqp')), 5672, 'amqp')
+        self.assertPort(Url.Port(Url.Port(5672)), 5672, '5672')
+
+        try:
+            Url.Port('xxx')
+            assert False, "Expected ValueError"
+        except ValueError: pass
+
+        self.assertEqual(str(Url("host:amqp")), "host:amqp")
+        self.assertEqual(Url("host:amqp").port, 5672)
+
+    def testArgs(self):
+        u = Url("amqp://u:p@host:amqp/path", scheme='foo', host='bar', port=1234, path='garden')
+        self.assertUrl(u, 'foo', 'u', 'p', 'bar', 1234, 'garden')
+        u = Url()
+        self.assertUrl(u, None, None, None, None, None, None)
+
+    def assertRaises(self, exception, function, *args, **kwargs):
+        try:
+            function(*args, **kwargs)
+            assert False, "Expected exception %s" % exception.__name__
+        except exception: pass
+
+    def testMissing(self):
+        self.assertUrl(Url(), None, None, None, None, None, None)
+        self.assertUrl(Url('amqp://'), 'amqp', None, None, None, None, None)
+        self.assertUrl(Url('username@'), None, 'username', None, None, None, None)
+        self.assertUrl(Url(':pass@'), None, '', 'pass', None, None, None)
+        self.assertUrl(Url('host'), None, None, None, 'host', None, None)
+        self.assertUrl(Url(':1234'), None, None, None, None, 1234, None)
+        self.assertUrl(Url('/path'), None, None, None, None, None, 'path')
+
+        for s in ['amqp://', 'username@', ':pass@', ':1234', '/path']:
+            self.assertEqual(s, str(Url(s)))
+
+        for s, full in [
+                ('amqp://', 'amqp://0.0.0.0:amqp'),
+                ('username@', 'amqp://username@0.0.0.0:amqp'),
+                (':pass@', 'amqp://:pass@0.0.0.0:amqp'),
+                (':1234', 'amqp://0.0.0.0:1234'),
+                ('/path', 'amqp://0.0.0.0:amqp/path')]:
+            self.assertEqual(str(Url(s).defaults()), full)
+
+    def testAmqps(self):
+        """Some old platforms don't recognize the amqps service name, this test is a no-op
+        if that is the case otherwise verify we treat amqps correctly."""
+        try:
+            Url.Port('amqps')
+        except ValueError:
+            print "skipping: service 'amqps' not recognized on this platform"
+            return
+        # Scheme defaults
+        self.assertEqual(str(Url("me:secret@myhost/foobar").defaults()),
+                         "amqp://me:secret@myhost:amqp/foobar")
+        # Correct port for amqps vs. amqps
+        self.assertEqual(str(Url("amqps://me:secret@myhost/foobar").defaults()),
+                         "amqps://me:secret@myhost:amqps/foobar")
+
+        self.assertPort(Url.Port('amqps'), 5671, 'amqps')
+        self.assertEqual(str(Url("host:amqps")), "host:amqps")
+        self.assertEqual(Url("host:amqps").port, 5671)


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


[40/51] [abbrv] qpid-proton git commit: Improve check for node.js in examples. Add mechanism for clients to increase stack as well as total memory - NB this feature requires emscripten fix only recently applied to incoming so may not be available in SDK

Posted by rh...@apache.org.
Improve check for node.js in examples. Add mechanism for clients to increase stack as well as total memory - NB this feature requires emscripten fix only recently applied to incoming so may not be available in SDK yet

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1627942 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d8ebc7f4
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d8ebc7f4
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d8ebc7f4

Branch: refs/heads/master
Commit: d8ebc7f4ade39d9266ea23568cfc126a1c0e1c9f
Parents: 2cf80a9
Author: fadams <fa...@unknown>
Authored: Sat Sep 27 10:13:43 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sat Sep 27 10:13:43 2014 +0000

----------------------------------------------------------------------
 examples/messenger/javascript/client.js      |  129 +-
 examples/messenger/javascript/drain.js       |   71 +-
 examples/messenger/javascript/proxy.js       |  111 +-
 examples/messenger/javascript/qpid-config.js | 2769 +++++++++++----------
 examples/messenger/javascript/recv.js        |   79 +-
 examples/messenger/javascript/send.html      |   11 +-
 examples/messenger/javascript/send.js        |  133 +-
 examples/messenger/javascript/server.js      |   99 +-
 examples/messenger/javascript/spout.js       |  130 +-
 proton-c/bindings/javascript/README          |   36 +-
 proton-c/bindings/javascript/messenger.js    |   11 +-
 proton-c/bindings/javascript/module.js       |   32 +-
 proton-c/bindings/javascript/subscription.js |   10 +-
 tests/javascript/codec.js                    | 1050 ++++----
 tests/javascript/message.js                  |  600 +++--
 tests/javascript/soak.js                     |  132 +-
 16 files changed, 2699 insertions(+), 2704 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/examples/messenger/javascript/client.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/client.js b/examples/messenger/javascript/client.js
index 5fae391..62f9a61 100644
--- a/examples/messenger/javascript/client.js
+++ b/examples/messenger/javascript/client.js
@@ -22,84 +22,83 @@
 // Simple client for use with server.js illustrating request/response
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("client.js should be run in Node.js");
-    return;
-}
-
-var proton = require("qpid-proton");
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
 
-var address = "amqp://0.0.0.0";
-var subject = "UK.WEATHER";
-var replyTo = "~/replies";
-var msgtext = "Hello World!";
-var tracker = null;
-var running = true;
+    var address = "amqp://0.0.0.0";
+    var subject = "UK.WEATHER";
+    var replyTo = "~/replies";
+    var msgtext = "Hello World!";
+    var tracker = null;
+    var running = true;
 
-var message = new proton.Message();
-var messenger = new proton.Messenger();
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
 
-var pumpData = function() {
-    while (messenger.incoming()) {
-        var t = messenger.get(message);
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            var t = messenger.get(message);
 
-        console.log("Reply");
-        console.log("Address: " + message.getAddress());
-        console.log("Subject: " + message.getSubject());
+            console.log("Reply");
+            console.log("Address: " + message.getAddress());
+            console.log("Subject: " + message.getSubject());
 
-        // body is the body as a native JavaScript Object, useful for most real cases.
-        //console.log("Content: " + message.body);
+            // body is the body as a native JavaScript Object, useful for most real cases.
+            //console.log("Content: " + message.body);
 
-        // data is the body as a proton.Data Object, used in this case because
-        // format() returns exactly the same representation as recv.c
-        console.log("Content: " + message.data.format());
+            // data is the body as a proton.Data Object, used in this case because
+            // format() returns exactly the same representation as recv.c
+            console.log("Content: " + message.data.format());
 
-        messenger.accept(t);
-        messenger.stop();
-    }
+            messenger.accept(t);
+            messenger.stop();
+        }
 
-    if (messenger.isStopped()) {
-        message.free();
-        messenger.free();
-    }
-};
-
-var args = process.argv.slice(2);
-if (args.length > 0) {
-    if (args[0] === '-h' || args[0] === '--help') {
-        console.log("Usage: node client.js [-r replyTo] [-s subject] <addr> (default " + address + ")");
-        console.log("Options:");
-        console.log("  -r <reply to> The message replyTo (default " + replyTo + ")");
-        console.log("  -s <subject> The message subject (default " + subject + ")");
-        process.exit(0);
-    }
+        if (messenger.isStopped()) {
+            message.free();
+            messenger.free();
+        }
+    };
+
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node client.js [-r replyTo] [-s subject] <addr> (default " + address + ")");
+            console.log("Options:");
+            console.log("  -r <reply to> The message replyTo (default " + replyTo + ")");
+            console.log("  -s <subject> The message subject (default " + subject + ")");
+            process.exit(0);
+        }
 
-    for (var i = 0; i < args.length; i++) {
-        var arg = args[i];
-        if (arg.charAt(0) === '-') {
-            i++;
-            var val = args[i];
-            if (arg === '-r') {
-                replyTo = val;
-            } else if (arg === '-s') {
-                subject = val;
+        for (var i = 0; i < args.length; i++) {
+            var arg = args[i];
+            if (arg.charAt(0) === '-') {
+                i++;
+                var val = args[i];
+                if (arg === '-r') {
+                    replyTo = val;
+                } else if (arg === '-s') {
+                    subject = val;
+                }
+            } else {
+                address = arg;
             }
-        } else {
-            address = arg;
         }
     }
-}
 
-messenger.on('error', function(error) {console.log(error);});
-messenger.on('work', pumpData);
-messenger.setOutgoingWindow(1024);
-messenger.start();
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.setOutgoingWindow(1024);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
 
-message.setAddress(address);
-message.setSubject(subject);
-message.setReplyTo(replyTo);
-message.body = msgtext;
+    message.setAddress(address);
+    message.setSubject(subject);
+    message.setReplyTo(replyTo);
+    message.body = msgtext;
 
-tracker = messenger.put(message);
-messenger.recv(); // Receive as many messages as messenger can buffer.
+    tracker = messenger.put(message);
+} else {
+    console.error("client.js should be run in Node.js");
+}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/examples/messenger/javascript/drain.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/drain.js b/examples/messenger/javascript/drain.js
index 20a7e83..04ced73 100644
--- a/examples/messenger/javascript/drain.js
+++ b/examples/messenger/javascript/drain.js
@@ -20,52 +20,51 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("drain.js should be run in Node.js");
-    return;
-}
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
 
-var proton = require("qpid-proton");
+    console.log("drain not implemented yet");
+    process.exit(0);
 
-console.log("drain not implemented yet");
-process.exit(0);
+    var address = "amqp://~0.0.0.0";
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
 
-var address = "amqp://~0.0.0.0";
-var message = new proton.Message();
-var messenger = new proton.Messenger();
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            var t = messenger.get(message);
 
-var pumpData = function() {
-    while (messenger.incoming()) {
-        var t = messenger.get(message);
+            console.log("Address: " + message.getAddress());
+            console.log("Subject: " + message.getSubject());
+    
+            // body is the body as a native JavaScript Object, useful for most real cases.
+            //console.log("Content: " + message.body);
 
-        console.log("Address: " + message.getAddress());
-        console.log("Subject: " + message.getSubject());
+            // data is the body as a proton.Data Object, used in this case because
+            // format() returns exactly the same representation as recv.c
+            console.log("Content: " + message.data.format());
 
-        // body is the body as a native JavaScript Object, useful for most real cases.
-        //console.log("Content: " + message.body);
+            messenger.accept(t);
+        }
+    };
 
-        // data is the body as a proton.Data Object, used in this case because
-        // format() returns exactly the same representation as recv.c
-        console.log("Content: " + message.data.format());
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: recv <addr> (default " + address + ").");
+            process.exit(0);
+        }
 
-        messenger.accept(t);
+        address = args[0];
     }
-};
 
-var args = process.argv.slice(2);
-if (args.length > 0) {
-    if (args[0] === '-h' || args[0] === '--help') {
-        console.log("Usage: recv <addr> (default " + address + ").");
-        process.exit(0);
-    }
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
 
-    address = args[0];
+    messenger.subscribe(address);
+} else {
+    console.error("drain.js should be run in Node.js");
 }
 
-messenger.on('error', function(error) {console.log(error);});
-messenger.on('work', pumpData);
-messenger.start();
-
-messenger.subscribe(address);
-messenger.recv(); // Receive as many messages as messenger can buffer.
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/examples/messenger/javascript/proxy.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/proxy.js b/examples/messenger/javascript/proxy.js
index 2a7866b..cac5cf5 100755
--- a/examples/messenger/javascript/proxy.js
+++ b/examples/messenger/javascript/proxy.js
@@ -36,71 +36,70 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("proxy.js should be run in Node.js");
-    return;
-}
-
-var proxy = require('./ws2tcp.js');
+if (typeof process === 'object' && typeof require === 'function') {
+    var proxy = require('./ws2tcp.js');
 
-var lport = 5673;
-var tport = lport - 1;
-var thost = '0.0.0.0';
-var method = 'ws2tcp';
+    var lport = 5673;
+    var tport = lport - 1;
+    var thost = '0.0.0.0';
+    var method = 'ws2tcp';
 
-var args = process.argv.slice(2);
-if (args.length > 0) {
-    if (args[0] === '-h' || args[0] === '--help') {
-        console.log("Usage: node proxy.js [options]");
-        console.log("Options:");
-        console.log("  -p <listen port>, --port  <listen port> (default " + lport + " for ws2tcp");
-        console.log("                                                   " + tport + " for tcp2ws)");
-        console.log("  -t <target port>, --tport <target port> (default listen port - 1 for ws2tcp");
-        console.log("                                                   listen port + 1 for tcp2ws)");
-        console.log("  -h <target host>, --thost <target host> (default " + thost + ")");
-        console.log("  -m <ws2tcp or tcp2ws>, --method <ws2tcp or tcp2ws> (default " + method + ")");
-        process.exit(0);
-    }
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node proxy.js [options]");
+            console.log("Options:");
+            console.log("  -p <listen port>, --port  <listen port> (default " + lport + " for ws2tcp");
+            console.log("                                                   " + tport + " for tcp2ws)");
+            console.log("  -t <target port>, --tport <target port> (default listen port - 1 for ws2tcp");
+            console.log("                                                   listen port + 1 for tcp2ws)");
+            console.log("  -h <target host>, --thost <target host> (default " + thost + ")");
+            console.log("  -m <ws2tcp or tcp2ws>, --method <ws2tcp or tcp2ws> (default " + method + ")");
+            process.exit(0);
+        }
 
-    var lportSet = false;
-    var tportSet = false;
-    for (var i = 0; i < args.length; i++) {
-        var arg = args[i];
-        if (arg.charAt(0) === '-') {
-            i++;
-            var val = args[i];
-            if (arg === '-p' || arg === '--port') {
-                lport = val;
-                lportSet = true;
-            } else if (arg === '-t' || arg === '--tport') {
-                tport = val;
-                tportSet = true;
-            } else if (arg === '-h' || arg === '--thost') {
-                thost = val;
-            } else if (arg === '-m' || arg === '--method') {
-                method = val;
+        var lportSet = false;
+        var tportSet = false;
+        for (var i = 0; i < args.length; i++) {
+            var arg = args[i];
+            if (arg.charAt(0) === '-') {
+                i++;
+                var val = args[i];
+                if (arg === '-p' || arg === '--port') {
+                    lport = val;
+                    lportSet = true;
+                } else if (arg === '-t' || arg === '--tport') {
+                    tport = val;
+                    tportSet = true;
+                } else if (arg === '-h' || arg === '--thost') {
+                    thost = val;
+                } else if (arg === '-m' || arg === '--method') {
+                    method = val;
+                }
             }
         }
-    }
 
-    if (method === 'tcp2ws' && !lportSet) {
-        lport--;
-    }
+        if (method === 'tcp2ws' && !lportSet) {
+            lport--;
+        }
 
-    if (!tportSet) {
-        tport = (method === 'ws2tcp') ? lport - 1 : +lport + 1;
+        if (!tportSet) {
+            tport = (method === 'ws2tcp') ? lport - 1 : +lport + 1;
+        }
     }
-}
 
-if (method === 'tcp2ws') {
-    console.log("Proxying tcp -> ws");
-    console.log("Forwarding port " + lport + " to " + thost + ":" + tport);
-    proxy.tcp2ws(lport, thost, tport, 'AMQPWSB10');
-} else if (method === 'ws2tcp') {
-    console.log("Proxying ws -> tcp");
-    console.log("Forwarding port " + lport + " to " + thost + ":" + tport);
-    proxy.ws2tcp(lport, thost, tport);
+    if (method === 'tcp2ws') {
+        console.log("Proxying tcp -> ws");
+        console.log("Forwarding port " + lport + " to " + thost + ":" + tport);
+        proxy.tcp2ws(lport, thost, tport, 'AMQPWSB10');
+    } else if (method === 'ws2tcp') {
+        console.log("Proxying ws -> tcp");
+        console.log("Forwarding port " + lport + " to " + thost + ":" + tport);
+        proxy.ws2tcp(lport, thost, tport);
+    } else {
+        console.error("Method must be either ws2tcp or tcp2ws.");
+    }
 } else {
-    console.error("Method must be either ws2tcp or tcp2ws.");
+    console.error("proxy.js should be run in Node.js");
 }
 


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


[04/51] [abbrv] qpid-proton git commit: Implement proton.Data.Binary and check end to end binary transfer, looks like it works OK but more testing needed

Posted by rh...@apache.org.
Implement proton.Data.Binary and check end to end binary transfer, looks like it works OK but more testing needed

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1588790 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/aa766d06
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/aa766d06
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/aa766d06

Branch: refs/heads/master
Commit: aa766d067e31c72fb988c3d7f0b1614ca487e293
Parents: 2448135
Author: fadams <fa...@unknown>
Authored: Sun Apr 20 16:46:08 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sun Apr 20 16:46:08 2014 +0000

----------------------------------------------------------------------
 proton-c/bindings/javascript/CMakeLists.txt |   3 +-
 proton-c/bindings/javascript/binding.js     | 180 +++++++++--------------
 proton-c/bindings/javascript/spout.js       |  10 +-
 3 files changed, 81 insertions(+), 112 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aa766d06/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index 19dc0a0..966d0ba 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -225,7 +225,8 @@ set_target_properties(
   LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_m
 essenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_
 put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get
 _binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
   )
 
-
+# If the docs target is specified and the jsdoc3 package for node.js has been
+# installed then build the JavaScript API documentation.
 if (NODE_JSDOC_FOUND)
     message(STATUS "Documentation Enabled")
     add_custom_target(docs-js COMMAND ${JSDOC_EXE}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aa766d06/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index 6559f11..41020e6 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -49,56 +49,6 @@ var Module = {
 };
 
 
-
-/**
- * This class is a buffer for use with the emscripten based port of zlib. It allows creation management of a 
- * buffer in the virtual heap space of the zlib library hiding the implementation detail from client code.
- */
-/*
-var Buffer = function(size) {
-    var _public = {};
-    var asize = 0; // The allocated size of the input buffer.
-    var ptr   = 0; // Handle to the input buffer.
-
-    // Private methods.
-    function freeBuffer() {
-        if (ptr !== 0) {
-            _free(ptr);
-        }
-    };
-
-    // Public methods
-    _public.destroy = function() {
-        freeBuffer();
-    };
-
-    _public.setSize = function(size) {
-        if (size > asize) {
-            freeBuffer();
-            ptr = _malloc(size); // Get output buffer from emscripten.
-            asize = size;
-        }
-        _public.size = size;
-    };
-
-    _public.getRaw = function() {
-        return ptr;
-    };
-
-    _public.getBuffer = function() {
-        // Get a Uint8Array view on the input buffer.
-        return new Uint8Array(HEAPU8.buffer, ptr, _public.size);
-    };
-
-    if (size) {
-        _public.setSize(size);
-    }
-
-    return _public;
-};
-*/
-
-
 /*****************************************************************************/
 /*                                                                           */
 /*                                   Status                                  */
@@ -1515,6 +1465,18 @@ Data.Long.prototype.toString = function() {
  * @param {number} start an optional data pointer to the start of the Binary data buffer.
  */
 Data['Binary'] = function(size, start) { // Data.Binary Constructor.
+    /*
+     * If the start pointer is specified then the underlying binary data is owned
+     * by another object, so we set the call to free to be a null function. If
+     * the start pointer is not passed then we allocate storage of the specified
+     * size on the emscripten heap and set the call to free to free the data from
+     * the emscripten heap. We have made the call to free a protected method that
+     * is only visible within the scope of the binding closure, clients should
+     * not have to call free themselves as the data is either already "owned" by
+     * a Data object or is destined to be passed to a Data object, which will in
+     * turn take responsibility for calling free once it has taken ownership of
+     * the underlying binary data.
+     */
     if (start) {
         this.free = function() {};
     } else {
@@ -1528,7 +1490,7 @@ Data['Binary'] = function(size, start) { // Data.Binary Constructor.
 
 /*
  * Get a Uint8Array view of the data. N.B. this is just a *view* of the data,
- * which will out of scope on the next call to {@link proton.Messenger.get}. If
+ * which will go out of scope on the next call to {@link proton.Messenger.get}. If
  * a client wants to retain the data then copyBuffer should be used to explicitly
  * create a copy of the data which the client then owns to do with as it wishes.
  * @method getBuffer
@@ -1956,11 +1918,34 @@ _Data_['putUUID'] = function(u) {
  * Puts a binary value.
  * @method putBinary
  * @memberof! proton.Data#
- * @param b a binary value.
+ * @param {proton.Data.Binary} b a binary value.
  */
-_Data_['putBinary'] = function(d) {
-console.log("putBinary not properly implemented yet");
-    this._check(_pn_data_put_binary(this._data, b));
+_Data_['putBinary'] = function(b) {
+console.log("putBinary");
+
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_data_put_binary(data, pn_bytes(b.size, b.start));
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the compiled
+    // pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, b.size, b.start);
+
+    // The compiled pn_data_put_binary takes the pn_bytes_t by reference not value.
+    this._check(_pn_data_put_binary(this._data, bytes));
+
+    // After calling _pn_data_put_binary the underlying data object "owns" the
+    // binary data, so we can call free on the proton.Data.Binary instance to
+    // release any storage it has acquired back to the emscripten heap.
+    b.free();
+    Runtime.stackRestore(sp);
 };
 
 /**
@@ -2282,8 +2267,34 @@ _Data_['getUUID'] = function() {
  * @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise.
  */
 _Data_['getBinary'] = function() {
-console.log("getBinary not properly implemented yet");
-    //this._check(_pn_data_put_binary(this._data, b));
+console.log("getBinary");
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes bytes = pn_data_get_binary(data);
+
+    // Here's the quirky bit, pn_data_get_binary actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_binary.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_data_get_binary(bytes, this._data);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a proton.Data.Binary from the pn_bytes_t information.
+    var binary = new Data['Binary'](size, start);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return binary;
 };
 
 /**
@@ -2484,6 +2495,8 @@ console.log("obj is quoted String " + quoted);
         }   
     } else if (obj instanceof Data['UUID']) {
         this['putUUID'](obj);
+    } else if (obj instanceof Data['Binary']) {
+        this['putBinary'](obj);
     } else if (obj instanceof Data['Symbol']) {
         this['putSymbol'](obj);
     } else if (Data.isNumber(obj)) {
@@ -2548,56 +2561,3 @@ _Data_.getObject = _Data_['getObject'];
 
 
 
-
-
-
-
-
-
-
-
-
-
-/*
-Module['Inflate'] = function(size) {
-    var _public = {};
-    var stream = _inflateInitialise();
-    var inputBuffer  = Buffer(size);
-    var outputBuffer = Buffer(size);
-
-    // Public methods
-    _public['destroy'] = function() {
-        _inflateDestroy(stream);
-        inputBuffer.destroy();
-        outputBuffer.destroy();
-    };
-
-    _public['reset'] = function() {
-        _inflateReset(stream);
-    };
-
-    _public['inflate'] = function(ptr) {
-        ptr = ptr ? ptr : outputBuffer.getRaw();
-        var inflatedSize; // Pass by reference variable - need to use Module.setValue to initialise it.
-        setValue(inflatedSize, outputBuffer.size, 'i32');
-        var err = _zinflate(stream, ptr, inflatedSize, inputBuffer.getRaw(), inputBuffer.size);
-        inflatedSize = getValue(inflatedSize, 'i32'); // Dereference the real inflatedSize value;
-        outputBuffer.setSize(inflatedSize);
-        return ((err < 0) ? err : inflatedSize); // Return the inflated size, or error code if inflation fails.
-    };
-
-    // Export methods from the input and output buffers for use by client code.
-    _public['setInputBufferSize'] = inputBuffer.setSize;
-    _public['getRawInputBuffer'] = inputBuffer.getRaw;
-    _public['getInputBuffer'] = inputBuffer.getBuffer;
-
-    _public['setOutputBufferSize'] = outputBuffer.setSize;
-    _public['getRawOutBuffer'] = outputBuffer.getRaw;
-    _public['getOutputBuffer'] = outputBuffer.getBuffer;
-
-    return _public;
-};
-*/
-
-
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aa766d06/proton-c/bindings/javascript/spout.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/spout.js b/proton-c/bindings/javascript/spout.js
index 8bb8542..7d3cc58 100644
--- a/proton-c/bindings/javascript/spout.js
+++ b/proton-c/bindings/javascript/spout.js
@@ -70,6 +70,14 @@ console.log("exiting");
     //message.body = msgtext;
     //message.body = new proton.Data.UUID();
     //message.body = new proton.Data.Symbol("My Symbol");
+    message.body = new proton.Data.Binary(4);
+    var buffer = message.body.getBuffer();
+    buffer[0] = 65;
+    buffer[1] = 77;
+    buffer[2] = 81;
+    buffer[3] = 80;
+
+
     //message.body = true;
     //message.body = "   \"127.0\"  ";
 
@@ -80,7 +88,7 @@ console.log("exiting");
     //message.body = 2147483647.000001; // double
 
     //message.body = ['Rod', 'Jane', 'Freddy'];
-    message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
+    //message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
 
 
     tracker = messenger.put(message);


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


[45/51] [abbrv] qpid-proton git commit: Sync with proton trunk revision 1627945 and update CMakeLists.txt

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/include/proton/util.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/util.h b/proton-c/include/proton/util.h
deleted file mode 100644
index 70043eb..0000000
--- a/proton-c/include/proton/util.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef PROTON_UTIL_H
-#define PROTON_UTIL_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/import_export.h>
-#include <stdarg.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-PN_EXTERN void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path);
-PN_EXTERN void pn_fatal(const char *fmt, ...);
-PN_EXTERN void pn_vfatal(const char *fmt, va_list ap);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* util.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/codec/codec.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/codec.c b/proton-c/src/codec/codec.c
index 87d7df7..afd0c57 100644
--- a/proton-c/src/codec/codec.c
+++ b/proton-c/src/codec/codec.c
@@ -22,7 +22,6 @@
 #include <proton/object.h>
 #include <proton/codec.h>
 #include <proton/error.h>
-#include <proton/util.h>
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
@@ -32,9 +31,9 @@
 #include "encodings.h"
 #define DEFINE_FIELDS
 #include "protocol.h"
-#include "../platform.h"
-#include "../platform_fmt.h"
-#include "../util.h"
+#include "platform.h"
+#include "platform_fmt.h"
+#include "util.h"
 #include "decoder.h"
 #include "encoder.h"
 #include "data.h"
@@ -367,7 +366,7 @@ static int pn_data_inspect(void *obj, pn_string_t *dst)
 pn_data_t *pn_data(size_t capacity)
 {
   static const pn_class_t clazz = PN_CLASS(pn_data);
-  pn_data_t *data = (pn_data_t *) pn_new(sizeof(pn_data_t), &clazz);
+  pn_data_t *data = (pn_data_t *) pn_class_new(&clazz, sizeof(pn_data_t));
   data->capacity = capacity;
   data->size = 0;
   data->nodes = capacity ? (pni_node_t *) malloc(capacity * sizeof(pni_node_t)) : NULL;
@@ -1112,15 +1111,6 @@ int pn_data_resize(pn_data_t *data, size_t size)
 }
 
 
-pni_node_t *pn_data_node(pn_data_t *data, pni_nid_t nd)
-{
-  if (nd) {
-    return &data->nodes[nd - 1];
-  } else {
-    return NULL;
-  }
-}
-
 size_t pn_data_id(pn_data_t *data, pni_node_t *node)
 {
   return node - data->nodes + 1;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/codec/data.h
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/data.h b/proton-c/src/codec/data.h
index be1669a..a528d26 100644
--- a/proton-c/src/codec/data.h
+++ b/proton-c/src/codec/data.h
@@ -61,7 +61,11 @@ struct pn_data_t {
   pni_nid_t base_current;
 };
 
-pni_node_t *pn_data_node(pn_data_t *data, pni_nid_t nd);
+inline pni_node_t * pn_data_node(pn_data_t *data, pni_nid_t nd) 
+{
+  return nd ? (data->nodes + nd - 1) : NULL;
+}
+
 int pni_data_traverse(pn_data_t *data,
                       int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
                       int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/codec/decoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/decoder.c b/proton-c/src/codec/decoder.c
index 7a01388..2bd4ecc 100644
--- a/proton-c/src/codec/decoder.c
+++ b/proton-c/src/codec/decoder.c
@@ -55,7 +55,7 @@ static void pn_decoder_finalize(void *obj) {
 pn_decoder_t *pn_decoder()
 {
   static const pn_class_t clazz = PN_CLASS(pn_decoder);
-  return (pn_decoder_t *) pn_new(sizeof(pn_decoder_t), &clazz);
+  return (pn_decoder_t *) pn_class_new(&clazz, sizeof(pn_decoder_t));
 }
 
 static inline uint8_t pn_decoder_readf8(pn_decoder_t *decoder)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/codec/encoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/encoder.c b/proton-c/src/codec/encoder.c
index f0f3cef..4a32183 100644
--- a/proton-c/src/codec/encoder.c
+++ b/proton-c/src/codec/encoder.c
@@ -57,7 +57,7 @@ static void pn_encoder_finalize(void *obj) {
 pn_encoder_t *pn_encoder()
 {
   static const pn_class_t clazz = PN_CLASS(pn_encoder);
-  return (pn_encoder_t *) pn_new(sizeof(pn_encoder_t), &clazz);
+  return (pn_encoder_t *) pn_class_new(&clazz, sizeof(pn_encoder_t));
 }
 
 static uint8_t pn_type2code(pn_encoder_t *encoder, pn_type_t type)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/dispatcher/dispatcher.c
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatcher/dispatcher.c b/proton-c/src/dispatcher/dispatcher.c
index 296c3ab..6368aa5 100644
--- a/proton-c/src/dispatcher/dispatcher.c
+++ b/proton-c/src/dispatcher/dispatcher.c
@@ -27,8 +27,8 @@
 #include <proton/buffer.h>
 #include "dispatcher.h"
 #include "protocol.h"
-#include "../util.h"
-#include "../platform_fmt.h"
+#include "util.h"
+#include "platform_fmt.h"
 
 #include "dispatch_actions.h"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/dispatcher/dispatcher.h
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatcher/dispatcher.h b/proton-c/src/dispatcher/dispatcher.h
index a87e383..9ec2dda 100644
--- a/proton-c/src/dispatcher/dispatcher.h
+++ b/proton-c/src/dispatcher/dispatcher.h
@@ -26,8 +26,9 @@
 #ifndef __cplusplus
 #include <stdbool.h>
 #endif
-#include <proton/buffer.h>
-#include <proton/codec.h>
+#include "proton/buffer.h"
+#include "proton/codec.h"
+#include "proton/transport.h"
 
 typedef struct pn_dispatcher_t pn_dispatcher_t;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
index 03cb630..37e8311 100644
--- a/proton-c/src/engine/engine-internal.h
+++ b/proton-c/src/engine/engine-internal.h
@@ -26,8 +26,8 @@
 #include <proton/buffer.h>
 #include <proton/engine.h>
 #include <proton/types.h>
-#include "../dispatcher/dispatcher.h"
-#include "../util.h"
+#include "dispatcher/dispatcher.h"
+#include "util.h"
 
 typedef enum pn_endpoint_type_t {CONNECTION, SESSION, SENDER, RECEIVER} pn_endpoint_type_t;
 
@@ -127,6 +127,7 @@ struct pn_transport_t {
   uint32_t   local_max_frame;
   uint32_t   remote_max_frame;
   pn_condition_t remote_condition;
+  pn_condition_t condition;
 
 #define PN_IO_SSL  0
 #define PN_IO_SASL 1
@@ -174,6 +175,8 @@ struct pn_transport_t {
   bool tail_closed;      // input stream closed by driver
   bool head_closed;
   bool done_processing; // if true, don't call pn_process again
+  bool posted_head_closed;
+  bool posted_tail_closed;
 };
 
 struct pn_connection_t {
@@ -250,6 +253,7 @@ struct pn_link_t {
   uint8_t remote_rcv_settle_mode;
   bool drain_flag_mode; // receiver only
   bool drain;
+  bool detached;
 };
 
 struct pn_disposition_t {
@@ -311,5 +315,10 @@ void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery);
 void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint);
 void pn_connection_unbound(pn_connection_t *conn);
 int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...);
+void pn_session_unbound(pn_session_t* ssn);
+void pn_link_unbound(pn_link_t* link);
+
+void pni_close_tail(pn_transport_t *transport);
+
 
 #endif /* engine-internal.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/engine/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine.c b/proton-c/src/engine/engine.c
index 02e5009..46bf462 100644
--- a/proton-c/src/engine/engine.c
+++ b/proton-c/src/engine/engine.c
@@ -28,12 +28,9 @@
 #include <stdarg.h>
 #include <stdio.h>
 
-#include "../sasl/sasl-internal.h"
-#include "../ssl/ssl-internal.h"
-#include "../platform.h"
-#include "../platform_fmt.h"
-#include "../transport/transport.h"
-#include "../engine/event.h"
+#include "platform.h"
+#include "platform_fmt.h"
+#include "transport/transport.h"
 
 // endpoints
 
@@ -72,8 +69,8 @@ static void pn_endpoint_open(pn_endpoint_t *endpoint)
   // TODO: do we care about the current state?
   PN_SET_LOCAL(endpoint->state, PN_LOCAL_ACTIVE);
   pn_connection_t *conn = pn_ep_get_connection(endpoint);
-  pn_collector_put(conn->collector, endpoint_event(endpoint->type, true),
-                   endpoint);
+  pn_collector_put(conn->collector, PN_OBJECT, endpoint,
+                   endpoint_event(endpoint->type, true));
   pn_modified(conn, endpoint, true);
 }
 
@@ -82,8 +79,8 @@ static void pn_endpoint_close(pn_endpoint_t *endpoint)
   // TODO: do we care about the current state?
   PN_SET_LOCAL(endpoint->state, PN_LOCAL_CLOSED);
   pn_connection_t *conn = pn_ep_get_connection(endpoint);
-  pn_collector_put(conn->collector, endpoint_event(endpoint->type, false),
-                   endpoint);
+  pn_collector_put(conn->collector, PN_OBJECT, endpoint,
+                   endpoint_event(endpoint->type, false));
   pn_modified(conn, endpoint, true);
 }
 
@@ -190,7 +187,7 @@ void pn_add_session(pn_connection_t *conn, pn_session_t *ssn)
 {
   pn_list_add(conn->sessions, ssn);
   ssn->connection = conn;
-  pn_incref2(conn, ssn);  // keep around until finalized
+  pn_incref(conn);  // keep around until finalized
 }
 
 void pn_remove_session(pn_connection_t *conn, pn_session_t *ssn)
@@ -228,7 +225,7 @@ void pn_session_free(pn_session_t *session)
   pn_endpoint_t *endpoint = (pn_endpoint_t *) session;
   LL_REMOVE(pn_ep_get_connection(endpoint), endpoint, endpoint);
   session->endpoint.freed = true;
-  pn_decref2(session, session->connection);
+  pn_decref(session);
 }
 
 void *pn_session_get_context(pn_session_t *session)
@@ -266,6 +263,15 @@ void pn_link_close(pn_link_t *link)
   pn_endpoint_close(&link->endpoint);
 }
 
+void pn_link_detach(pn_link_t *link)
+{
+  assert(link);
+  link->detached = true;
+  pn_collector_put(link->session->connection->collector, PN_OBJECT, link, PN_LINK_DETACH);
+  pn_modified(link->session->connection, &link->endpoint, true);
+
+}
+
 void pn_terminus_free(pn_terminus_t *terminus)
 {
   pn_free(terminus->address);
@@ -290,10 +296,10 @@ void pn_link_free(pn_link_t *link)
   while (link->settled_head) {
     delivery = link->settled_head;
     LL_POP(link, settled, pn_delivery_t);
-    pn_decref2(delivery, link);
+    pn_decref(delivery);
   }
   link->endpoint.freed = true;
-  pn_decref2(link, link->session);
+  pn_decref(link);
 }
 
 void *pn_link_get_context(pn_link_t *link)
@@ -332,14 +338,13 @@ void pn_endpoint_tini(pn_endpoint_t *endpoint)
   pn_condition_tini(&endpoint->condition);
 }
 
-#include "event.h"
-
 static bool pni_post_final(pn_endpoint_t *endpoint, pn_event_type_t type)
 {
   pn_connection_t *conn = pn_ep_get_connection(endpoint);
   if (!endpoint->posted_final) {
     endpoint->posted_final = true;
-    pn_event_t *event = pn_collector_put(conn->collector, type, endpoint);
+    pn_event_t *event = pn_collector_put(conn->collector, PN_OBJECT, endpoint,
+                                         type);
     if (event) { return true; }
   }
 
@@ -355,7 +360,7 @@ static void pn_connection_finalize(void *object)
     return;
   }
 
-  pn_decref2(conn->collector, conn);
+  pn_decref(conn->collector);
   pn_free(conn->sessions);
   pn_free(conn->container);
   pn_free(conn->hostname);
@@ -373,7 +378,7 @@ static void pn_connection_finalize(void *object)
 pn_connection_t *pn_connection()
 {
   static const pn_class_t clazz = PN_CLASS(pn_connection);
-  pn_connection_t *conn = (pn_connection_t *) pn_new(sizeof(pn_connection_t), &clazz);
+  pn_connection_t *conn = (pn_connection_t *) pn_class_new(&clazz, sizeof(pn_connection_t));
   if (!conn) return NULL;
 
   conn->context = NULL;
@@ -382,7 +387,7 @@ pn_connection_t *pn_connection()
   pn_endpoint_init(&conn->endpoint, CONNECTION, conn);
   conn->transport_head = NULL;
   conn->transport_tail = NULL;
-  conn->sessions = pn_list(0, 0);
+  conn->sessions = pn_list(PN_WEAKREF, 0);
   conn->transport = NULL;
   conn->work_head = NULL;
   conn->work_tail = NULL;
@@ -406,12 +411,12 @@ static const pn_event_type_t endpoint_init_event_map[] = {
 
 void pn_connection_collect(pn_connection_t *connection, pn_collector_t *collector)
 {
-  pn_decref2(connection->collector, connection);
+  pn_decref(connection->collector);
   connection->collector = collector;
-  pn_incref2(connection->collector, connection);
+  pn_incref(connection->collector);
   pn_endpoint_t *endpoint = connection->endpoint_head;
   while (endpoint) {
-    pn_collector_put(connection->collector, endpoint_init_event_map[endpoint->type], endpoint);
+    pn_collector_put(connection->collector, PN_OBJECT, endpoint, endpoint_init_event_map[endpoint->type]);
     endpoint = endpoint->endpoint_next;
   }
 }
@@ -561,7 +566,7 @@ void pn_add_tpwork(pn_delivery_t *delivery)
   {
     LL_ADD(connection, tpwork, delivery);
     delivery->tpwork = true;
-    pn_incref2(delivery, connection);
+    pn_incref(delivery);
   }
   pn_modified(connection, &connection->endpoint, true);
 }
@@ -573,7 +578,7 @@ void pn_clear_tpwork(pn_delivery_t *delivery)
   {
     LL_REMOVE(connection, tpwork, delivery);
     delivery->tpwork = false;
-    pn_decref2(delivery, connection);  // may free delivery!
+    pn_decref(delivery);  // may free delivery!
   }
 }
 
@@ -595,12 +600,12 @@ void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit
   if (!endpoint->modified) {
     LL_ADD(connection, transport, endpoint);
     endpoint->modified = true;
-    pn_incref2(endpoint, connection);
+    pn_incref(endpoint);
   }
 
   if (emit && connection->transport) {
-    pn_collector_put(connection->collector, PN_TRANSPORT,
-                     connection->transport);
+    pn_collector_put(connection->collector, PN_OBJECT, connection->transport,
+                     PN_TRANSPORT);
   }
 }
 
@@ -611,7 +616,7 @@ void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint)
     endpoint->transport_next = NULL;
     endpoint->transport_prev = NULL;
     endpoint->modified = false;
-    pn_decref2(endpoint, connection);  // may free endpoint!
+    pn_decref(endpoint);  // may free endpoint!
   }
 }
 
@@ -709,7 +714,7 @@ static void pn_session_finalize(void *object)
   pn_delivery_map_free(&session->state.outgoing);
   pn_free(session->state.local_handles);
   pn_free(session->state.remote_handles);
-  pn_decref2(session->connection, session);
+  pn_decref(session->connection);
 }
 
 #define pn_session_initialize NULL
@@ -721,12 +726,12 @@ pn_session_t *pn_session(pn_connection_t *conn)
 {
   assert(conn);
   static const pn_class_t clazz = PN_CLASS(pn_session);
-  pn_session_t *ssn = (pn_session_t *) pn_new2(sizeof(pn_session_t), &clazz, conn);
+  pn_session_t *ssn = (pn_session_t *) pn_class_new(&clazz, sizeof(pn_session_t));
   if (!ssn) return NULL;
 
   pn_endpoint_init(&ssn->endpoint, SESSION, conn);
   pn_add_session(conn, ssn);
-  ssn->links = pn_list(0, 0);
+  ssn->links = pn_list(PN_WEAKREF, 0);
   ssn->context = 0;
   ssn->incoming_capacity = 1024*1024;
   ssn->incoming_bytes = 0;
@@ -740,14 +745,25 @@ pn_session_t *pn_session(pn_connection_t *conn)
   ssn->state.remote_channel = (uint16_t)-1;
   pn_delivery_map_init(&ssn->state.incoming, 0);
   pn_delivery_map_init(&ssn->state.outgoing, 0);
-  ssn->state.local_handles = pn_hash(0, 0.75, PN_REFCOUNT);
-  ssn->state.remote_handles = pn_hash(0, 0.75, PN_REFCOUNT);
+  ssn->state.local_handles = pn_hash(PN_OBJECT, 0, 0.75);
+  ssn->state.remote_handles = pn_hash(PN_OBJECT, 0, 0.75);
   // end transport state
 
-  pn_collector_put(conn->collector, PN_SESSION_INIT, ssn);
+  pn_collector_put(conn->collector, PN_OBJECT, ssn, PN_SESSION_INIT);
   return ssn;
 }
 
+void pn_session_unbound(pn_session_t* ssn)
+{
+  assert(ssn);
+  ssn->state.local_channel = (uint16_t)-1;
+  ssn->state.remote_channel = (uint16_t)-1;
+  ssn->incoming_bytes = 0;
+  ssn->outgoing_bytes = 0;
+  ssn->incoming_deliveries = 0;
+  ssn->outgoing_deliveries = 0;
+}
+
 size_t pn_session_get_incoming_capacity(pn_session_t *ssn)
 {
   assert(ssn);
@@ -817,7 +833,7 @@ static void pn_link_finalize(void *object)
   pn_terminus_free(&link->remote_target);
   pn_free(link->name);
   pn_endpoint_tini(endpoint);
-  pn_decref2(link->session, link);
+  pn_decref(link->session);
 }
 
 #define pn_link_initialize NULL
@@ -828,11 +844,11 @@ static void pn_link_finalize(void *object)
 pn_link_t *pn_link_new(int type, pn_session_t *session, const char *name)
 {
   static const pn_class_t clazz = PN_CLASS(pn_link);
-  pn_link_t *link = (pn_link_t *) pn_new2(sizeof(pn_link_t), &clazz, session);
+  pn_link_t *link = (pn_link_t *) pn_class_new(&clazz, sizeof(pn_link_t));
 
   pn_endpoint_init(&link->endpoint, type, session->connection);
   pn_add_link(session, link);
-  pn_incref2(session, link);  // keep session until link finalized
+  pn_incref(session);  // keep session until link finalized
   link->name = pn_string(name);
   pn_terminus_init(&link->source, PN_SOURCE);
   pn_terminus_init(&link->target, PN_TARGET);
@@ -852,6 +868,7 @@ pn_link_t *pn_link_new(int type, pn_session_t *session, const char *name)
   link->rcv_settle_mode = PN_RCV_FIRST;
   link->remote_snd_settle_mode = PN_SND_MIXED;
   link->remote_rcv_settle_mode = PN_RCV_FIRST;
+  link->detached = false;
 
   // begin transport state
   link->state.local_handle = -1;
@@ -860,10 +877,19 @@ pn_link_t *pn_link_new(int type, pn_session_t *session, const char *name)
   link->state.link_credit = 0;
   // end transport state
 
-  pn_collector_put(session->connection->collector, PN_LINK_INIT, link);
+  pn_collector_put(session->connection->collector, PN_OBJECT, link, PN_LINK_INIT);
   return link;
 }
 
+void pn_link_unbound(pn_link_t* link)
+{
+  assert(link);
+  link->state.local_handle = -1;
+  link->state.remote_handle = -1;
+  link->state.delivery_count = 0;
+  link->state.link_credit = 0;
+}
+
 pn_terminus_t *pn_link_source(pn_link_t *link)
 {
   return link ? &link->source : NULL;
@@ -1072,7 +1098,7 @@ static void pn_delivery_finalize(void *object)
   pn_buffer_free(delivery->bytes);
   pn_disposition_finalize(&delivery->local);
   pn_disposition_finalize(&delivery->remote);
-  pn_decref2(delivery->link, delivery);
+  pn_decref(delivery->link);
 }
 
 static void pn_disposition_init(pn_disposition_t *ds)
@@ -1107,10 +1133,10 @@ pn_delivery_t *pn_delivery(pn_link_t *link, pn_delivery_tag_t tag)
   LL_POP(link, settled, pn_delivery_t);
   if (!delivery) {
     static const pn_class_t clazz = PN_CLASS(pn_delivery);
-    delivery = (pn_delivery_t *) pn_new2(sizeof(pn_delivery_t), &clazz, link);
+    delivery = (pn_delivery_t *) pn_class_new(&clazz, sizeof(pn_delivery_t));
     if (!delivery) return NULL;
     delivery->link = link;
-    pn_incref2(delivery->link, delivery);  // keep link until finalized
+    pn_incref(delivery->link);  // keep link until finalized
     delivery->tag = pn_buffer(16);
     delivery->bytes = pn_buffer(64);
     pn_disposition_init(&delivery->local);
@@ -1734,3 +1760,77 @@ int pn_condition_redirect_port(pn_condition_t *condition)
   pn_data_rewind(data);
   return port;
 }
+
+pn_connection_t *pn_event_connection(pn_event_t *event)
+{
+  pn_session_t *ssn;
+  pn_transport_t *transport;
+
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_connection:
+    return (pn_connection_t *) pn_event_context(event);
+  case CID_pn_transport:
+    transport = pn_event_transport(event);
+    if (transport)
+      return transport->connection;
+    return NULL;
+  default:
+    ssn = pn_event_session(event);
+    if (ssn)
+     return pn_session_connection(ssn);
+  }
+  return NULL;
+}
+
+pn_session_t *pn_event_session(pn_event_t *event)
+{
+  pn_link_t *link;
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_session:
+    return (pn_session_t *) pn_event_context(event);
+  default:
+    link = pn_event_link(event);
+    if (link)
+      return pn_link_session(link);
+  }
+  return NULL;
+}
+
+pn_link_t *pn_event_link(pn_event_t *event)
+{
+  pn_delivery_t *dlv;
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_link:
+    return (pn_link_t *) pn_event_context(event);
+  default:
+    dlv = pn_event_delivery(event);
+    if (dlv)
+      return pn_delivery_link(dlv);
+  }
+  return NULL;
+}
+
+pn_delivery_t *pn_event_delivery(pn_event_t *event)
+{
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_delivery:
+    return (pn_delivery_t *) pn_event_context(event);
+  default:
+    return NULL;
+  }
+}
+
+pn_transport_t *pn_event_transport(pn_event_t *event)
+{
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_transport:
+    return (pn_transport_t *) pn_event_context(event);
+  default:
+    {
+      pn_connection_t *conn = pn_event_connection(event);
+      if (conn)
+        return pn_connection_transport(conn);
+      return NULL;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/engine/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/event.c b/proton-c/src/engine/event.c
deleted file mode 100644
index 07e3cb5..0000000
--- a/proton-c/src/engine/event.c
+++ /dev/null
@@ -1,348 +0,0 @@
-#include <proton/engine.h>
-#include <assert.h>
-#include "engine-internal.h"
-
-struct pn_collector_t {
-  pn_event_t *head;
-  pn_event_t *tail;
-  pn_event_t *free_head;
-  bool freed;
-};
-
-struct pn_event_t {
-  void *context;    // depends on type
-  pn_event_t *next;
-  pn_event_type_t type;
-};
-
-static void pn_collector_initialize(void *obj)
-{
-  pn_collector_t *collector = (pn_collector_t *) obj;
-  collector->head = NULL;
-  collector->tail = NULL;
-  collector->free_head = NULL;
-  collector->freed = false;
-}
-
-static void pn_collector_drain(pn_collector_t *collector)
-{
-  while (pn_collector_peek(collector)) {
-    pn_collector_pop(collector);
-  }
-
-  assert(!collector->head);
-  assert(!collector->tail);
-}
-
-static void pn_collector_shrink(pn_collector_t *collector)
-{
-  pn_event_t *event = collector->free_head;
-  while (event) {
-    pn_event_t *next = event->next;
-    pn_free(event);
-    event = next;
-  }
-
-  collector->free_head = NULL;
-}
-
-static void pn_collector_finalize(void *obj)
-{
-  pn_collector_t *collector = (pn_collector_t *) obj;
-  pn_collector_drain(collector);
-  pn_collector_shrink(collector);
-}
-
-static int pn_collector_inspect(void *obj, pn_string_t *dst)
-{
-  assert(obj);
-  pn_collector_t *collector = (pn_collector_t *) obj;
-  int err = pn_string_addf(dst, "EVENTS[");
-  if (err) return err;
-  pn_event_t *event = collector->head;
-  bool first = true;
-  while (event) {
-    if (first) {
-      first = false;
-    } else {
-      err = pn_string_addf(dst, ", ");
-      if (err) return err;
-    }
-    err = pn_inspect(event, dst);
-    if (err) return err;
-    event = event->next;
-  }
-  return pn_string_addf(dst, "]");
-}
-
-#define pn_collector_hashcode NULL
-#define pn_collector_compare NULL
-
-pn_collector_t *pn_collector(void)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_collector);
-  pn_collector_t *collector = (pn_collector_t *) pn_new(sizeof(pn_collector_t), &clazz);
-  return collector;
-}
-
-void pn_collector_free(pn_collector_t *collector)
-{
-  collector->freed = true;
-  pn_collector_drain(collector);
-  pn_collector_shrink(collector);
-  pn_decref(collector);
-}
-
-pn_event_t *pn_event(void);
-static void pn_event_initialize(void *obj);
-
-pn_event_t *pn_collector_put(pn_collector_t *collector, pn_event_type_t type, void *context)
-{
-  if (!collector) {
-    return NULL;
-  }
-
-  assert(context);
-
-  if (collector->freed) {
-    return NULL;
-  }
-
-  pn_event_t *tail = collector->tail;
-  if (tail && tail->type == type && tail->context == context) {
-    return NULL;
-  }
-
-  pn_event_t *event;
-
-  if (collector->free_head) {
-    event = collector->free_head;
-    collector->free_head = collector->free_head->next;
-    pn_event_initialize(event);
-  } else {
-    event = pn_event();
-  }
-
-  if (tail) {
-    tail->next = event;
-    collector->tail = event;
-  } else {
-    collector->tail = event;
-    collector->head = event;
-  }
-
-  event->type = type;
-  event->context = context;
-  pn_incref2(event->context, collector);
-
-  //printf("event %s on %p\n", pn_event_type_name(event->type), event->context);
-
-  return event;
-}
-
-pn_event_t *pn_collector_peek(pn_collector_t *collector)
-{
-  return collector->head;
-}
-
-bool pn_collector_pop(pn_collector_t *collector)
-{
-  pn_event_t *event = collector->head;
-  if (event) {
-    collector->head = event->next;
-  } else {
-    return false;
-  }
-
-  if (!collector->head) {
-    collector->tail = NULL;
-  }
-
-  // decref before adding to the free list
-  if (event->context) {
-    pn_decref2(event->context, collector);
-    event->context = NULL;
-  }
-
-  event->next = collector->free_head;
-  collector->free_head = event;
-
-  return true;
-}
-
-static void pn_event_initialize(void *obj)
-{
-  pn_event_t *event = (pn_event_t *) obj;
-  event->type = PN_EVENT_NONE;
-  event->context = NULL;
-  event->next = NULL;
-}
-
-static void pn_event_finalize(void *obj) {}
-
-static int pn_event_inspect(void *obj, pn_string_t *dst)
-{
-  assert(obj);
-  pn_event_t *event = (pn_event_t *) obj;
-  int err = pn_string_addf(dst, "(0x%X", (unsigned int)event->type);
-  if (event->context) {
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    err = pn_inspect(event->context, dst);
-    if (err) return err;
-  }
-
-  return pn_string_addf(dst, ")");
-}
-
-#define pn_event_hashcode NULL
-#define pn_event_compare NULL
-
-pn_event_t *pn_event(void)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_event);
-  pn_event_t *event = (pn_event_t *) pn_new(sizeof(pn_event_t), &clazz);
-  return event;
-}
-
-pn_event_type_t pn_event_type(pn_event_t *event)
-{
-  return event->type;
-}
-
-pn_event_category_t pn_event_category(pn_event_t *event)
-{
-  return (pn_event_category_t)(event->type & 0xFFFF0000);
-}
-
-void *pn_event_context(pn_event_t *event)
-{
-  assert(event);
-  return event->context;
-}
-
-pn_connection_t *pn_event_connection(pn_event_t *event)
-{
-  pn_session_t *ssn;
-  pn_transport_t *transport;
-
-  switch (pn_event_category(event)) {
-  case PN_EVENT_CATEGORY_CONNECTION:
-    return (pn_connection_t *)event->context;
-  case PN_EVENT_CATEGORY_TRANSPORT:
-    transport = pn_event_transport(event);
-    if (transport)
-      return transport->connection;
-    return NULL;
-  default:
-    ssn = pn_event_session(event);
-    if (ssn)
-     return pn_session_connection(ssn);
-  }
-  return NULL;
-}
-
-pn_session_t *pn_event_session(pn_event_t *event)
-{
-  pn_link_t *link;
-  switch (pn_event_category(event)) {
-  case PN_EVENT_CATEGORY_SESSION:
-    return (pn_session_t *)event->context;
-  default:
-    link = pn_event_link(event);
-    if (link)
-      return pn_link_session(link);
-  }
-  return NULL;
-}
-
-pn_link_t *pn_event_link(pn_event_t *event)
-{
-  pn_delivery_t *dlv;
-  switch (pn_event_category(event)) {
-  case PN_EVENT_CATEGORY_LINK:
-    return (pn_link_t *)event->context;
-  default:
-    dlv = pn_event_delivery(event);
-    if (dlv)
-      return pn_delivery_link(dlv);
-  }
-  return NULL;
-}
-
-pn_delivery_t *pn_event_delivery(pn_event_t *event)
-{
-  switch (pn_event_category(event)) {
-  case PN_EVENT_CATEGORY_DELIVERY:
-    return (pn_delivery_t *)event->context;
-  default:
-    return NULL;
-  }
-}
-
-pn_transport_t *pn_event_transport(pn_event_t *event)
-{
-  switch (pn_event_category(event)) {
-  case PN_EVENT_CATEGORY_TRANSPORT:
-    return (pn_transport_t *)event->context;
-  default:
-    {
-      pn_connection_t *conn = pn_event_connection(event);
-      if (conn)
-        return pn_connection_transport(conn);
-      return NULL;
-    }
-  }
-}
-
-const char *pn_event_type_name(pn_event_type_t type)
-{
-  switch (type) {
-  case PN_EVENT_NONE:
-    return "PN_EVENT_NONE";
-  case PN_CONNECTION_INIT:
-    return "PN_CONNECTION_INIT";
-  case PN_CONNECTION_REMOTE_OPEN:
-    return "PN_CONNECTION_REMOTE_OPEN";
-  case PN_CONNECTION_OPEN:
-    return "PN_CONNECTION_OPEN";
-  case PN_CONNECTION_REMOTE_CLOSE:
-    return "PN_CONNECTION_REMOTE_CLOSE";
-  case PN_CONNECTION_CLOSE:
-    return "PN_CONNECTION_CLOSE";
-  case PN_CONNECTION_FINAL:
-    return "PN_CONNECTION_FINAL";
-  case PN_SESSION_INIT:
-    return "PN_SESSION_INIT";
-  case PN_SESSION_REMOTE_OPEN:
-    return "PN_SESSION_REMOTE_OPEN";
-  case PN_SESSION_OPEN:
-    return "PN_SESSION_OPEN";
-  case PN_SESSION_REMOTE_CLOSE:
-    return "PN_SESSION_REMOTE_CLOSE";
-  case PN_SESSION_CLOSE:
-    return "PN_SESSION_CLOSE";
-  case PN_SESSION_FINAL:
-    return "PN_SESSION_FINAL";
-  case PN_LINK_INIT:
-    return "PN_LINK_INIT";
-  case PN_LINK_REMOTE_OPEN:
-    return "PN_LINK_REMOTE_OPEN";
-  case PN_LINK_OPEN:
-    return "PN_LINK_OPEN";
-  case PN_LINK_REMOTE_CLOSE:
-    return "PN_LINK_REMOTE_CLOSE";
-  case PN_LINK_CLOSE:
-    return "PN_LINK_CLOSE";
-  case PN_LINK_FLOW:
-    return "PN_LINK_FLOW";
-  case PN_LINK_FINAL:
-    return "PN_LINK_FINAL";
-  case PN_DELIVERY:
-    return "PN_DELIVERY";
-  case PN_TRANSPORT:
-    return "PN_TRANSPORT";
-  }
-
-  return "<unrecognized>";
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/engine/event.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/event.h b/proton-c/src/engine/event.h
deleted file mode 100644
index b05f2d0..0000000
--- a/proton-c/src/engine/event.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef _PROTON_EVENT_H
-#define _PROTON_EVENT_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-pn_event_t *pn_collector_put(pn_collector_t *collector, pn_event_type_t type,
-                             void *context);
-
-#endif /* event.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/events/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/events/event.c b/proton-c/src/events/event.c
new file mode 100644
index 0000000..95aeb03
--- /dev/null
+++ b/proton-c/src/events/event.c
@@ -0,0 +1,298 @@
+#include <proton/object.h>
+#include <proton/event.h>
+#include <assert.h>
+
+struct pn_collector_t {
+  pn_event_t *head;
+  pn_event_t *tail;
+  pn_event_t *free_head;
+  bool freed;
+};
+
+struct pn_event_t {
+  const pn_class_t *clazz;
+  void *context;    // depends on type
+  pn_event_t *next;
+  pn_event_type_t type;
+};
+
+static void pn_collector_initialize(void *obj)
+{
+  pn_collector_t *collector = (pn_collector_t *) obj;
+  collector->head = NULL;
+  collector->tail = NULL;
+  collector->free_head = NULL;
+  collector->freed = false;
+}
+
+static void pn_collector_drain(pn_collector_t *collector)
+{
+  while (pn_collector_peek(collector)) {
+    pn_collector_pop(collector);
+  }
+
+  assert(!collector->head);
+  assert(!collector->tail);
+}
+
+static void pn_collector_shrink(pn_collector_t *collector)
+{
+  pn_event_t *event = collector->free_head;
+  while (event) {
+    pn_event_t *next = event->next;
+    pn_free(event);
+    event = next;
+  }
+
+  collector->free_head = NULL;
+}
+
+static void pn_collector_finalize(void *obj)
+{
+  pn_collector_t *collector = (pn_collector_t *) obj;
+  pn_collector_drain(collector);
+  pn_collector_shrink(collector);
+}
+
+static int pn_collector_inspect(void *obj, pn_string_t *dst)
+{
+  assert(obj);
+  pn_collector_t *collector = (pn_collector_t *) obj;
+  int err = pn_string_addf(dst, "EVENTS[");
+  if (err) return err;
+  pn_event_t *event = collector->head;
+  bool first = true;
+  while (event) {
+    if (first) {
+      first = false;
+    } else {
+      err = pn_string_addf(dst, ", ");
+      if (err) return err;
+    }
+    err = pn_inspect(event, dst);
+    if (err) return err;
+    event = event->next;
+  }
+  return pn_string_addf(dst, "]");
+}
+
+#define pn_collector_hashcode NULL
+#define pn_collector_compare NULL
+
+pn_collector_t *pn_collector(void)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_collector);
+  pn_collector_t *collector = (pn_collector_t *) pn_class_new(&clazz, sizeof(pn_collector_t));
+  return collector;
+}
+
+void pn_collector_free(pn_collector_t *collector)
+{
+  collector->freed = true;
+  pn_collector_drain(collector);
+  pn_collector_shrink(collector);
+  pn_class_decref(PN_OBJECT, collector);
+}
+
+pn_event_t *pn_event(void);
+static void pn_event_initialize(void *obj);
+
+pn_event_t *pn_collector_put(pn_collector_t *collector,
+                             const pn_class_t *clazz, void *context,
+                             pn_event_type_t type)
+{
+  if (!collector) {
+    return NULL;
+  }
+
+  assert(context);
+
+  if (collector->freed) {
+    return NULL;
+  }
+
+  pn_event_t *tail = collector->tail;
+  if (tail && tail->type == type && tail->context == context) {
+    return NULL;
+  }
+
+  clazz = clazz->reify(context);
+
+  pn_event_t *event;
+
+  if (collector->free_head) {
+    event = collector->free_head;
+    collector->free_head = collector->free_head->next;
+    pn_event_initialize(event);
+  } else {
+    event = pn_event();
+  }
+
+  if (tail) {
+    tail->next = event;
+    collector->tail = event;
+  } else {
+    collector->tail = event;
+    collector->head = event;
+  }
+
+  event->clazz = clazz;
+  event->context = context;
+  event->type = type;
+  pn_class_incref(clazz, event->context);
+
+  //printf("event %s on %p\n", pn_event_type_name(event->type), event->context);
+
+  return event;
+}
+
+pn_event_t *pn_collector_peek(pn_collector_t *collector)
+{
+  return collector->head;
+}
+
+bool pn_collector_pop(pn_collector_t *collector)
+{
+  pn_event_t *event = collector->head;
+  if (event) {
+    collector->head = event->next;
+  } else {
+    return false;
+  }
+
+  if (!collector->head) {
+    collector->tail = NULL;
+  }
+
+  // decref before adding to the free list
+  if (event->context) {
+    pn_class_decref(event->clazz, event->context);
+    event->context = NULL;
+  }
+
+  event->next = collector->free_head;
+  collector->free_head = event;
+
+  return true;
+}
+
+static void pn_event_initialize(void *obj)
+{
+  pn_event_t *event = (pn_event_t *) obj;
+  event->type = PN_EVENT_NONE;
+  event->clazz = NULL;
+  event->context = NULL;
+  event->next = NULL;
+}
+
+static void pn_event_finalize(void *obj) {}
+
+static int pn_event_inspect(void *obj, pn_string_t *dst)
+{
+  assert(obj);
+  pn_event_t *event = (pn_event_t *) obj;
+  int err = pn_string_addf(dst, "(0x%X", (unsigned int)event->type);
+  if (event->context) {
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    err = pn_class_inspect(event->clazz, event->context, dst);
+    if (err) return err;
+  }
+
+  return pn_string_addf(dst, ")");
+}
+
+#define pn_event_hashcode NULL
+#define pn_event_compare NULL
+
+pn_event_t *pn_event(void)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_event);
+  pn_event_t *event = (pn_event_t *) pn_class_new(&clazz, sizeof(pn_event_t));
+  return event;
+}
+
+pn_event_type_t pn_event_type(pn_event_t *event)
+{
+  return event->type;
+}
+
+const pn_class_t *pn_event_class(pn_event_t *event)
+{
+  assert(event);
+  return event->clazz;
+}
+
+void *pn_event_context(pn_event_t *event)
+{
+  assert(event);
+  return event->context;
+}
+
+const char *pn_event_type_name(pn_event_type_t type)
+{
+  switch (type) {
+  case PN_EVENT_NONE:
+    return "PN_EVENT_NONE";
+  case PN_CONNECTION_INIT:
+    return "PN_CONNECTION_INIT";
+  case PN_CONNECTION_BOUND:
+    return "PN_CONNECTION_BOUND";
+  case PN_CONNECTION_UNBOUND:
+    return "PN_CONNECTION_UNBOUND";
+  case PN_CONNECTION_REMOTE_OPEN:
+    return "PN_CONNECTION_REMOTE_OPEN";
+  case PN_CONNECTION_OPEN:
+    return "PN_CONNECTION_OPEN";
+  case PN_CONNECTION_REMOTE_CLOSE:
+    return "PN_CONNECTION_REMOTE_CLOSE";
+  case PN_CONNECTION_CLOSE:
+    return "PN_CONNECTION_CLOSE";
+  case PN_CONNECTION_FINAL:
+    return "PN_CONNECTION_FINAL";
+  case PN_SESSION_INIT:
+    return "PN_SESSION_INIT";
+  case PN_SESSION_REMOTE_OPEN:
+    return "PN_SESSION_REMOTE_OPEN";
+  case PN_SESSION_OPEN:
+    return "PN_SESSION_OPEN";
+  case PN_SESSION_REMOTE_CLOSE:
+    return "PN_SESSION_REMOTE_CLOSE";
+  case PN_SESSION_CLOSE:
+    return "PN_SESSION_CLOSE";
+  case PN_SESSION_FINAL:
+    return "PN_SESSION_FINAL";
+  case PN_LINK_INIT:
+    return "PN_LINK_INIT";
+  case PN_LINK_REMOTE_OPEN:
+    return "PN_LINK_REMOTE_OPEN";
+  case PN_LINK_OPEN:
+    return "PN_LINK_OPEN";
+  case PN_LINK_REMOTE_CLOSE:
+    return "PN_LINK_REMOTE_CLOSE";
+  case PN_LINK_DETACH:
+    return "PN_LINK_DETACH";
+  case PN_LINK_REMOTE_DETACH:
+    return "PN_LINK_REMOTE_DETACH";
+  case PN_LINK_CLOSE:
+    return "PN_LINK_CLOSE";
+  case PN_LINK_FLOW:
+    return "PN_LINK_FLOW";
+  case PN_LINK_FINAL:
+    return "PN_LINK_FINAL";
+  case PN_DELIVERY:
+    return "PN_DELIVERY";
+  case PN_TRANSPORT:
+    return "PN_TRANSPORT";
+  case PN_TRANSPORT_ERROR:
+    return "PN_TRANSPORT_ERROR";
+  case PN_TRANSPORT_HEAD_CLOSED:
+    return "PN_TRANSPORT_HEAD_CLOSED";
+  case PN_TRANSPORT_TAIL_CLOSED:
+    return "PN_TRANSPORT_TAIL_CLOSED";
+  case PN_TRANSPORT_CLOSED:
+    return "PN_TRANSPORT_CLOSED";
+  }
+
+  return "<unrecognized>";
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/message/message.c
----------------------------------------------------------------------
diff --git a/proton-c/src/message/message.c b/proton-c/src/message/message.c
index d91ab63..c158345 100644
--- a/proton-c/src/message/message.c
+++ b/proton-c/src/message/message.c
@@ -29,8 +29,8 @@
 #include <stdio.h>
 #include <assert.h>
 #include "protocol.h"
-#include "../util.h"
-#include "../platform_fmt.h"
+#include "util.h"
+#include "platform_fmt.h"
 
 ssize_t pn_message_data(char *dst, size_t available, const char *src, size_t size)
 {
@@ -322,7 +322,7 @@ int pn_message_inspect(void *obj, pn_string_t *dst)
 pn_message_t *pn_message()
 {
   static const pn_class_t clazz = PN_CLASS(pn_message);
-  pn_message_t *msg = (pn_message_t *) pn_new(sizeof(pn_message_t), &clazz);
+  pn_message_t *msg = (pn_message_t *) pn_class_new(&clazz, sizeof(pn_message_t));
   msg->durable = false;
   msg->priority = PN_DEFAULT_PRIORITY;
   msg->ttl = 0;
@@ -975,6 +975,7 @@ int pn_message_save_data(pn_message_t *msg, char *data, size_t *size)
                                   pn_data_error(msg->body));
   if (scanned) {
     if (bytes.size > *size) {
+      *size = bytes.size;
       return PN_OVERFLOW;
     } else {
       memcpy(data, bytes.start, bytes.size);
@@ -997,6 +998,7 @@ int pn_message_save_text(pn_message_t *msg, char *data, size_t *size)
       {
         pn_bytes_t str = pn_data_get_bytes(msg->body);
         if (str.size >= *size) {
+          *size = str.size;
           return PN_OVERFLOW;
         } else {
           memcpy(data, str.start, str.size);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/messenger/messenger.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/messenger.c b/proton-c/src/messenger/messenger.c
index 0e2488b..f0204b9 100644
--- a/proton-c/src/messenger/messenger.c
+++ b/proton-c/src/messenger/messenger.c
@@ -20,10 +20,13 @@
  */
 
 #include <proton/messenger.h>
-#include <proton/sasl.h>
-#include <proton/ssl.h>
-#include <proton/util.h>
+
+#include <proton/connection.h>
+#include <proton/delivery.h>
+#include <proton/event.h>
 #include <proton/object.h>
+#include <proton/sasl.h>
+#include <proton/session.h>
 #include <proton/selector.h>
 
 #include <assert.h>
@@ -32,13 +35,13 @@
 #include <string.h>
 #include <stdio.h>
 
-#include "../util.h"
-#include "../platform.h"
-#include "../platform_fmt.h"
+#include "util.h"
+#include "platform.h"
+#include "platform_fmt.h"
 #include "store.h"
 #include "transform.h"
 #include "subscription.h"
-#include "../selectable.h"
+#include "selectable.h"
 
 typedef struct pn_link_ctx_t pn_link_ctx_t;
 
@@ -54,10 +57,11 @@ typedef struct {
 } pn_address_t;
 
 // algorithm for granting credit to receivers
-typedef  enum {
+typedef enum {
   // pn_messenger_recv( X ), where:
-  LINK_CREDIT_EXPLICIT,  // X > 0
-  LINK_CREDIT_AUTO   // X == -1
+  LINK_CREDIT_EXPLICIT, // X > 0
+  LINK_CREDIT_AUTO,     // X == -1
+  LINK_CREDIT_MANUAL    // X == -2
 } pn_link_credit_mode_t;
 
 struct pn_messenger_t {
@@ -100,6 +104,11 @@ struct pn_messenger_t {
   int receivers;     // # receiver links
   int draining;      // # links in drain state
   int connection_error;
+  int flags;
+  pn_snd_settle_mode_t snd_settle_mode;
+  pn_rcv_settle_mode_t rcv_settle_mode;
+  pn_tracer_t tracer;
+  pn_ssl_verify_mode_t ssl_peer_authentication_mode;
   bool blocking;
   bool passive;
   bool interrupted;
@@ -372,10 +381,14 @@ static pn_listener_ctx_t *pn_listener_ctx(pn_messenger_t *messenger,
   pn_socket_t socket = pn_listen(messenger->io, host, port ? port : default_port(scheme));
   if (socket == PN_INVALID_SOCKET) {
     pn_error_copy(messenger->error, pn_io_error(messenger->io));
+    pn_error_format(messenger->error, PN_ERR, "CONNECTION ERROR (%s:%s): %s\n",
+                    messenger->address.host, messenger->address.port,
+                    pn_error_text(messenger->error));
+
     return NULL;
   }
 
-  pn_listener_ctx_t *ctx = (pn_listener_ctx_t *) pn_new(sizeof(pn_listener_ctx_t), NULL);
+  pn_listener_ctx_t *ctx = (pn_listener_ctx_t *) pn_class_new(PN_OBJECT, sizeof(pn_listener_ctx_t));
   ctx->messenger = messenger;
   ctx->domain = pn_ssl_domain(PN_SSL_MODE_SERVER);
   if (messenger->certificate) {
@@ -596,7 +609,7 @@ pn_messenger_t *pn_messenger(const char *name)
     m->blocking = true;
     m->passive = false;
     m->io = pn_io();
-    m->pending = pn_list(0, 0);
+    m->pending = pn_list(PN_WEAKREF, 0);
     m->interruptor = pni_selectable
       (pni_interruptor_capacity, pni_interruptor_pending,
        pni_interruptor_deadline, pni_interruptor_readable,
@@ -611,8 +624,8 @@ pn_messenger_t *pn_messenger(const char *name)
     pn_pipe(m->io, m->ctrl);
     pni_selectable_set_fd(m->interruptor, m->ctrl[0]);
     pni_selectable_set_context(m->interruptor, m);
-    m->listeners = pn_list(0, 0);
-    m->connections = pn_list(0, 0);
+    m->listeners = pn_list(PN_WEAKREF, 0);
+    m->connections = pn_list(PN_WEAKREF, 0);
     m->selector = pn_io_selector(m->io);
     m->collector = pn_collector();
     m->credit_mode = LINK_CREDIT_EXPLICIT;
@@ -621,13 +634,13 @@ pn_messenger_t *pn_messenger(const char *name)
     m->distributed = 0;
     m->receivers = 0;
     m->draining = 0;
-    m->credited = pn_list(0, 0);
-    m->blocked = pn_list(0, 0);
+    m->credited = pn_list(PN_WEAKREF, 0);
+    m->blocked = pn_list(PN_WEAKREF, 0);
     m->next_drain = 0;
     m->next_tag = 0;
     m->outgoing = pni_store();
     m->incoming = pni_store();
-    m->subscriptions = pn_list(0, PN_REFCOUNT);
+    m->subscriptions = pn_list(PN_OBJECT, 0);
     m->incoming_subscription = NULL;
     m->error = pn_error();
     m->routes = pn_transform();
@@ -639,6 +652,11 @@ pn_messenger_t *pn_messenger(const char *name)
     m->rewritten = pn_string(NULL);
     m->domain = pn_string(NULL);
     m->connection_error = 0;
+    m->flags = 0;
+    m->snd_settle_mode = PN_SND_SETTLED;
+    m->rcv_settle_mode = PN_RCV_FIRST;
+    m->tracer = NULL;
+    m->ssl_peer_authentication_mode = PN_SSL_VERIFY_PEER_NAME;
   }
 
   return m;
@@ -840,6 +858,8 @@ bool pn_messenger_flow(pn_messenger_t *messenger)
     const int used = messenger->distributed + pn_messenger_incoming(messenger);
     if (max > used)
       messenger->credit = max - used;
+  } else if (messenger->credit_mode == LINK_CREDIT_MANUAL) {
+    return false;
   }
 
   const int batch = per_link_credit(messenger);
@@ -896,6 +916,8 @@ static int pn_transport_config(pn_messenger_t *messenger,
 {
   pn_connection_ctx_t *ctx = (pn_connection_ctx_t *) pn_connection_get_context(connection);
   pn_transport_t *transport = pn_connection_transport(connection);
+  if (messenger->tracer)
+    pn_transport_set_tracer(transport, messenger->tracer);
   if (ctx->scheme && !strcmp(ctx->scheme, "amqps")) {
     pn_ssl_domain_t *d = pn_ssl_domain(PN_SSL_MODE_CLIENT);
     if (messenger->certificate && messenger->private_key) {
@@ -913,7 +935,8 @@ static int pn_transport_config(pn_messenger_t *messenger,
         pn_error_report("CONNECTION", "invalid certificate db");
         return err;
       }
-      err = pn_ssl_domain_set_peer_authentication(d, PN_SSL_VERIFY_PEER_NAME, NULL);
+      err = pn_ssl_domain_set_peer_authentication(
+          d, messenger->ssl_peer_authentication_mode, NULL);
       if (err) {
         pn_error_report("CONNECTION", "error configuring ssl to verify peer");
       }
@@ -985,33 +1008,38 @@ int pni_pump_in(pn_messenger_t *messenger, const char *address, pn_link_t *recei
   n = pn_link_recv(receiver, encoded + pending, 1);
   pn_link_advance(receiver);
 
-  // account for the used credit
-  assert( ctx );
-  assert( messenger->distributed );
-  messenger->distributed--;
-
   pn_link_t *link = receiver;
 
-  // replenish if low (< 20% maximum batch) and credit available
-  if (!pn_link_get_drain(link) && pn_list_size(messenger->blocked) == 0 && messenger->credit > 0) {
-    const int max = per_link_credit(messenger);
-    const int lo_thresh = (int)(max * 0.2 + 0.5);
-    if (pn_link_remote_credit(link) < lo_thresh) {
-      const int more = pn_min(messenger->credit, max - pn_link_remote_credit(link));
-      messenger->credit -= more;
-      messenger->distributed += more;
-      pn_link_flow(link, more);
+  if (messenger->credit_mode != LINK_CREDIT_MANUAL) {
+    // account for the used credit
+    assert(ctx);
+    assert(messenger->distributed);
+    messenger->distributed--;
+
+    // replenish if low (< 20% maximum batch) and credit available
+    if (!pn_link_get_drain(link) && pn_list_size(messenger->blocked) == 0 &&
+        messenger->credit > 0) {
+      const int max = per_link_credit(messenger);
+      const int lo_thresh = (int)(max * 0.2 + 0.5);
+      if (pn_link_remote_credit(link) < lo_thresh) {
+        const int more =
+            pn_min(messenger->credit, max - pn_link_remote_credit(link));
+        messenger->credit -= more;
+        messenger->distributed += more;
+        pn_link_flow(link, more);
+      }
     }
-  }
-  // check if blocked
-  if (pn_list_index(messenger->blocked, link) < 0 && pn_link_remote_credit(link) == 0) {
-    pn_list_remove(messenger->credited, link);
-    if (pn_link_get_drain(link)) {
-      pn_link_set_drain(link, false);
-      assert( messenger->draining > 0 );
-      messenger->draining--;
+    // check if blocked
+    if (pn_list_index(messenger->blocked, link) < 0 &&
+        pn_link_remote_credit(link) == 0) {
+      pn_list_remove(messenger->credited, link);
+      if (pn_link_get_drain(link)) {
+        pn_link_set_drain(link, false);
+        assert(messenger->draining > 0);
+        messenger->draining--;
+      }
+      pn_list_add(messenger->blocked, link);
     }
-    pn_list_add(messenger->blocked, link);
   }
 
   if (n != PN_EOS) {
@@ -1248,8 +1276,10 @@ int pn_messenger_process_events(pn_messenger_t *messenger)
       break;
     case PN_LINK_REMOTE_OPEN:
     case PN_LINK_REMOTE_CLOSE:
+    case PN_LINK_REMOTE_DETACH:
     case PN_LINK_OPEN:
     case PN_LINK_CLOSE:
+    case PN_LINK_DETACH:
       pn_messenger_process_link(messenger, event);
       break;
     case PN_LINK_FLOW:
@@ -1259,10 +1289,18 @@ int pn_messenger_process_events(pn_messenger_t *messenger)
       pn_messenger_process_delivery(messenger, event);
       break;
     case PN_TRANSPORT:
+    case PN_TRANSPORT_ERROR:
+    case PN_TRANSPORT_HEAD_CLOSED:
+    case PN_TRANSPORT_TAIL_CLOSED:
+    case PN_TRANSPORT_CLOSED:
       pn_messenger_process_transport(messenger, event);
       break;
     case PN_EVENT_NONE:
       break;
+    case PN_CONNECTION_BOUND:
+      break;
+    case PN_CONNECTION_UNBOUND:
+      break;
     case PN_CONNECTION_FINAL:
       break;
     case PN_SESSION_FINAL:
@@ -1422,11 +1460,85 @@ int pn_messenger_sync(pn_messenger_t *messenger, bool (*predicate)(pn_messenger_
   }
 }
 
+static void pni_parse(pn_address_t *address);
+pn_connection_t *pn_messenger_resolve(pn_messenger_t *messenger,
+                                      const char *address, char **name);
+int pn_messenger_work(pn_messenger_t *messenger, int timeout);
+
 int pn_messenger_start(pn_messenger_t *messenger)
 {
   if (!messenger) return PN_ARG_ERR;
-  // right now this is a noop
-  return 0;
+
+  int error = 0;
+
+  // When checking of routes is required we attempt to resolve each route
+  // with a substitution that has a defined scheme, address and port. If
+  // any of theses routes is invalid an appropriate error code will be
+  // returned. Currently no attempt is made to check the name part of the
+  // address, as the intent here is to fail fast if the addressed host
+  // is invalid or unavailable.
+  if (messenger->flags | PN_FLAGS_CHECK_ROUTES) {
+    pn_list_t *substitutions = pn_list(PN_WEAKREF, 0);
+    pn_transform_get_substitutions(messenger->routes, substitutions);
+    for (size_t i = 0; i < pn_list_size(substitutions) && error == 0; i++) {
+      pn_string_t *substitution = (pn_string_t *)pn_list_get(substitutions, i);
+      if (substitution) {
+        pn_address_t addr;
+        addr.text = pn_string(NULL);
+        error = pn_string_copy(addr.text, substitution);
+        if (!error) {
+          pni_parse(&addr);
+          if (addr.scheme && strlen(addr.scheme) > 0 &&
+              !strstr(addr.scheme, "$") && addr.host && strlen(addr.host) > 0 &&
+              !strstr(addr.host, "$") && addr.port && strlen(addr.port) > 0 &&
+              !strstr(addr.port, "$")) {
+            pn_string_t *check_addr = pn_string(NULL);
+            // ipv6 hosts need to be wrapped in [] within a URI
+            if (strstr(addr.host, ":")) {
+              pn_string_format(check_addr, "%s://[%s]:%s/", addr.scheme,
+                               addr.host, addr.port);
+            } else {
+              pn_string_format(check_addr, "%s://%s:%s/", addr.scheme,
+                               addr.host, addr.port);
+            }
+            char *name = NULL;
+            pn_connection_t *connection = pn_messenger_resolve(
+                messenger, pn_string_get(check_addr), &name);
+            pn_free(check_addr);
+            if (!connection) {
+              if (pn_error_code(messenger->error) == 0)
+                pn_error_copy(messenger->error, pn_io_error(messenger->io));
+              pn_error_format(messenger->error, PN_ERR,
+                              "CONNECTION ERROR (%s:%s): %s\n",
+                              messenger->address.host, messenger->address.port,
+                              pn_error_text(messenger->error));
+              error = pn_error_code(messenger->error);
+            } else {
+              // Send and receive outstanding messages until connection
+              // completes or an error occurs
+              int work = pn_messenger_work(messenger, -1);
+              pn_connection_ctx_t *cctx =
+                  (pn_connection_ctx_t *)pn_connection_get_context(connection);
+              while ((work > 0 ||
+                      (pn_connection_state(connection) & PN_REMOTE_UNINIT) ||
+                      pni_connection_pending(cctx->selectable) != (ssize_t)0) &&
+                     pn_error_code(messenger->error) == 0)
+                work = pn_messenger_work(messenger, 0);
+              if (work < 0 && work != PN_TIMEOUT) {
+                error = work;
+              } else {
+                error = pn_error_code(messenger->error);
+              }
+            }
+          }
+          pn_free(addr.text);
+        }
+      }
+    }
+    pn_free(substitutions);
+  }
+
+  return error;
 }
 
 bool pn_messenger_stopped(pn_messenger_t *messenger)
@@ -1560,12 +1672,12 @@ pn_connection_t *pn_messenger_resolve(pn_messenger_t *messenger, const char *add
   return connection;
 }
 
-pn_link_t *pn_messenger_link(pn_messenger_t *messenger, const char *address, bool sender)
+PN_EXTERN pn_link_t *pn_messenger_get_link(pn_messenger_t *messenger,
+                                           const char *address, bool sender)
 {
   char *name = NULL;
   pn_connection_t *connection = pn_messenger_resolve(messenger, address, &name);
   if (!connection) return NULL;
-  pn_connection_ctx_t *cctx = (pn_connection_ctx_t *) pn_connection_get_context(connection);
 
   pn_link_t *link = pn_link_head(connection, PN_LOCAL_ACTIVE);
   while (link) {
@@ -1578,6 +1690,22 @@ pn_link_t *pn_messenger_link(pn_messenger_t *messenger, const char *address, boo
     }
     link = pn_link_next(link, PN_LOCAL_ACTIVE);
   }
+  return NULL;
+}
+
+pn_link_t *pn_messenger_link(pn_messenger_t *messenger, const char *address,
+                             bool sender, pn_seconds_t timeout)
+{
+  char *name = NULL;
+  pn_connection_t *connection = pn_messenger_resolve(messenger, address, &name);
+  if (!connection)
+    return NULL;
+  pn_connection_ctx_t *cctx =
+      (pn_connection_ctx_t *)pn_connection_get_context(connection);
+
+  pn_link_t *link = pn_messenger_get_link(messenger, address, sender);
+  if (link)
+    return link;
 
   pn_session_t *ssn = pn_session(connection);
   pn_session_open(ssn);
@@ -1593,9 +1721,9 @@ pn_link_t *pn_messenger_link(pn_messenger_t *messenger, const char *address, boo
 
   if ((sender && pn_messenger_get_outgoing_window(messenger)) ||
       (!sender && pn_messenger_get_incoming_window(messenger))) {
-    // use explicit settlement via dispositions (not pre-settled)
-    pn_link_set_snd_settle_mode( link, PN_SND_UNSETTLED );
-    pn_link_set_rcv_settle_mode( link, PN_RCV_SECOND );
+    // use required settlement (defaults to sending pre-settled messages)
+    pn_link_set_snd_settle_mode(link, messenger->snd_settle_mode);
+    pn_link_set_rcv_settle_mode(link, messenger->rcv_settle_mode);
   }
   // XXX
   if (pn_streq(name, "#")) {
@@ -1609,6 +1737,14 @@ pn_link_t *pn_messenger_link(pn_messenger_t *messenger, const char *address, boo
     pn_terminus_set_address(pn_link_source(link), name);
   }
   link_ctx_setup( messenger, connection, link );
+
+  if (timeout > 0) {
+    pn_terminus_set_expiry_policy(pn_link_target(link), PN_EXPIRE_WITH_LINK);
+    pn_terminus_set_expiry_policy(pn_link_source(link), PN_EXPIRE_WITH_LINK);
+    pn_terminus_set_timeout(pn_link_target(link), timeout);
+    pn_terminus_set_timeout(pn_link_source(link), timeout);
+  }
+
   if (!sender) {
     pn_link_ctx_t *ctx = (pn_link_ctx_t *)pn_link_get_context(link);
     assert( ctx );
@@ -1619,18 +1755,27 @@ pn_link_t *pn_messenger_link(pn_messenger_t *messenger, const char *address, boo
   return link;
 }
 
-pn_link_t *pn_messenger_source(pn_messenger_t *messenger, const char *source)
+pn_link_t *pn_messenger_source(pn_messenger_t *messenger, const char *source,
+                               pn_seconds_t timeout)
 {
-  return pn_messenger_link(messenger, source, false);
+  return pn_messenger_link(messenger, source, false, timeout);
 }
 
-pn_link_t *pn_messenger_target(pn_messenger_t *messenger, const char *target)
+pn_link_t *pn_messenger_target(pn_messenger_t *messenger, const char *target,
+                               pn_seconds_t timeout)
 {
-  return pn_messenger_link(messenger, target, true);
+  return pn_messenger_link(messenger, target, true, timeout);
 }
 
 pn_subscription_t *pn_messenger_subscribe(pn_messenger_t *messenger, const char *source)
 {
+  return pn_messenger_subscribe_ttl(messenger, source, 0);
+}
+
+pn_subscription_t *pn_messenger_subscribe_ttl(pn_messenger_t *messenger,
+                                              const char *source,
+                                              pn_seconds_t timeout)
+{
   pni_route(messenger, source);
   if (pn_error_code(messenger->error)) return NULL;
 
@@ -1647,7 +1792,7 @@ pn_subscription_t *pn_messenger_subscribe(pn_messenger_t *messenger, const char
       return NULL;
     }
   } else {
-    pn_link_t *src = pn_messenger_source(messenger, source);
+    pn_link_t *src = pn_messenger_source(messenger, source, timeout);
     if (!src) return NULL;
     pn_link_ctx_t *ctx = (pn_link_ctx_t *) pn_link_get_context( src );
     return ctx ? ctx->subscription : NULL;
@@ -1820,7 +1965,7 @@ int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg)
     } else {
       pni_restore(messenger, msg);
       pn_buffer_append(buf, encoded, size); // XXX
-      pn_link_t *sender = pn_messenger_target(messenger, address);
+      pn_link_t *sender = pn_messenger_target(messenger, address, 0);
       if (!sender) {
         int err = pn_error_code(messenger->error);
         if (err) {
@@ -1865,6 +2010,18 @@ pn_status_t pn_messenger_status(pn_messenger_t *messenger, pn_tracker_t tracker)
   }
 }
 
+pn_delivery_t *pn_messenger_delivery(pn_messenger_t *messenger,
+                                     pn_tracker_t tracker)
+{
+  pni_store_t *store = pn_tracker_store(messenger, tracker);
+  pni_entry_t *e = pni_store_entry(store, pn_tracker_sequence(tracker));
+  if (e) {
+    return pni_entry_get_delivery(e);
+  } else {
+    return NULL;
+  }
+}
+
 bool pn_messenger_buffered(pn_messenger_t *messenger, pn_tracker_t tracker)
 {
   pni_store_t *store = pn_tracker_store(messenger, tracker);
@@ -2007,7 +2164,9 @@ int pn_messenger_recv(pn_messenger_t *messenger, int n)
     return pn_error_format(messenger->error, PN_STATE_ERR, "no valid sources");
 
   // re-compute credit, and update credit scheduler
-  if (n == -1) {
+  if (n == -2) {
+    messenger->credit_mode = LINK_CREDIT_MANUAL;
+  } else if (n == -1) {
     messenger->credit_mode = LINK_CREDIT_AUTO;
   } else {
     messenger->credit_mode = LINK_CREDIT_EXPLICIT;
@@ -2100,6 +2259,20 @@ int pn_messenger_reject(pn_messenger_t *messenger, pn_tracker_t tracker, int fla
                           PN_STATUS_REJECTED, flags, false, false);
 }
 
+PN_EXTERN pn_link_t *pn_messenger_tracker_link(pn_messenger_t *messenger,
+                                               pn_tracker_t tracker)
+{
+  pni_store_t *store = pn_tracker_store(messenger, tracker);
+  pni_entry_t *e = pni_store_entry(store, pn_tracker_sequence(tracker));
+  if (e) {
+    pn_delivery_t *d = pni_entry_get_delivery(e);
+    if (d) {
+      return pn_delivery_link(d);
+    }
+  }
+  return NULL;
+}
+
 int pn_messenger_queued(pn_messenger_t *messenger, bool sender)
 {
   if (!messenger) return 0;
@@ -2146,3 +2319,81 @@ int pn_messenger_rewrite(pn_messenger_t *messenger, const char *pattern, const c
   pn_transform_rule(messenger->rewrites, pattern, address);
   return 0;
 }
+
+PN_EXTERN int pn_messenger_set_flags(pn_messenger_t *messenger, const int flags)
+{
+  if (!messenger)
+    return PN_ARG_ERR;
+  if (flags != 0 && (flags ^ PN_FLAGS_CHECK_ROUTES) != 0)
+    return PN_ARG_ERR;
+  messenger->flags = flags;
+  return 0;
+}
+
+PN_EXTERN int pn_messenger_get_flags(pn_messenger_t *messenger)
+{
+  return messenger ? messenger->flags : 0;
+}
+
+int pn_messenger_set_snd_settle_mode(pn_messenger_t *messenger,
+                                     const pn_snd_settle_mode_t mode)
+{
+  if (!messenger)
+    return PN_ARG_ERR;
+  messenger->snd_settle_mode = mode;
+  return 0;
+}
+
+int pn_messenger_set_rcv_settle_mode(pn_messenger_t *messenger,
+                                     const pn_rcv_settle_mode_t mode)
+{
+  if (!messenger)
+    return PN_ARG_ERR;
+  messenger->rcv_settle_mode = mode;
+  return 0;
+}
+
+void pn_messenger_set_tracer(pn_messenger_t *messenger, pn_tracer_t tracer)
+{
+  assert(messenger);
+  assert(tracer);
+
+  messenger->tracer = tracer;
+}
+
+pn_millis_t pn_messenger_get_remote_idle_timeout(pn_messenger_t *messenger,
+                                                 const char *address)
+{
+  if (!messenger)
+    return PN_ARG_ERR;
+
+  pn_address_t addr;
+  addr.text = pn_string(address);
+  pni_parse(&addr);
+
+  pn_millis_t timeout = -1;
+  for (size_t i = 0; i < pn_list_size(messenger->connections); i++) {
+    pn_connection_t *connection =
+        (pn_connection_t *)pn_list_get(messenger->connections, i);
+    pn_connection_ctx_t *ctx =
+        (pn_connection_ctx_t *)pn_connection_get_context(connection);
+    if (pn_streq(addr.scheme, ctx->scheme) && pn_streq(addr.host, ctx->host) &&
+        pn_streq(addr.port, ctx->port)) {
+      pn_transport_t *transport = pn_connection_transport(connection);
+      if (transport)
+        timeout = pn_transport_get_remote_idle_timeout(transport);
+      break;
+    }
+  }
+  return timeout;
+}
+
+int
+pn_messenger_set_ssl_peer_authentication_mode(pn_messenger_t *messenger,
+                                              const pn_ssl_verify_mode_t mode)
+{
+  if (!messenger)
+    return PN_ARG_ERR;
+  messenger->ssl_peer_authentication_mode = mode;
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/messenger/store.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/store.c b/proton-c/src/messenger/store.c
index 88d6a5d..83b9b68 100644
--- a/proton-c/src/messenger/store.c
+++ b/proton-c/src/messenger/store.c
@@ -28,7 +28,7 @@
 #endif
 #include <stdlib.h>
 #include <string.h>
-#include "../util.h"
+#include "util.h"
 #include "store.h"
 
 typedef struct pni_stream_t pni_stream_t;
@@ -89,7 +89,7 @@ pni_store_t *pni_store()
   store->window = 0;
   store->lwm = 0;
   store->hwm = 0;
-  store->tracked = pn_hash(0, 0.75, PN_REFCOUNT);
+  store->tracked = pn_hash(PN_OBJECT, 0, 0.75);
 
   return store;
 }
@@ -197,6 +197,7 @@ pni_stream_t *pni_stream_get(pni_store_t *store, const char *address)
   return pni_stream(store, address, false);
 }
 
+#define CID_pni_entry CID_pn_object
 #define pni_entry_initialize NULL
 #define pni_entry_hashcode NULL
 #define pni_entry_compare NULL
@@ -210,7 +211,7 @@ pni_entry_t *pni_store_put(pni_store_t *store, const char *address)
   if (!address) address = "";
   pni_stream_t *stream = pni_stream_put(store, address);
   if (!stream) return NULL;
-  pni_entry_t *entry = (pni_entry_t *) pn_new(sizeof(pni_entry_t), &clazz);
+  pni_entry_t *entry = (pni_entry_t *) pn_class_new(&clazz, sizeof(pni_entry_t));
   if (!entry) return NULL;
   entry->stream = stream;
   entry->free = false;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/messenger/subscription.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/subscription.c b/proton-c/src/messenger/subscription.c
index 346a23f..c26d40a 100644
--- a/proton-c/src/messenger/subscription.c
+++ b/proton-c/src/messenger/subscription.c
@@ -55,6 +55,7 @@ void pn_subscription_finalize(void *obj)
   pn_free(sub->address);
 }
 
+#define CID_pn_subscription CID_pn_object
 #define pn_subscription_hashcode NULL
 #define pn_subscription_compare NULL
 #define pn_subscription_inspect NULL
@@ -65,13 +66,13 @@ pn_subscription_t *pn_subscription(pn_messenger_t *messenger,
                                    const char *port)
 {
   static const pn_class_t clazz = PN_CLASS(pn_subscription);
-  pn_subscription_t *sub = (pn_subscription_t *) pn_new(sizeof(pn_subscription_t), &clazz);
+  pn_subscription_t *sub = (pn_subscription_t *) pn_class_new(&clazz, sizeof(pn_subscription_t));
   sub->messenger = messenger;
   pn_string_set(sub->scheme, scheme);
   pn_string_set(sub->host, host);
   pn_string_set(sub->port, port);
   pni_messenger_add_subscription(messenger, sub);
-  pn_decref(sub);
+  pn_class_decref(PN_OBJECT, sub);
   return sub;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/messenger/transform.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/transform.c b/proton-c/src/messenger/transform.c
index 801eb10..8f18667 100644
--- a/proton-c/src/messenger/transform.c
+++ b/proton-c/src/messenger/transform.c
@@ -19,7 +19,6 @@
  *
  */
 
-#include <proton/object.h>
 #include <string.h>
 #include <assert.h>
 #include <ctype.h>
@@ -55,6 +54,7 @@ static void pn_rule_finalize(void *object)
   pn_free(rule->substitution);
 }
 
+#define CID_pn_rule CID_pn_object
 #define pn_rule_initialize NULL
 #define pn_rule_hashcode NULL
 #define pn_rule_compare NULL
@@ -63,7 +63,7 @@ static void pn_rule_finalize(void *object)
 pn_rule_t *pn_rule(const char *pattern, const char *substitution)
 {
   static const pn_class_t clazz = PN_CLASS(pn_rule);
-  pn_rule_t *rule = (pn_rule_t *) pn_new(sizeof(pn_rule_t), &clazz);
+  pn_rule_t *rule = (pn_rule_t *) pn_class_new(&clazz, sizeof(pn_rule_t));
   rule->pattern = pn_string(pattern);
   rule->substitution = pn_string(substitution);
   return rule;
@@ -75,6 +75,7 @@ static void pn_transform_finalize(void *object)
   pn_free(transform->rules);
 }
 
+#define CID_pn_transform CID_pn_object
 #define pn_transform_initialize NULL
 #define pn_transform_hashcode NULL
 #define pn_transform_compare NULL
@@ -83,8 +84,8 @@ static void pn_transform_finalize(void *object)
 pn_transform_t *pn_transform()
 {
   static const pn_class_t clazz = PN_CLASS(pn_transform);
-  pn_transform_t *transform = (pn_transform_t *) pn_new(sizeof(pn_transform_t), &clazz);
-  transform->rules = pn_list(0, PN_REFCOUNT);
+  pn_transform_t *transform = (pn_transform_t *) pn_class_new(&clazz, sizeof(pn_transform_t));
+  transform->rules = pn_list(PN_OBJECT, 0);
   transform->matched = false;
   return transform;
 }
@@ -239,3 +240,15 @@ bool pn_transform_matched(pn_transform_t *transform)
 {
   return transform->matched;
 }
+
+int pn_transform_get_substitutions(pn_transform_t *transform,
+                                   pn_list_t *substitutions)
+{
+  int size = pn_list_size(transform->rules);
+  for (size_t i = 0; i < (size_t)size; i++) {
+    pn_rule_t *rule = (pn_rule_t *)pn_list_get(transform->rules, i);
+    pn_list_add(substitutions, rule->substitution);
+  }
+
+  return size;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/messenger/transform.h
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/transform.h b/proton-c/src/messenger/transform.h
index 1662f38..8160be3 100644
--- a/proton-c/src/messenger/transform.h
+++ b/proton-c/src/messenger/transform.h
@@ -22,6 +22,7 @@
  *
  */
 
+#include <proton/object.h>
 #include <proton/buffer.h>
 
 typedef struct pn_transform_t pn_transform_t;
@@ -32,6 +33,7 @@ void pn_transform_rule(pn_transform_t *transform, const char *pattern,
 int pn_transform_apply(pn_transform_t *transform, const char *src,
                        pn_string_t *dest);
 bool pn_transform_matched(pn_transform_t *transform);
-
+int pn_transform_get_substitutions(pn_transform_t *transform,
+                                   pn_list_t *substitutions);
 
 #endif /* transform.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/object/iterator.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/iterator.c b/proton-c/src/object/iterator.c
new file mode 100644
index 0000000..61b3b8e
--- /dev/null
+++ b/proton-c/src/object/iterator.c
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct pn_iterator_t {
+  pn_iterator_next_t next;
+  size_t size;
+  void *state;
+};
+
+static void pn_iterator_initialize(void *object)
+{
+  pn_iterator_t *it = (pn_iterator_t *) object;
+  it->next = NULL;
+  it->size = 0;
+  it->state = NULL;
+}
+
+static void pn_iterator_finalize(void *object)
+{
+  pn_iterator_t *it = (pn_iterator_t *) object;
+  free(it->state);
+}
+
+#define CID_pn_iterator CID_pn_object
+#define pn_iterator_hashcode NULL
+#define pn_iterator_compare NULL
+#define pn_iterator_inspect NULL
+
+pn_iterator_t *pn_iterator()
+{
+  static const pn_class_t clazz = PN_CLASS(pn_iterator);
+  pn_iterator_t *it = (pn_iterator_t *) pn_class_new(&clazz, sizeof(pn_iterator_t));
+  return it;
+}
+
+void  *pn_iterator_start(pn_iterator_t *iterator, pn_iterator_next_t next,
+                         size_t size) {
+  assert(iterator);
+  assert(next);
+  iterator->next = next;
+  if (iterator->size < size) {
+    iterator->state = realloc(iterator->state, size);
+  }
+  return iterator->state;
+}
+
+void *pn_iterator_next(pn_iterator_t *iterator) {
+  assert(iterator);
+  if (iterator->next) {
+    void *result = iterator->next(iterator->state);
+    if (!result) iterator->next = NULL;
+    return result;
+  } else {
+    return NULL;
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/object/list.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/list.c b/proton-c/src/object/list.c
new file mode 100644
index 0000000..7936f5b
--- /dev/null
+++ b/proton-c/src/object/list.c
@@ -0,0 +1,225 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct pn_list_t {
+  const pn_class_t *clazz;
+  size_t capacity;
+  size_t size;
+  void **elements;
+};
+
+size_t pn_list_size(pn_list_t *list)
+{
+  assert(list);
+  return list->size;
+}
+
+void *pn_list_get(pn_list_t *list, int index)
+{
+  assert(list); assert(list->size);
+  return list->elements[index % list->size];
+}
+
+void pn_list_set(pn_list_t *list, int index, void *value)
+{
+  assert(list); assert(list->size);
+  void *old = list->elements[index % list->size];
+  pn_class_decref(list->clazz, old);
+  list->elements[index % list->size] = value;
+  pn_class_incref(list->clazz, value);
+}
+
+void pn_list_ensure(pn_list_t *list, size_t capacity)
+{
+  assert(list);
+  if (list->capacity < capacity) {
+    size_t newcap = list->capacity;
+    while (newcap < capacity) { newcap *= 2; }
+    list->elements = (void **) realloc(list->elements, newcap * sizeof(void *));
+    assert(list->elements);
+    list->capacity = newcap;
+  }
+}
+
+int pn_list_add(pn_list_t *list, void *value)
+{
+  assert(list);
+  pn_list_ensure(list, list->size + 1);
+  list->elements[list->size++] = value;
+  pn_class_incref(list->clazz, value);
+  return 0;
+}
+
+ssize_t pn_list_index(pn_list_t *list, void *value)
+{
+  for (size_t i = 0; i < list->size; i++) {
+    if (pn_equals(list->elements[i], value)) {
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+bool pn_list_remove(pn_list_t *list, void *value)
+{
+  assert(list);
+  ssize_t idx = pn_list_index(list, value);
+  if (idx < 0) {
+    return false;
+  } else {
+    pn_list_del(list, idx, 1);
+  }
+
+  return true;
+}
+
+void pn_list_del(pn_list_t *list, int index, int n)
+{
+  assert(list);
+  index %= list->size;
+
+  for (int i = 0; i < n; i++) {
+    pn_class_decref(list->clazz, list->elements[index + i]);
+  }
+
+  size_t slide = list->size - (index + n);
+  for (size_t i = 0; i < slide; i++) {
+    list->elements[index + i] = list->elements[index + n + i];
+  }
+
+  list->size -= n;
+}
+
+void pn_list_clear(pn_list_t *list)
+{
+  assert(list);
+  pn_list_del(list, 0, list->size);
+}
+
+void pn_list_fill(pn_list_t *list, void *value, int n)
+{
+  for (int i = 0; i < n; i++) {
+    pn_list_add(list, value);
+  }
+}
+
+typedef struct {
+  pn_list_t *list;
+  size_t index;
+} pni_list_iter_t;
+
+static void *pni_list_next(void *ctx)
+{
+  pni_list_iter_t *iter = (pni_list_iter_t *) ctx;
+  if (iter->index < pn_list_size(iter->list)) {
+    return pn_list_get(iter->list, iter->index++);
+  } else {
+    return NULL;
+  }
+}
+
+void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter)
+{
+  pni_list_iter_t *liter = (pni_list_iter_t *) pn_iterator_start(iter, pni_list_next, sizeof(pni_list_iter_t));
+  liter->list = list;
+  liter->index = 0;
+}
+
+static void pn_list_finalize(void *object)
+{
+  assert(object);
+  pn_list_t *list = (pn_list_t *) object;
+  for (size_t i = 0; i < list->size; i++) {
+    pn_class_decref(list->clazz, pn_list_get(list, i));
+  }
+  free(list->elements);
+}
+
+static uintptr_t pn_list_hashcode(void *object)
+{
+  assert(object);
+  pn_list_t *list = (pn_list_t *) object;
+  uintptr_t hash = 1;
+
+  for (size_t i = 0; i < list->size; i++) {
+    hash = hash * 31 + pn_hashcode(pn_list_get(list, i));
+  }
+
+  return hash;
+}
+
+static intptr_t pn_list_compare(void *oa, void *ob)
+{
+  assert(oa); assert(ob);
+  pn_list_t *a = (pn_list_t *) oa;
+  pn_list_t *b = (pn_list_t *) ob;
+
+  size_t na = pn_list_size(a);
+  size_t nb = pn_list_size(b);
+  if (na != nb) {
+    return nb - na;
+  } else {
+    for (size_t i = 0; i < na; i++) {
+      intptr_t delta = pn_compare(pn_list_get(a, i), pn_list_get(b, i));
+      if (delta) return delta;
+    }
+  }
+
+  return 0;
+}
+
+static int pn_list_inspect(void *obj, pn_string_t *dst)
+{
+  assert(obj);
+  pn_list_t *list = (pn_list_t *) obj;
+  int err = pn_string_addf(dst, "[");
+  if (err) return err;
+  size_t n = pn_list_size(list);
+  for (size_t i = 0; i < n; i++) {
+    if (i > 0) {
+      err = pn_string_addf(dst, ", ");
+      if (err) return err;
+    }
+    err = pn_class_inspect(list->clazz, pn_list_get(list, i), dst);
+    if (err) return err;
+  }
+  return pn_string_addf(dst, "]");
+}
+
+#define pn_list_initialize NULL
+
+pn_list_t *pn_list(const pn_class_t *clazz, size_t capacity)
+{
+  static const pn_class_t list_clazz = PN_CLASS(pn_list);
+
+  pn_list_t *list = (pn_list_t *) pn_class_new(&list_clazz, sizeof(pn_list_t));
+  list->clazz = clazz;
+  list->capacity = capacity ? capacity : 16;
+  list->elements = (void **) malloc(list->capacity * sizeof(void *));
+  list->size = 0;
+  return list;
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-c/src/object/map.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/map.c b/proton-c/src/object/map.c
new file mode 100644
index 0000000..fc98116
--- /dev/null
+++ b/proton-c/src/object/map.c
@@ -0,0 +1,401 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define PNI_ENTRY_FREE (0)
+#define PNI_ENTRY_LINK (1)
+#define PNI_ENTRY_TAIL (2)
+
+typedef struct {
+  void *key;
+  void *value;
+  size_t next;
+  uint8_t state;
+} pni_entry_t;
+
+struct pn_map_t {
+  const pn_class_t *key;
+  const pn_class_t *value;
+  pni_entry_t *entries;
+  size_t capacity;
+  size_t addressable;
+  size_t size;
+  uintptr_t (*hashcode)(void *key);
+  bool (*equals)(void *a, void *b);
+  float load_factor;
+};
+
+static void pn_map_finalize(void *object)
+{
+  pn_map_t *map = (pn_map_t *) object;
+
+  for (size_t i = 0; i < map->capacity; i++) {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      pn_class_decref(map->key, map->entries[i].key);
+      pn_class_decref(map->value, map->entries[i].value);
+    }
+  }
+
+  free(map->entries);
+}
+
+static uintptr_t pn_map_hashcode(void *object)
+{
+  pn_map_t *map = (pn_map_t *) object;
+
+  uintptr_t hashcode = 0;
+
+  for (size_t i = 0; i < map->capacity; i++) {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      void *key = map->entries[i].key;
+      void *value = map->entries[i].value;
+      hashcode += pn_hashcode(key) ^ pn_hashcode(value);
+    }
+  }
+
+  return hashcode;
+}
+
+static void pni_map_allocate(pn_map_t *map)
+{
+  map->entries = (pni_entry_t *) malloc(map->capacity * sizeof (pni_entry_t));
+  for (size_t i = 0; i < map->capacity; i++) {
+    map->entries[i].key = NULL;
+    map->entries[i].value = NULL;
+    map->entries[i].next = 0;
+    map->entries[i].state = PNI_ENTRY_FREE;
+  }
+  map->size = 0;
+}
+
+static int pn_map_inspect(void *obj, pn_string_t *dst)
+{
+  assert(obj);
+  pn_map_t *map = (pn_map_t *) obj;
+  int err = pn_string_addf(dst, "{");
+  if (err) return err;
+  pn_handle_t entry = pn_map_head(map);
+  bool first = true;
+  while (entry) {
+    if (first) {
+      first = false;
+    } else {
+      err = pn_string_addf(dst, ", ");
+      if (err) return err;
+    }
+    err = pn_class_inspect(map->key, pn_map_key(map, entry), dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ": ");
+    if (err) return err;
+    err = pn_class_inspect(map->value, pn_map_value(map, entry), dst);
+    if (err) return err;
+    entry = pn_map_next(map, entry);
+  }
+  return pn_string_addf(dst, "}");
+}
+
+#define pn_map_initialize NULL
+#define pn_map_compare NULL
+
+pn_map_t *pn_map(const pn_class_t *key, const pn_class_t *value,
+                 size_t capacity, float load_factor)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_map);
+
+  pn_map_t *map = (pn_map_t *) pn_class_new(&clazz, sizeof(pn_map_t));
+  map->key = key;
+  map->value = value;
+  map->capacity = capacity ? capacity : 16;
+  map->addressable = (size_t) (map->capacity * 0.86);
+  if (!map->addressable) map->addressable = map->capacity;
+  map->load_factor = load_factor;
+  map->hashcode = pn_hashcode;
+  map->equals = pn_equals;
+  pni_map_allocate(map);
+  return map;
+}
+
+size_t pn_map_size(pn_map_t *map)
+{
+  assert(map);
+  return map->size;
+}
+
+static float pni_map_load(pn_map_t *map)
+{
+  return ((float) map->size) / ((float) map->addressable);
+}
+
+static bool pni_map_ensure(pn_map_t *map, size_t capacity)
+{
+  float load = pni_map_load(map);
+  if (capacity <= map->capacity && load <= map->load_factor) {
+    return false;
+  }
+
+  size_t oldcap = map->capacity;
+
+  while (map->capacity < capacity || pni_map_load(map) > map->load_factor) {
+    map->capacity *= 2;
+    map->addressable = (size_t) (0.86 * map->capacity);
+  }
+
+  pni_entry_t *entries = map->entries;
+  pni_map_allocate(map);
+
+  for (size_t i = 0; i < oldcap; i++) {
+    if (entries[i].state != PNI_ENTRY_FREE) {
+      void *key = entries[i].key;
+      void *value = entries[i].value;
+      pn_map_put(map, key, value);
+      pn_class_decref(map->key, key);
+      pn_class_decref(map->value, value);
+    }
+  }
+
+  free(entries);
+  return true;
+}
+
+static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev, bool create)
+{
+  uintptr_t hashcode = map->hashcode(key);
+
+  pni_entry_t *entry = &map->entries[hashcode % map->addressable];
+  pni_entry_t *prev = NULL;
+
+  if (entry->state == PNI_ENTRY_FREE) {
+    if (create) {
+      entry->state = PNI_ENTRY_TAIL;
+      entry->key = key;
+      pn_class_incref(map->key, key);
+      map->size++;
+      return entry;
+    } else {
+      return NULL;
+    }
+  }
+
+  while (true) {
+    if (map->equals(entry->key, key)) {
+      if (pprev) *pprev = prev;
+      return entry;
+    }
+
+    if (entry->state == PNI_ENTRY_TAIL) {
+      break;
+    } else {
+      prev = entry;
+      entry = &map->entries[entry->next];
+    }
+  }
+
+  if (create) {
+    if (pni_map_ensure(map, map->size + 1)) {
+      // if we had to grow the table we need to start over
+      return pni_map_entry(map, key, pprev, create);
+    }
+
+    size_t empty = 0;
+    for (size_t i = 0; i < map->capacity; i++) {
+      size_t idx = map->capacity - i - 1;
+      if (map->entries[idx].state == PNI_ENTRY_FREE) {
+        empty = idx;
+        break;
+      }
+    }
+    entry->next = empty;
+    entry->state = PNI_ENTRY_LINK;
+    map->entries[empty].state = PNI_ENTRY_TAIL;
+    map->entries[empty].key = key;
+    pn_class_incref(map->key, key);
+    if (pprev) *pprev = entry;
+    map->size++;
+    return &map->entries[empty];
+  } else {
+    return NULL;
+  }
+}
+
+int pn_map_put(pn_map_t *map, void *key, void *value)
+{
+  assert(map);
+  pni_entry_t *entry = pni_map_entry(map, key, NULL, true);
+  pn_class_decref(map->value, entry->value);
+  entry->value = value;
+  pn_class_incref(map->value, value);
+  return 0;
+}
+
+void *pn_map_get(pn_map_t *map, void *key)
+{
+  assert(map);
+  pni_entry_t *entry = pni_map_entry(map, key, NULL, false);
+  return entry ? entry->value : NULL;
+}
+
+void pn_map_del(pn_map_t *map, void *key)
+{
+  assert(map);
+  pni_entry_t *prev = NULL;
+  pni_entry_t *entry = pni_map_entry(map, key, &prev, false);
+  if (entry) {
+    void *dref_key = entry->key;
+    void *dref_value = entry->value;
+    if (prev) {
+      prev->next = entry->next;
+      prev->state = entry->state;
+    } else if (entry->next) {
+      assert(entry->state == PNI_ENTRY_LINK);
+      pni_entry_t *next = &map->entries[entry->next];
+      *entry = *next;
+      entry = next;
+    }
+    entry->state = PNI_ENTRY_FREE;
+    entry->next = 0;
+    entry->key = NULL;
+    entry->value = NULL;
+    map->size--;
+    pn_class_decref(map->key, dref_key);
+    pn_class_decref(map->value, dref_value);
+  }
+}
+
+pn_handle_t pn_map_head(pn_map_t *map)
+{
+  assert(map);
+  for (size_t i = 0; i < map->capacity; i++)
+  {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      return i + 1;
+    }
+  }
+
+  return 0;
+}
+
+pn_handle_t pn_map_next(pn_map_t *map, pn_handle_t entry)
+{
+  for (size_t i = entry; i < map->capacity; i++) {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      return i + 1;
+    }
+  }
+
+  return 0;
+}
+
+void *pn_map_key(pn_map_t *map, pn_handle_t entry)
+{
+  assert(map);
+  assert(entry);
+  return map->entries[entry - 1].key;
+}
+
+void *pn_map_value(pn_map_t *map, pn_handle_t entry)
+{
+  assert(map);
+  assert(entry);
+  return map->entries[entry - 1].value;
+}
+
+struct pn_hash_t {
+  pn_map_t map;
+};
+
+static uintptr_t pni_identity_hashcode(void *obj)
+{
+  return (uintptr_t ) obj;
+}
+
+static bool pni_identity_equals(void *a, void *b)
+{
+  return a == b;
+}
+
+extern const pn_class_t *PN_UINTPTR;
+
+#define CID_pni_uintptr CID_pn_void
+static const pn_class_t *pni_uintptr_reify(void *object) { return PN_UINTPTR; }
+#define pni_uintptr_new NULL
+#define pni_uintptr_free NULL
+#define pni_uintptr_initialize NULL
+static void pni_uintptr_incref(void *object) {}
+static void pni_uintptr_decref(void *object) {}
+static int pni_uintptr_refcount(void *object) { return -1; }
+#define pni_uintptr_finalize NULL
+#define pni_uintptr_hashcode NULL
+#define pni_uintptr_compare NULL
+#define pni_uintptr_inspect NULL
+
+const pn_class_t PNI_UINTPTR = PN_METACLASS(pni_uintptr);
+const pn_class_t *PN_UINTPTR = &PNI_UINTPTR;
+
+pn_hash_t *pn_hash(const pn_class_t *clazz, size_t capacity, float load_factor)
+{
+  pn_hash_t *hash = (pn_hash_t *) pn_map(PN_UINTPTR, clazz, capacity, load_factor);
+  hash->map.hashcode = pni_identity_hashcode;
+  hash->map.equals = pni_identity_equals;
+  return hash;
+}
+
+size_t pn_hash_size(pn_hash_t *hash)
+{
+  return pn_map_size(&hash->map);
+}
+
+int pn_hash_put(pn_hash_t *hash, uintptr_t key, void *value)
+{
+  return pn_map_put(&hash->map, (void *) key, value);
+}
+
+void *pn_hash_get(pn_hash_t *hash, uintptr_t key)
+{
+  return pn_map_get(&hash->map, (void *) key);
+}
+
+void pn_hash_del(pn_hash_t *hash, uintptr_t key)
+{
+  pn_map_del(&hash->map, (void *) key);
+}
+
+pn_handle_t pn_hash_head(pn_hash_t *hash)
+{
+  return pn_map_head(&hash->map);
+}
+
+pn_handle_t pn_hash_next(pn_hash_t *hash, pn_handle_t entry)
+{
+  return pn_map_next(&hash->map, entry);
+}
+
+uintptr_t pn_hash_key(pn_hash_t *hash, pn_handle_t entry)
+{
+  return (uintptr_t) pn_map_key(&hash->map, entry);
+}
+
+void *pn_hash_value(pn_hash_t *hash, pn_handle_t entry)
+{
+  return pn_map_value(&hash->map, entry);
+}


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


[27/51] [abbrv] qpid-proton git commit: Improve tests and demos, in particular improve the encapsulation around the QMF handling in qpid-config.js to make it potentially reusable

Posted by rh...@apache.org.
Improve tests and demos, in particular improve the encapsulation around the QMF handling in qpid-config.js to make it potentially reusable

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1624737 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/6343817a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/6343817a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/6343817a

Branch: refs/heads/master
Commit: 6343817a98afdf12aa7278948b2a8a45b86e8ffc
Parents: a856698
Author: fadams <fa...@unknown>
Authored: Sat Sep 13 13:46:29 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sat Sep 13 13:46:29 2014 +0000

----------------------------------------------------------------------
 examples/messenger/javascript/client.js      |   9 +-
 examples/messenger/javascript/drain.js       |   9 +-
 examples/messenger/javascript/proxy.js       |   6 +
 examples/messenger/javascript/qpid-config.js | 464 +++++++++++-----------
 examples/messenger/javascript/recv.js        |   9 +-
 examples/messenger/javascript/send.html      |   4 +-
 examples/messenger/javascript/send.js        |   9 +-
 examples/messenger/javascript/server.js      |   9 +-
 examples/messenger/javascript/spout.js       |   9 +-
 proton-c/bindings/javascript/binding.js      | 181 +++++----
 tests/javascript/codec.js                    |  13 +-
 tests/javascript/message.js                  |  13 +-
 tests/javascript/soak.js                     |  40 +-
 13 files changed, 408 insertions(+), 367 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/examples/messenger/javascript/client.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/client.js b/examples/messenger/javascript/client.js
index c9419a2..5fae391 100644
--- a/examples/messenger/javascript/client.js
+++ b/examples/messenger/javascript/client.js
@@ -21,11 +21,14 @@
 
 // Simple client for use with server.js illustrating request/response
 
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("client.js should be run in Node.js");
+    return;
 }
 
+var proton = require("qpid-proton");
+
 var address = "amqp://0.0.0.0";
 var subject = "UK.WEATHER";
 var replyTo = "~/replies";

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/examples/messenger/javascript/drain.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/drain.js b/examples/messenger/javascript/drain.js
index 923e29a..20a7e83 100644
--- a/examples/messenger/javascript/drain.js
+++ b/examples/messenger/javascript/drain.js
@@ -19,11 +19,14 @@
  *
  */
 
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("drain.js should be run in Node.js");
+    return;
 }
 
+var proton = require("qpid-proton");
+
 console.log("drain not implemented yet");
 process.exit(0);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/examples/messenger/javascript/proxy.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/proxy.js b/examples/messenger/javascript/proxy.js
index bd1c208..2a7866b 100755
--- a/examples/messenger/javascript/proxy.js
+++ b/examples/messenger/javascript/proxy.js
@@ -35,6 +35,12 @@
  * @file
  */
 
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("proxy.js should be run in Node.js");
+    return;
+}
+
 var proxy = require('./ws2tcp.js');
 
 var lport = 5673;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/examples/messenger/javascript/qpid-config.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/qpid-config.js b/examples/messenger/javascript/qpid-config.js
index eb0951f..67d84a2 100755
--- a/examples/messenger/javascript/qpid-config.js
+++ b/examples/messenger/javascript/qpid-config.js
@@ -20,7 +20,7 @@
  */
 
 /**
- * Port of qpid-config to JavaScript for node.js, mainly intended as a demo to
+ * Port of qpid-config to JavaScript for Node.js, mainly intended as a demo to
  * illustrate using QMF2 in JavaScript using the proton.Messenger JS binding.
  * It illustrates a few things including how to use Messenger completely
  * asynchronously including using an async request/response pattern with
@@ -36,180 +36,188 @@
  * for complication best illustrated by the need for the correlator object.
  */
 
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("qpid-config.js should be run in Node.js");
+    return;
 }
 
-var addr = 'guest:guest@localhost:5673';
-//var addr = 'localhost:5673';
-var address = 'amqp://' + addr + '/qmf.default.direct';
-console.log(address);
-
-var replyTo = '';
-var subscription;
-var subscribed = false;
-
-var message = new proton.Message();
-var messenger = new proton.Messenger();
-
-/**
- * The correlator object is a mechanism used to correlate requests with their
- * aynchronous responses. It might possible be better to make use of Promises
- * to implement part of this behaviour but a mechanism would still be needed to
- * correlate a request with its response callback in order to wrap things up in
- * a Promise, so much of the behaviour of this object would still be required.
- * In addition it seemed to make sense to make this QMF2 implementation fairly
- * free of dependencies and using Promises would require external libraries.
- * Instead the correlator implements "Promise-like" semantics, you might call it
- * a broken Promise :-)
- * <p>
- * in particular the request method behaves a *bit* like Promise.all() though it
- * is mostly fake and takes an array of functions that call the add() method
- * which is really the method used to associate response objects by correlationID.
- * The then method is used to register a listener that will be called when all
- * the requests that have been registered have received responses.
- * TODO error/timeout handling.
- */
-var correlator = {
-    _resolve: null,
-    _objects: {},
-    add: function(id) {
-        this._objects[id] = {complete: false, list: null};
-    },
-    request: function() {
-        this._resolve = function() {console.log("Warning: No resolver has been set")};
-        return this;
-    },
-    then: function(resolver) {
-        this._resolve = resolver ? resolver : this._resolve;
-    },
-    resolve: function() {
-        var opcode = message.properties['qmf.opcode'];
-        var correlationID = message.getCorrelationID();
-        var resp = this._objects[correlationID];
-        if (opcode === '_query_response') {
-            if (resp.list) {
-                Array.prototype.push.apply(resp.list, message.body); // This is faster than concat.
-            } else {
+var qmf = {}; // Create qmf namespace object.
+qmf.Console = function() { // qmf.Console Constructor.
+    var proton = require("qpid-proton");
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    var brokerAddress = '';
+    var replyTo = '';
+
+    /**
+     * The correlator object is a mechanism used to correlate requests with their
+     * aynchronous responses. It might possible be better to make use of Promises
+     * to implement part of this behaviour but a mechanism would still be needed to
+     * correlate a request with its response callback in order to wrap things up in
+     * a Promise, so much of the behaviour of this object would still be required.
+     * In addition it seemed to make sense to make this QMF2 implementation fairly
+     * free of dependencies and using Promises would require external libraries.
+     * Instead the correlator implements "Promise-like" semantics, you might call it
+     * a broken Promise :-)
+     * <p>
+     * in particular the request method behaves a *bit* like Promise.all() though it
+     * is mostly fake and takes an array of functions that call the add() method
+     * which is really the method used to associate response objects by correlationID.
+     * The then method is used to register a listener that will be called when all
+     * the requests that have been registered have received responses.
+     * TODO error/timeout handling.
+     */
+    var correlator = {
+        _resolve: null,
+        _objects: {},
+        add: function(id) {
+            this._objects[id] = {complete: false, list: null};
+        },
+        request: function() {
+            this._resolve = function() {console.log("Warning: No resolver has been set")};
+            return this;
+        },
+        then: function(resolver) {
+            this._resolve = resolver ? resolver : this._resolve;
+        },
+        resolve: function() {
+            var opcode = message.properties['qmf.opcode'];
+            var correlationID = message.getCorrelationID();
+            var resp = this._objects[correlationID];
+            if (opcode === '_query_response') {
+                if (resp.list) {
+                    Array.prototype.push.apply(resp.list, message.body); // This is faster than concat.
+                } else {
+                    resp.list = message.body;
+                }
+    
+                var partial = message.properties['partial'];
+                if (!partial) {
+                    resp.complete = true;
+                }
+    
+                this._objects[correlationID] = resp;
+                this._checkComplete();
+            } else if (opcode === '_method_response' || opcode === '_exception') {
                 resp.list = message.body;
-            }
-
-            var partial = message.properties['partial'];
-            if (!partial) {
                 resp.complete = true;
+                this._objects[correlationID] = resp;
+                this._checkComplete();
+            } else {
+                console.error("Bad Message response, qmf.opcode = " + opcode);
             }
+        },
+        _checkComplete: function() {
+            var response = {};
+            for (var id in this._objects) {
+                var object = this._objects[id];
+                if (object.complete) {
+                    response[id] = object.list;
+                } else {
+                    return;
+                }
+            }
+    
+            this._objects = {}; // Clear state ready for next call.
+            this._resolve(response.method ? response.method : response);
+        }
+    };  
+
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            // The second parameter forces Binary payloads to be decoded as strings
+            // this is useful because the broker QMF Agent encodes strings as AMQP
+            // binary, which is a right pain from an interoperability perspective.
+            var t = messenger.get(message, true);
+            correlator.resolve();
+            messenger.accept(t);
+        }
 
-            this._objects[correlationID] = resp;
-            this._checkComplete();
-        } else if (opcode === '_method_response' || opcode === '_exception') {
-            resp.list = message.body;
-            resp.complete = true;
-            this._objects[correlationID] = resp;
-            this._checkComplete();
-        } else {
-            console.error("Bad Message response, qmf.opcode = " + opcode);
+        if (messenger.isStopped()) {
+            message.free();
+            messenger.free();
         }
-    },
-    _checkComplete: function() {
-        var response = {};
-        for (var id in this._objects) {
-            var object = this._objects[id];
-            if (object.complete) {
-                response[id] = object.list;
-            } else {
-                return;
+    };
+
+    this.getObjects = function(packageName, className) {
+        message.setAddress(brokerAddress);
+        message.setSubject('broker');
+        message.setReplyTo(replyTo);
+        message.setCorrelationID(className);
+        message.properties = {
+            "routing-key": "broker", // Added for Java Broker
+            "x-amqp-0-10.app-id": "qmf2",
+            "method": "request",
+            "qmf.opcode": "_query_request",
+        };
+        message.body = {
+            "_what": "OBJECT",
+            "_schema_id": {
+                "_package_name": packageName,
+                "_class_name": className
             }
-        }
+        };
 
-        this._objects = {}; // Clear state ready for next call.
-        this._resolve(response.method ? response.method : response);
-    }
-};
+        correlator.add(className);
+        messenger.put(message);
+    };
 
-var pumpData = function() {
-    if (!subscribed) {
-        var subscriptionAddress = subscription.getAddress();
-        if (subscriptionAddress) {
-            subscribed = true;
+    this.invokeMethod = function(object, method, arguments) {
+        var correlationID = 'method';
+        message.setAddress(brokerAddress);
+        message.setSubject('broker');
+        message.setReplyTo(replyTo);
+        message.setCorrelationID(correlationID);
+        message.properties = {
+            "routing-key": "broker", // Added for Java Broker
+            "x-amqp-0-10.app-id": "qmf2",
+            "method": "request",
+            "qmf.opcode": "_method_request",
+        };
+        message.body = {
+            "_object_id": object._object_id,
+            "_method_name" : method,
+            "_arguments"   : arguments
+        };
+
+        correlator.add(correlationID);
+        messenger.put(message);
+    };
+
+    this.addConnection = function(addr, callback) {
+        brokerAddress = addr + '/qmf.default.direct';
+        var replyAddress = addr + '/#';
+
+        messenger.on('subscription', function(subscription) {
+            var subscriptionAddress = subscription.getAddress();
             var splitAddress = subscriptionAddress.split('/');
             replyTo = splitAddress[splitAddress.length - 1];
+            callback();
+        });
 
-            onSubscription();
-        }
-    }
-
-    while (messenger.incoming()) {
-        // The second parameter forces Binary payloads to be decoded as strings
-        // this is useful because the broker QMF Agent encodes strings as AMQP
-        // binary, which is a right pain from an interoperability perspective.
-        var t = messenger.get(message, true);
-        correlator.resolve();
-        messenger.accept(t);
+        messenger.subscribe(replyAddress);
     }
 
-    if (messenger.isStopped()) {
-        message.free();
-        messenger.free();
+    this.destroy = function() {
+        messenger.stop(); 
     }
-};
-
-var getObjects = function(packageName, className) {
-    message.setAddress(address);
-    message.setSubject('broker');
-    message.setReplyTo(replyTo);
-    message.setCorrelationID(className);
-    message.properties = {
-        "routing-key": "broker", // Added for Java Broker
-        "x-amqp-0-10.app-id": "qmf2",
-        "method": "request",
-        "qmf.opcode": "_query_request",
-    };
-    message.body = {
-        "_what": "OBJECT",
-        "_schema_id": {
-            "_package_name": packageName,
-            "_class_name": className
-        }
-    };
 
-    correlator.add(className);
-    messenger.put(message);
-};
+    this.request = function() {return correlator.request();}
 
-var invokeMethod = function(object, method, arguments) {
-    var correlationID = 'method';
-    message.setAddress(address);
-    message.setSubject('broker');
-    message.setReplyTo(replyTo);
-    message.setCorrelationID(correlationID);
-    message.properties = {
-        "routing-key": "broker", // Added for Java Broker
-        "x-amqp-0-10.app-id": "qmf2",
-        "method": "request",
-        "qmf.opcode": "_method_request",
-    };
-    message.body = {
-        "_object_id": object._object_id,
-        "_method_name" : method,
-        "_arguments"   : arguments
-    };
-
-    correlator.add(correlationID);
-    messenger.put(message);
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.setOutgoingWindow(1024);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
 };
 
-messenger.on('error', function(error) {console.log(error);});
-messenger.on('work', pumpData);
-messenger.setOutgoingWindow(1024);
-messenger.start();
-
-subscription = messenger.subscribe('amqp://' + addr + '/#');
-messenger.recv(); // Receive as many messages as messenger can buffer.
-
 
 /************************* qpid-config business logic ************************/
 
+var brokerAgent = new qmf.Console();
+
 var _usage =
 'Usage:  qpid-config [OPTIONS]\n' +
 '        qpid-config [OPTIONS] exchanges [filter-string]\n' +
@@ -382,7 +390,7 @@ var getValue = function(r) {
 
 var config = {
     _recursive      : false,
-    _host           : 'localhost:5673', // Note 5673 not 5672 as we use WebSocket transport.
+    _host           : 'guest:guest@localhost:5673', // Note 5673 not 5672 as we use WebSocket transport.
     _connTimeout    : 10,
     _ignoreDefault  : false,
     _altern_ex      : null,
@@ -539,10 +547,10 @@ var renderObject = function(obj, list) {
  */
 
 var overview = function() {
-    correlator.request(
+    brokerAgent.request(
         // Send the QMF query requests for the specified classes.
-        getObjects('org.apache.qpid.broker', 'queue'),
-        getObjects('org.apache.qpid.broker', 'exchange')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
     ).then(function(objects) {
         var exchanges = objects.exchange;
         var queues = objects.queue;
@@ -571,14 +579,14 @@ var overview = function() {
         }
         console.log("        durable: " + durable);
         console.log("    non-durable: " + (queues.length - durable));
-        messenger.stop();
+        brokerAgent.destroy();
     });
 };
 
 var exchangeList = function(filter) {
-    correlator.request(
+    brokerAgent.request(
         // Send the QMF query requests for the specified classes.
-        getObjects('org.apache.qpid.broker', 'exchange')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
     ).then(function(objects) {
         var exchanges = objects.exchange;
         var exMap = idMap(exchanges);
@@ -630,16 +638,16 @@ var exchangeList = function(filter) {
                 console.log(string);
             }
         }
-        messenger.stop();
+        brokerAgent.destroy();
     });
 };
 
 var exchangeListRecurse = function(filter) {
-    correlator.request(
+    brokerAgent.request(
         // Send the QMF query requests for the specified classes.
-        getObjects('org.apache.qpid.broker', 'queue'),
-        getObjects('org.apache.qpid.broker', 'exchange'),
-        getObjects('org.apache.qpid.broker', 'binding')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'),
+        brokerAgent.getObjects('org.apache.qpid.broker', 'binding')
     ).then(function(objects) {
         var exchanges = objects.exchange;
         var bindings = objects.binding;
@@ -666,15 +674,15 @@ var exchangeListRecurse = function(filter) {
                 }
             }
         }
-        messenger.stop();
+        brokerAgent.destroy();
     });
 };
 
 var queueList = function(filter) {
-    correlator.request(
+    brokerAgent.request(
         // Send the QMF query requests for the specified classes.
-        getObjects('org.apache.qpid.broker', 'queue'),
-        getObjects('org.apache.qpid.broker', 'exchange')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
     ).then(function(objects) {
         var queues = objects.queue;
         var exMap = idMap(objects.exchange);
@@ -763,16 +771,16 @@ var queueList = function(filter) {
                 console.log(string);
             }
         }
-        messenger.stop();
+        brokerAgent.destroy();
     });
 };
 
 var queueListRecurse = function(filter) {
-    correlator.request(
+    brokerAgent.request(
         // Send the QMF query requests for the specified classes.
-        getObjects('org.apache.qpid.broker', 'queue'),
-        getObjects('org.apache.qpid.broker', 'exchange'),
-        getObjects('org.apache.qpid.broker', 'binding')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'),
+        brokerAgent.getObjects('org.apache.qpid.broker', 'binding')
     ).then(function(objects) {
         var queues = objects.queue;
         var bindings = objects.binding;
@@ -806,7 +814,7 @@ var queueListRecurse = function(filter) {
                 }
             }
         }
-        messenger.stop();
+        brokerAgent.destroy();
     });
 };
 
@@ -836,7 +844,6 @@ var queueListRecurse = function(filter) {
  */
 
 var handleMethodResponse = function(response, dontStop) {
-console.log("Method result");
     if (response._arguments) {
         //console.log(response._arguments);
     } if (response._values) {
@@ -845,7 +852,7 @@ console.log("Method result");
     // Mostly we want to stop the Messenger Event loop and exit when a QMF method
     // returns, but sometimes we don't, the dontStop flag prevents this behaviour.
     if (!dontStop) {
-        messenger.stop();
+        brokerAgent.destroy();
     }
 }
 
@@ -885,13 +892,13 @@ var addExchange = function(args) {
         declArgs[REPLICATE] = config._replicate;
     }
 
-    correlator.request(
+    brokerAgent.request(
         // We invoke the CRUD methods on the broker object.
-        getObjects('org.apache.qpid.broker', 'broker')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
     ).then(function(objects) {
         var broker = objects.broker[0];
-        correlator.request(
-            invokeMethod(broker, 'create', {
+        brokerAgent.request(
+            brokerAgent.invokeMethod(broker, 'create', {
                 "type":      "exchange",
                 "name":       ename,
                 "properties": declArgs,
@@ -907,13 +914,13 @@ var delExchange = function(args) {
 
     var ename = args[0];
 
-    correlator.request(
+    brokerAgent.request(
         // We invoke the CRUD methods on the broker object.
-        getObjects('org.apache.qpid.broker', 'broker')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
     ).then(function(objects) {
         var broker = objects.broker[0];
-        correlator.request(
-            invokeMethod(broker, 'delete', {
+        brokerAgent.request(
+            brokerAgent.invokeMethod(broker, 'delete', {
                 "type":   "exchange",
                 "name":    ename})
         ).then(handleMethodResponse);
@@ -1009,13 +1016,13 @@ var addQueue = function(args) {
     // correlator object isn't as good as a real Promise and doesn't support
     // chaining of "then" calls, so where we have complex dependencies we still
     // get somewhat into "callback hell". TODO improve the correlator.
-    correlator.request(
+    brokerAgent.request(
         // We invoke the CRUD methods on the broker object.
-        getObjects('org.apache.qpid.broker', 'broker')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
     ).then(function(objects) {
         var broker = objects.broker[0];
-        correlator.request(
-            invokeMethod(broker, 'create', {
+        brokerAgent.request(
+            brokerAgent.invokeMethod(broker, 'create', {
                 "type":      "queue",
                 "name":       qname,
                 "properties": declArgs,
@@ -1024,18 +1031,18 @@ var addQueue = function(args) {
             if (config._start_replica) {
                 handleMethodResponse(response, true); // The second parameter prevents exiting.
                 // TODO test this stuff!
-                correlator.request(
-                    getObjects('org.apache.qpid.ha', 'habroker') // Not sure if this is correct
+                brokerAgent.request(
+                    brokerAgent.getObjects('org.apache.qpid.ha', 'habroker') // Not sure if this is correct
                 ).then(function(objects) {
                     if (objects.habroker.length > 0) {
                         var habroker = objects.habroker[0];
-                        correlator.request(
-                            invokeMethod(habroker, 'replicate', {
+                        brokerAgent.request(
+                            brokerAgent.invokeMethod(habroker, 'replicate', {
                                 "broker": config._start_replica,
                                 "queue":  qname})
                         ).then(handleMethodResponse);
                     } else {
-                        messenger.stop();
+                        brokerAgent.destroy();
                     }
                 });
             } else {
@@ -1052,13 +1059,13 @@ var delQueue = function(args) {
 
     var qname = args[0];
 
-    correlator.request(
+    brokerAgent.request(
         // We invoke the CRUD methods on the broker object.
-        getObjects('org.apache.qpid.broker', 'broker')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
     ).then(function(objects) {
         var broker = objects.broker[0];
-        correlator.request(
-            invokeMethod(broker, 'delete', {
+        brokerAgent.request(
+            brokerAgent.invokeMethod(broker, 'delete', {
                 "type":   "queue",
                 "name":    qname,
                 "options": {"if_empty":  config._if_empty,
@@ -1092,9 +1099,6 @@ var snarf_header_args = function(args) {
 };
 
 var bind = function(args) {
-console.log("bind");
-console.log(args);
-
     if (args.length < 2) {
         usage();
     }
@@ -1107,10 +1111,10 @@ console.log(args);
         key = args[2];
     }
 
-    correlator.request(
+    brokerAgent.request(
         // We invoke the CRUD methods on the broker object.
-        getObjects('org.apache.qpid.broker', 'broker'),
-        getObjects('org.apache.qpid.broker', 'exchange') // Get exchanges to look up exchange type.
+        brokerAgent.getObjects('org.apache.qpid.broker', 'broker'),
+        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange') // Get exchanges to look up exchange type.
     ).then(function(objects) {
         var exchanges = objects.exchange;
 
@@ -1136,15 +1140,15 @@ console.log(args);
         } else if (etype === 'headers') {
             declArgs = snarf_header_args(Array.prototype.slice.apply(args, [3]));
         }
-console.log(declArgs);
+//console.log(declArgs);
 
         if (typeof declArgs !== 'object') {
             process.exit(1);
         }
 
         var broker = objects.broker[0];
-        correlator.request(
-            invokeMethod(broker, 'create', {
+        brokerAgent.request(
+            brokerAgent.invokeMethod(broker, 'create', {
                 "type":   "binding",
                 "name":    ename + '/' + qname + '/' + key,
                 "properties": declArgs,
@@ -1177,9 +1181,6 @@ console.log(declArgs);
 };
 
 var unbind = function(args) {
-console.log("unbind");
-console.log(args);
-
     if (args.length < 2) {
         usage();
     }
@@ -1192,13 +1193,13 @@ console.log(args);
         key = args[2];
     }
 
-    correlator.request(
+    brokerAgent.request(
         // We invoke the CRUD methods on the broker object.
-        getObjects('org.apache.qpid.broker', 'broker')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
     ).then(function(objects) {
         var broker = objects.broker[0];
-        correlator.request(
-            invokeMethod(broker, 'delete', {
+        brokerAgent.request(
+            brokerAgent.invokeMethod(broker, 'delete', {
                 "type":   "binding",
                 "name":    ename + '/' + qname + '/' + key})
         ).then(handleMethodResponse);
@@ -1216,14 +1217,14 @@ console.log(args);
  */
 
 var createObject = function(type, name, args) {
-    correlator.request(
+    brokerAgent.request(
         // We invoke the CRUD methods on the broker object.
-        getObjects('org.apache.qpid.broker', 'broker')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
     ).then(function(objects) {
         var broker = objects.broker[0];
-        correlator.request(
+        brokerAgent.request(
             // Create an object of the specified type.
-            invokeMethod(broker, 'create', {
+            brokerAgent.invokeMethod(broker, 'create', {
                 "type":       type,
                 "name":       name,
                 "properties": args,
@@ -1233,14 +1234,14 @@ var createObject = function(type, name, args) {
 };
 
 var deleteObject = function(type, name, args) {
-    correlator.request(
+    brokerAgent.request(
         // We invoke the CRUD methods on the broker object.
-        getObjects('org.apache.qpid.broker', 'broker')
+        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
     ).then(function(objects) {
         var broker = objects.broker[0];
-        correlator.request(
+        brokerAgent.request(
             // Create an object of the specified type and name.
-            invokeMethod(broker, 'delete', {
+            brokerAgent.invokeMethod(broker, 'delete', {
                 "type":    type,
                 "name":    name,
                 "options": args})
@@ -1252,8 +1253,8 @@ var deleteObject = function(type, name, args) {
  * This is a "generic" mechanism for listing arbitrary Management Objects.
  */
 var listObjects = function(type) {
-    correlator.request(
-        getObjects('org.apache.qpid.broker', type)
+    brokerAgent.request(
+        brokerAgent.getObjects('org.apache.qpid.broker', type)
     ).then(function(objects) {
         // The correlator passes an object containing responses for all of the
         // supplied requests so we index it by the supplied type to get our response.
@@ -1325,23 +1326,23 @@ var listObjects = function(type) {
             console.log(string);
         }
 
-        messenger.stop();
+        brokerAgent.destroy();
     });
 };
 
 var reloadAcl = function() {
-    correlator.request(
-        getObjects('org.apache.qpid.acl', 'acl')
+    brokerAgent.request(
+        brokerAgent.getObjects('org.apache.qpid.acl', 'acl')
     ).then(function(objects) {
         if (objects.acl.length > 0) {
             var acl = objects.acl[0];
-            correlator.request(
+            brokerAgent.request(
                 // Create an object of the specified type.
-                invokeMethod(acl, 'reloadACLFile', {})
+                brokerAgent.invokeMethod(acl, 'reloadACLFile', {})
             ).then(handleMethodResponse);
         } else {
             console.log("Failed: No ACL Loaded in Broker");
-            messenger.stop();
+            brokerAgent.destroy();
         }
     });
 };
@@ -1502,9 +1503,6 @@ if (params.length > 0) {
 }
 
 //console.log(config._host);
+brokerAgent.addConnection(config._host, command);
 
 
-var onSubscription = function() {
-    command();
-};
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/examples/messenger/javascript/recv.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/recv.js b/examples/messenger/javascript/recv.js
index 3d2b468..f4fe5c0 100644
--- a/examples/messenger/javascript/recv.js
+++ b/examples/messenger/javascript/recv.js
@@ -19,11 +19,14 @@
  *
  */
 
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("recv.js should be run in Node.js");
+    return;
 }
 
+var proton = require("qpid-proton");
+
 var address = "amqp://~0.0.0.0";
 var message = new proton.Message();
 var messenger = new proton.Messenger();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/examples/messenger/javascript/send.html
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html
index eff1fad..382b293 100644
--- a/examples/messenger/javascript/send.html
+++ b/examples/messenger/javascript/send.html
@@ -61,9 +61,9 @@ console.log("body = " + body);
 messenger.on('error', function(error) {
     console.log("Received error " + error);
 
-message.free();
+// Error recovery seems to require a new Messenger instance.
+messenger.stop();
 messenger.free();
-message = new proton.Message();
 messenger = new proton.Messenger();
 messenger.start();
 console.log("Restarted");

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/examples/messenger/javascript/send.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.js b/examples/messenger/javascript/send.js
index 5a93333..9c48fab 100644
--- a/examples/messenger/javascript/send.js
+++ b/examples/messenger/javascript/send.js
@@ -19,11 +19,14 @@
  *
  */
 
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("send.js should be run in Node.js");
+    return;
 }
 
+var proton = require("qpid-proton");
+
 var address = "amqp://0.0.0.0";
 var subject = "UK.WEATHER";
 var msgtext = "Hello World!";

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/examples/messenger/javascript/server.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/server.js b/examples/messenger/javascript/server.js
index cce8aa3..483e49d 100644
--- a/examples/messenger/javascript/server.js
+++ b/examples/messenger/javascript/server.js
@@ -21,11 +21,14 @@
 
 // Simple server for use with client.js illustrating request/response
 
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("server.js should be run in Node.js");
+    return;
 }
 
+var proton = require("qpid-proton");
+
 var address = "amqp://~0.0.0.0";
 var message = new proton.Message();
 var reply   = new proton.Message();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/examples/messenger/javascript/spout.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/spout.js b/examples/messenger/javascript/spout.js
index 1219627..ad5b376 100644
--- a/examples/messenger/javascript/spout.js
+++ b/examples/messenger/javascript/spout.js
@@ -19,11 +19,14 @@
  *
  */
 
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("spout.js should be run in Node.js");
+    return;
 }
 
+var proton = require("qpid-proton");
+
 console.log("spout not implemented yet");
 process.exit(0);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index 4caafa6..fa53e4c 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -214,9 +214,17 @@ Module['Messenger'] = function(name) { // Messenger Constructor.
      */
     _pn_messenger_set_blocking(this._messenger, false);
 
+    // Subscriptions that haven't yet completed, used for managing subscribe events.
+    this._pendingSubscriptions = [];
+
     // Used in the Event registration mechanism (in the 'on' and 'emit' methods).
     this._callbacks = {};
 
+    // This call ensures that the emscripten network callback functions are initialised.
+    Module.EventDispatch.registerMessenger(this);
+
+
+    // TODO improve error handling mechanism.
     /*
      * The emscripten websocket error event could get triggered by any Messenger
      * and it's hard to determine which one without knowing which file descriptors
@@ -233,10 +241,13 @@ Module['Messenger'] = function(name) { // Messenger Constructor.
      */
     var that = this;
     Module['websocket']['on']('error', function(error) {
+
+console.log("Module['websocket']['on'] caller is " + arguments.callee.caller.toString());
+
 console.log("that._checkErrors = " + that._checkErrors);
 console.log("error = " + error);
         if (that._checkErrors) {
-            that.emit('error', new Module['MessengerError'](error[2]));
+            that._emit('error', new Module['MessengerError'](error[2]));
         }
     });
 };
@@ -269,7 +280,7 @@ _Messenger_._check = function(code) {
         var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
 
         if (this._callbacks['error']) {
-            this.emit('error', new Module['MessengerError'](message));
+            this._emit('error', new Module['MessengerError'](message));
         } else {
             throw new Module['MessengerError'](message);
         }
@@ -279,18 +290,48 @@ _Messenger_._check = function(code) {
 };
 
 /**
- * Invokes a callback registered for a specified event.
- * @method emit
+ * Invokes the callbacks registered for a specified event.
+ * @method _emit
  * @memberof! proton.Messenger#
  * @param event the event we want to emit.
  * @param param the parameter we'd like to pass to the event callback.
  */
-_Messenger_.emit = function(event, param) {
-    if ('function' === typeof this._callbacks[event]) {
-        this._callbacks[event].call(this, param);
+_Messenger_._emit = function(event, param) {
+    var callbacks = this._callbacks[event];
+    if (callbacks) {
+        for (var i = 0; i < callbacks.length; i++) {
+            var callback = callbacks[i];
+            if ('function' === typeof callback) {
+                callback.call(this, param);
+            }
+        }
+    }
+};
+
+/**
+ * Checks any pending subscriptions and when a source address becomes available
+ * emit a subscription event passing the Subscription that triggered the event.
+ * Note that this doesn't seem to work for listen/bind style subscriptions,
+ * that is to say subscriptions of the form amqp://~0.0.0.0 don't know why?
+ */
+_Messenger_._checkSubscriptions = function() {
+    // Check for completed subscriptions, and emit subscribe event.
+    var subscriptions = this._pendingSubscriptions;
+    if (subscriptions.length) {
+        var pending = []; // Array of any subscriptions that remain pending.
+        for (var j = 0; j < subscriptions.length; j++) {
+            subscription = subscriptions[j];
+            if (subscription['getAddress']()) {
+                this._emit('subscription', subscription);
+            } else {
+                pending.push(subscription);
+            }
+        }
+        this._pendingSubscriptions = pending;
     }
 };
 
+
 // *************************** Public methods *****************************
 
 /**
@@ -327,11 +368,11 @@ _Messenger_.emit = function(event, param) {
  */
 _Messenger_['on'] = function(event, callback) {
     if ('function' === typeof callback) {
-        if (event === 'work') {
-            Module.EventDispatch.addListener(this, callback);
-        } else {
-	        this._callbacks[event] = callback;
+        if (!this._callbacks[event]) {
+            this._callbacks[event] = [];
         }
+
+        this._callbacks[event].push(callback);
     }
 };
 
@@ -340,15 +381,25 @@ _Messenger_['on'] = function(event, callback) {
  * @method removeListener
  * @memberof! proton.Messenger#
  * @param event the event we want to detach from.
- * @param callback the callback function to be remove for the specified event.
+ * @param callback the callback function to be removed for the specified event.
+ *        if no callback is specified all callbacks are removed for the event.
  */
 _Messenger_['removeListener'] = function(event, callback) {
-    if ('function' === typeof callback) {
-        if (event === 'work') {
-            Module.EventDispatch.removeListener(this, callback);
-        } else {
-	        this._callbacks[event] = null;//callback;
+    if (callback) {
+        var callbacks = this._callbacks[event];
+        if ('function' === typeof callback && callbacks) {
+            // Search for the specified callback.
+            for (var i = 0; i < callbacks.length; i++) {
+                if (callback === callbacks[i]) {
+                    // If we find the specified callback delete it and return.
+                    callbacks.splice(i, 1);
+                    return;
+                }
+            }
         }
+    } else {
+        // If we call remove with no callback we remove all callbacks.
+        delete this._callbacks[event];
     }
 };
 
@@ -392,6 +443,8 @@ _Messenger_['isBlocking'] = function() {
  * @memberof! proton.Messenger#
  */
 _Messenger_['free'] = function() {
+    // This call ensures that the emscripten network callback functions are removed.
+    Module.EventDispatch.unregisterMessenger(this);
     _pn_messenger_free(this._messenger);
 };
 
@@ -477,14 +530,6 @@ _Messenger_['setIncomingWindow'] = function(window) {
  */
 _Messenger_['start'] = function() {
     this._check(_pn_messenger_start(this._messenger));
-
-    // This call ensures that the emscripten network callback functions are set
-    // up even if a client hasn't explicity added a work function via a call to
-    // messenger.on('work', <work function>);
-    // Doing this means that pn_messenger_work() will still get called when any
-    // WebSocket events occur, which keeps things more reliable when things like
-    // reconnections occur.
-    Module.EventDispatch.addListener(this);
 };
 
 /**
@@ -534,7 +579,7 @@ _Messenger_['subscribe'] = function(source) {
         this._check(Module['Error']['ARG_ERR']);
     }
     var sp = Runtime.stackSave();
-    this._checkErrors = true;
+    this._checkErrors = true; // TODO improve error handling mechanism.
     var subscription = _pn_messenger_subscribe(this._messenger,
                                                allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
     Runtime.stackRestore(sp);
@@ -542,7 +587,10 @@ _Messenger_['subscribe'] = function(source) {
     if (!subscription) {
         this._check(Module['Error']['ERR']);
     }
-    return new Subscription(subscription);
+
+    subscription = new Subscription(subscription)
+    this._pendingSubscriptions.push(subscription);
+    return subscription;
 };
 
 /**
@@ -570,7 +618,7 @@ _Messenger_['subscribe'] = function(source) {
 _Messenger_['put'] = function(message, flush) {
     flush = flush === false ? false : true;
     message._preEncode();
-    this._checkErrors = true;
+    this._checkErrors = true; // TODO improve error handling mechanism.
     this._check(_pn_messenger_put(this._messenger, message._message));
 
     // If flush is set invoke pn_messenger_work.
@@ -660,7 +708,7 @@ _Messenger_['work'] = function() {
 console.log("work = false");
         return false;
     } else {
-        this._checkErrors = false;
+        this._checkErrors = false; // TODO improve error handling mechanism.
         this._check(err);
 console.log("work = true");
         return true;
@@ -931,7 +979,7 @@ _Messenger_['rewrite'] = function(pattern, address) {
  * @memberof proton
  */
 Module.EventDispatch = new function() { // Note the use of new to create a Singleton.
-    var _firstCall = true; // Flag used to check the first time addListener is called.
+    var _firstCall = true; // Flag used to check the first time registerMessenger is called.
     var _messengers = {};
 
     /**
@@ -950,15 +998,15 @@ Module.EventDispatch = new function() { // Note the use of new to create a Singl
     var _pump = function(fd, closing) {
         for (var i in _messengers) {
             if (_messengers.hasOwnProperty(i)) {
-                var current = _messengers[i];
+                var messenger = _messengers[i];
 
                 if (closing) {
-                    current.invokeCallbacks();
+                    messenger._emit('work');
                 } else {
-                    var messenger = current.messenger;
                     while (_pn_messenger_work(messenger._messenger, 0) >= 0) {
-                        messenger._checkErrors = false;
-                        current.invokeCallbacks();
+                        messenger._checkSubscriptions();
+                        messenger._checkErrors = false; // TODO improve error handling mechanism.
+                        messenger._emit('work');
                     }
                 }
             }
@@ -974,64 +1022,33 @@ Module.EventDispatch = new function() { // Note the use of new to create a Singl
     };
 
     /**
-     * Initialises the emscripten network callback functions. This needs to be
-     * done the first time we call addListener rather that when we create the
-     * Singleton because emscripten's socket filesystem has to be mounted before
-     * we can register listeners for any of these events.
-     */
-    var _init = function() {
-        Module['websocket']['on']('open', _pump);
-        Module['websocket']['on']('connection', _pump);
-        Module['websocket']['on']('message', _pump);
-        Module['websocket']['on']('close', _close);
-    };
-
-    /**
-     * Add a listener callback for the specified Messenger. Multiple listeners
-     * are permitted for each Messenger and listeners can be registered for
-     * multiple Messenger instances. The first time this method is called we
-     * initialise the emscripten network callback functions.
+     * Register the specified Messenger as being interested in network events.
      */
-    this.addListener = function(messenger, callback) {
+    this.registerMessenger = function(messenger) {
         if (_firstCall) {
-            _init();
+            /**
+             * Initialises the emscripten network callback functions. This needs
+             * to be done the first time we call registerMessenger rather than
+             * when we create the Singleton because emscripten's socket filesystem
+             * has to be mounted before can listen for any of these events.
+             */
+            Module['websocket']['on']('open', _pump);
+            Module['websocket']['on']('connection', _pump);
+            Module['websocket']['on']('message', _pump);
+            Module['websocket']['on']('close', _close);
             _firstCall = false;
         }
 
         var name = messenger.getName();
-        if (!_messengers[name]) {
-            _messengers[name] = {
-                messenger: messenger,
-                callbacks: [],
-                invokeCallbacks: function() {
-                    for (var j = 0; j < this.callbacks.length; j++) {
-                        this.callbacks[j]();
-                    }
-                }
-            };
-        }
-
-        if (callback) {
-            _messengers[name].callbacks.push(callback);
-        }
+        _messengers[name] = messenger; 
     };
 
     /**
-     * Remove the specified listener callback from the specified Messenger.
+     * Unregister the specified Messenger from interest in network events.
      */
-    this.removeListener = function(messenger, callback) {
+    this.unregisterMessenger = function(messenger) {
         var name = messenger.getName();
-        if (_messengers[name]) {
-            // If we find the registered Messenger search for the specified callback.
-            var callbacks = _messengers[name].callbacks;
-            for (var j = 0; j < callbacks.length; j++) {
-                if (callback === callbacks[j]) {
-                    // If we find the specified callback delete it and return.
-                    callbacks.splice(j, 1);
-                    return;
-                }
-            }
-        }
+        delete _messengers[name];
     };
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/tests/javascript/codec.js
----------------------------------------------------------------------
diff --git a/tests/javascript/codec.js b/tests/javascript/codec.js
index 36156ae..9decbe7 100644
--- a/tests/javascript/codec.js
+++ b/tests/javascript/codec.js
@@ -23,13 +23,16 @@
  * proton.Data wrapper class.
  */
 
-// Check if the environment is Node.js and if so import the required libraries.
-if (typeof exports !== "undefined" && exports !== null) {
-    unittest = require("./unittest.js");
-    assert = require("assert");
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("codec.js should be run in Node.js");
+    return;
 }
 
+var unittest = require("./unittest.js");
+var assert = require("assert");
+var proton = require("qpid-proton");
+
 // Extend TestCase by creating a prototype instance and adding test methods as properties.
 var DataTest = new unittest.TestCase();
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/tests/javascript/message.js
----------------------------------------------------------------------
diff --git a/tests/javascript/message.js b/tests/javascript/message.js
index 8f03ec8..ed2d1eb 100644
--- a/tests/javascript/message.js
+++ b/tests/javascript/message.js
@@ -23,13 +23,16 @@
  * proton.Message wrapper class.
  */
 
-// Check if the environment is Node.js and if so import the required libraries.
-if (typeof exports !== "undefined" && exports !== null) {
-    unittest = require("./unittest.js");
-    assert = require("assert");
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("message.js should be run in Node.js");
+    return;
 }
 
+var unittest = require("./unittest.js");
+var assert = require("assert");
+var proton = require("qpid-proton");
+
 /**
  * JavaScript Implementation of Python's range() function taken from:
  * http://stackoverflow.com/questions/8273047/javascript-function-similar-to-python-range

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6343817a/tests/javascript/soak.js
----------------------------------------------------------------------
diff --git a/tests/javascript/soak.js b/tests/javascript/soak.js
index c561989..c3882ab 100755
--- a/tests/javascript/soak.js
+++ b/tests/javascript/soak.js
@@ -19,19 +19,20 @@
  *
  */
 
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("qpid-proton");
+// Check if the environment is Node.js and if not log an error and exit.
+if (!exports) {
+    console.error("soak.js should be run in Node.js");
+    return;
 }
 
+var proton = require("qpid-proton");
+
 var addr = 'guest:guest@localhost:5673';
 //var addr = 'localhost:5673';
 var address = 'amqp://' + addr;
 console.log(address);
 
 var subscriptionQueue = '';
-var subscription;
-var subscribed = false;
 var count = 0;
 var start = 0; // Start Time.
 
@@ -39,16 +40,6 @@ var message = new proton.Message();
 var messenger = new proton.Messenger();
 
 var pumpData = function() {
-    if (!subscribed) {
-        var subscriptionAddress = subscription.getAddress();
-        if (subscriptionAddress) {
-            subscribed = true;
-            var splitAddress = subscriptionAddress.split('/');
-            subscriptionQueue = splitAddress[splitAddress.length - 1];
-            onSubscription();
-        }
-    }
-
     while (messenger.incoming()) {
         // The second parameter forces Binary payloads to be decoded as strings
         // this is useful because the broker QMF Agent encodes strings as AMQP
@@ -84,16 +75,21 @@ var sendMessage = function() {
 
 messenger.on('error', function(error) {console.log(error);});
 messenger.on('work', pumpData);
+messenger.on('subscription', function(subscription) {
+    var subscriptionAddress = subscription.getAddress();
+    var splitAddress = subscriptionAddress.split('/');
+    subscriptionQueue = splitAddress[splitAddress.length - 1];
+
+    console.log("Subscription Queue: " + subscriptionQueue);
+    start = +new Date();
+    sendMessage();
+});
+
 //messenger.setOutgoingWindow(1024);
 messenger.setIncomingWindow(1024); // The Java Broker seems to need this.
+messenger.recv(); // Receive as many messages as messenger can buffer.
 messenger.start();
 
-subscription = messenger.subscribe('amqp://' + addr + '/#');
-messenger.recv(); // Receive as many messages as messenger can buffer.
+messenger.subscribe('amqp://' + addr + '/#');
 
-var onSubscription = function() {
-    console.log("Subscription Queue: " + subscriptionQueue);
-    start = +new Date();
-    sendMessage();
-};
 


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


[49/51] [abbrv] qpid-proton git commit: merge from trunk to javascript branch

Posted by rh...@apache.org.
merge from trunk to javascript branch


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/726a49bc
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/726a49bc
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/726a49bc

Branch: refs/heads/master
Commit: 726a49bccd2858ff641e8fa30d8ff327b7578220
Parents: e8faa57 1781b4e
Author: Rafael Schloming <rh...@alum.mit.edu>
Authored: Thu Nov 27 13:22:12 2014 -0500
Committer: Rafael Schloming <rh...@alum.mit.edu>
Committed: Fri Nov 28 07:02:53 2014 -0500

----------------------------------------------------------------------
 CMakeLists.txt                                  |   14 +-
 .../jms/AMQPNativeOutboundTransformer.java      |    4 +-
 .../proton/jms/AutoOutboundTransformer.java     |    6 +
 .../qpid/proton/jms/InboundTransformer.java     |   84 +-
 .../jms/JMSMappingOutboundTransformer.java      |   51 +-
 .../org/apache/qpid/proton/jms/JMSVendor.java   |   16 +-
 .../qpid/proton/jms/OutboundTransformer.java    |   14 +-
 .../jms/JMSMappingInboundTransformerTest.java   |  287 ++
 .../jms/JMSMappingOutboundTransformerTest.java  |  351 ++
 examples/README.txt                             |    3 +
 examples/engine/java/LICENSE                    |  201 +
 examples/engine/java/drain                      |    2 +
 examples/engine/java/pom.xml                    |   40 +
 examples/engine/java/server                     |    2 +
 examples/engine/java/spout                      |    2 +
 .../org/apache/qpid/proton/examples/Drain.java  |  128 +
 .../org/apache/qpid/proton/examples/Driver.java |  262 ++
 .../qpid/proton/examples/FlowController.java    |   80 +
 .../apache/qpid/proton/examples/Handshaker.java |   88 +
 .../apache/qpid/proton/examples/Message.java    |   83 +
 .../org/apache/qpid/proton/examples/Pool.java   |  153 +
 .../org/apache/qpid/proton/examples/Router.java |  191 +
 .../org/apache/qpid/proton/examples/Server.java |  179 +
 .../org/apache/qpid/proton/examples/Spout.java  |  116 +
 proton-c/CMakeLists.txt                         |   34 +-
 proton-c/bindings/CMakeLists.txt                |    3 +-
 proton-c/bindings/javascript/CMakeLists.txt     |    2 +
 .../bindings/perl/lib/qpid/proton/Message.pm    |    2 +-
 proton-c/bindings/perl/lib/qpid/proton/utils.pm |    2 +-
 proton-c/bindings/perl/lib/qpid_proton.pm       |    1 +
 proton-c/bindings/python/CMakeLists.txt         |   83 +-
 proton-c/bindings/python/proton.py              | 3771 -----------------
 proton-c/bindings/python/proton/__init__.py     | 3891 ++++++++++++++++++
 proton-c/bindings/python/setup.py.in            |  107 -
 proton-c/bindings/ruby/lib/qpid_proton.rb       |    5 +-
 proton-c/bindings/ruby/lib/qpid_proton/array.rb |   10 +-
 proton-c/bindings/ruby/lib/qpid_proton/data.rb  |   14 +-
 .../bindings/ruby/lib/qpid_proton/described.rb  |    4 +-
 .../ruby/lib/qpid_proton/exception_handling.rb  |   53 +-
 .../bindings/ruby/lib/qpid_proton/exceptions.rb |    8 +-
 .../bindings/ruby/lib/qpid_proton/filters.rb    |    8 +-
 proton-c/bindings/ruby/lib/qpid_proton/hash.rb  |    6 +-
 .../bindings/ruby/lib/qpid_proton/mapping.rb    |   36 +-
 .../bindings/ruby/lib/qpid_proton/message.rb    |   51 +-
 .../ruby/lib/qpid_proton/message_format.rb      |    8 +-
 .../bindings/ruby/lib/qpid_proton/messenger.rb  |  106 +-
 .../bindings/ruby/lib/qpid_proton/selectable.rb |    8 +-
 .../bindings/ruby/lib/qpid_proton/strings.rb    |   69 +
 .../ruby/lib/qpid_proton/subscription.rb        |    8 +-
 .../bindings/ruby/lib/qpid_proton/tracker.rb    |    8 +-
 .../ruby/lib/qpid_proton/tracker_status.rb      |    8 +-
 .../bindings/ruby/lib/qpid_proton/version.rb    |   11 +-
 .../ruby/spec/qpid/proton/messenger_spec.rb     |   16 +
 proton-c/include/proton/cid.h                   |    1 +
 proton-c/include/proton/connection.h            |   10 +
 proton-c/include/proton/cproton.i               |    3 +-
 proton-c/include/proton/delivery.h              |   10 +
 proton-c/include/proton/driver.h                |   13 +-
 proton-c/include/proton/event.h                 |   39 +-
 proton-c/include/proton/link.h                  |   11 +
 proton-c/include/proton/object.h                |    9 +
 proton-c/include/proton/sasl.h                  |   20 +-
 proton-c/include/proton/session.h               |   10 +
 proton-c/include/proton/ssl.h                   |    6 +
 proton-c/include/proton/transport.h             |   47 +-
 proton-c/src/engine/engine-internal.h           |   54 +-
 proton-c/src/engine/engine.c                    |  180 +-
 proton-c/src/events/event.c                     |   28 +-
 proton-c/src/messenger/messenger.c              |   21 +-
 proton-c/src/object/record.c                    |  142 +
 proton-c/src/platform.h                         |   10 +
 proton-c/src/posix/driver.c                     |   16 +-
 proton-c/src/posix/io.c                         |   14 +-
 proton-c/src/protocol.py                        |    2 +
 proton-c/src/proton.c                           |   10 +-
 proton-c/src/sasl/sasl-internal.h               |    6 +-
 proton-c/src/sasl/sasl.c                        |  289 +-
 proton-c/src/ssl/openssl.c                      |  492 +--
 proton-c/src/ssl/ssl-internal.h                 |    6 +-
 proton-c/src/ssl/ssl_stub.c                     |   22 +-
 proton-c/src/tests/CMakeLists.txt               |   13 +-
 proton-c/src/tests/engine.c                     |    3 +
 proton-c/src/tests/refcount.c                   |  176 +
 proton-c/src/transport/autodetect.c             |  135 +
 proton-c/src/transport/autodetect.h             |   40 +
 proton-c/src/transport/transport.c              |  641 ++-
 proton-c/src/util.c                             |   15 +-
 proton-c/src/util.h                             |    2 +
 proton-c/src/windows/driver.c                   |   16 +-
 proton-c/src/windows/io.c                       |   17 +-
 proton-c/src/windows/schannel.c                 |  384 +-
 proton-c/src/windows/selector.c                 |    8 +-
 .../org/apache/qpid/proton/amqp/Binary.java     |  378 +-
 .../org/apache/qpid/proton/amqp/Symbol.java     |  188 +-
 .../apache/qpid/proton/amqp/UnsignedByte.java   |  268 +-
 .../qpid/proton/amqp/UnsignedInteger.java       |  298 +-
 .../apache/qpid/proton/amqp/UnsignedLong.java   |  320 +-
 .../apache/qpid/proton/amqp/UnsignedShort.java  |  268 +-
 .../qpid/proton/amqp/messaging/Accepted.java    |    3 +
 .../qpid/proton/amqp/messaging/Modified.java    |    3 +
 .../qpid/proton/amqp/messaging/Rejected.java    |    2 +
 .../qpid/proton/amqp/messaging/Released.java    |    3 +
 .../qpid/proton/amqp/transaction/Declared.java  |    3 +
 .../qpid/proton/codec/impl/ArrayElement.java    |   13 +
 .../apache/qpid/proton/codec/impl/DataImpl.java |   10 +
 .../apache/qpid/proton/engine/BaseHandler.java  |   67 +
 .../org/apache/qpid/proton/engine/Event.java    |   18 +-
 .../org/apache/qpid/proton/engine/Handler.java  |   67 +
 .../qpid/proton/engine/impl/ConnectionImpl.java |    4 +-
 .../qpid/proton/engine/impl/EventImpl.java      |   97 +
 .../qpid/proton/engine/impl/LinkImpl.java       |    6 +-
 .../qpid/proton/engine/impl/SaslImpl.java       |    7 +-
 .../qpid/proton/engine/impl/SessionImpl.java    |    4 +-
 .../qpid/proton/engine/impl/TransportImpl.java  |    5 +-
 .../impl/ssl/SimpleSslTransportWrapper.java     |    6 +
 .../engine/impl/ssl/SslEngineFacadeFactory.java |   15 +
 proton-j/src/main/resources/cengine.py          |   44 +-
 proton-j/src/main/resources/csasl.py            |   14 +-
 proton-j/src/main/resources/cssl.py             |    3 +
 .../qpid/proton/codec/impl/DataImplTest.java    |   84 +
 tests/python/proton_tests/common.py             |   13 +-
 tests/python/proton_tests/engine.py             |   68 +-
 tests/python/proton_tests/sasl.py               |   14 +-
 tests/python/proton_tests/url.py                |    7 -
 tests/ruby/proton_tests/smoke.rb                |    4 +-
 tools/cmake/Modules/FindPerlLibs.cmake          |   54 -
 tools/cmake/Modules/ProtonFindPerl.cmake        |   81 +
 tools/cmake/Modules/WindowsC99CheckDef.cmake    |    2 +-
 version.txt                                     |    2 +-
 129 files changed, 9987 insertions(+), 6067 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/726a49bc/proton-c/CMakeLists.txt
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/726a49bc/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --cc proton-c/bindings/javascript/CMakeLists.txt
index ee1241f,0000000..38d039b
mode 100644,000000..100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@@ -1,270 -1,0 +1,272 @@@
 +#
 +# Licensed to the Apache Software Foundation (ASF) under one
 +# or more contributor license agreements.  See the NOTICE file
 +# distributed with this work for additional information
 +# regarding copyright ownership.  The ASF licenses this file
 +# to you under the Apache License, Version 2.0 (the
 +# "License"); you may not use this file except in compliance
 +# with the License.  You may obtain a copy of the License at
 +#
 +#   http://www.apache.org/licenses/LICENSE-2.0
 +#
 +# Unless required by applicable law or agreed to in writing,
 +# software distributed under the License is distributed on an
 +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +# KIND, either express or implied.  See the License for the
 +# specific language governing permissions and limitations
 +# under the License.
 +#
 + 
 +# This file allows cross-compiling of proton to JavaScript using emscripten
 +# (https://github.com/kripken/emscripten). As it is really a cross-compilation
 +# (as opposed to a binding like with swig) the approach is rather different and
 +# somewhat replicates the main build in the proton-c/CMakeLists.txt using quite
 +# a bit of "copy and paste reuse".
 +# TODO refactor this file (and proton-c/CMakeLists.txt) to keep the main
 +# compilation and cross-compilation consistent.
 +
 +message(STATUS "Found emscripten, using that to build JavaScript binding")
 +
 +# Find and install the node.js packages that we might need. We can assume that
 +# node.js itself is installed because Emscripten has a dependency on it.
 +find_package(NodePackages)
 +
 +# Describe the target OS we are building to - Emscripten mimics the Linux platform.
 +set(CMAKE_SYSTEM_NAME Linux)
 +set(CMAKE_SYSTEM_VERSION 1)
 +set(CMAKE_CROSSCOMPILING TRUE)
 +
 +# Specify the compiler to use for cross-compilation.
 +set(CMAKE_C_COMPILER "${EMCC}")
 +
 +# Don't do compiler autodetection, since we are cross-compiling.
 +include(CMakeForceCompiler)
 +CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang)
 +
 +# The Proton default build type is RelWithDebInfo, but for JavaScript the C debug
 +# mechanism is irrelevant. If Debug is explicitly set we turn off optimisations
 +# and don't run the closure compiler so any error/profiling messages are readable.
 +if (CMAKE_BUILD_TYPE STREQUAL "Debug")
 +    message(STATUS "JavaScript build type is \"Debug\"")
 +else()
 +    set (CMAKE_BUILD_TYPE Release)
 +    message(STATUS "JavaScript build type is \"Release\"")
 +    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
 +    set(EMSCRIPTEN_LINK_OPTIMISATIONS "-O2 --closure 1")
 +endif()
 +
 +# From this point we should be using emscripten compilation tools.
 +message(STATUS "emscripten compilation environment:")
 +message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
 +
 +
 +# Set this to the proton-c directory, we're cross-compiling code from there.
 +set(PN_PATH ${CMAKE_SOURCE_DIR}/proton-c)
 +
 +
 +# TODO the OpenSSL stuff won't work for emscripten by default. It might well be
 +# possible to compile it from source using emscripten (that's the standard practice
 +# for libraries with emscripten) see https://github.com/kripken/emscripten/wiki/FAQ
 +# "Q. How do I link against system libraries like SDL, boost, etc.?"
 +# Though it might be more natural to simply use a TLS protected wss:// WebSocket URL.
 +#  set(pn_driver_ssl_impl src/ssl/openssl.c)
 +#  set(SSL_LIB ${OPENSSL_LIBRARIES})
 +set(pn_driver_ssl_impl ${PN_PATH}/src/ssl/ssl_stub.c)
 +
 +# emscripten is Linux like so use the posix driver.
 +set(pn_io_impl ${PN_PATH}/src/posix/io.c)
 +set(pn_selector_impl ${PN_PATH}/src/posix/selector.c)
 +set(pn_driver_impl ${PN_PATH}/src/posix/driver.c)
 +
 +
 +# Generate encodings.h and protocol.h
 +# It may be possible to use the ones generated for the main proton-c build but
 +# qpid-proton-core has a dependency on the generated files, so I'm not sure if
 +# it'll work without a command that can be run as a dependency. Probably best
 +# do it this way when cross-compiling - though more copy'n'paste
 +add_custom_command(
 +  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
 +  COMMAND python ${PN_PATH}/env.py PYTHONPATH=${PN_PATH} python ${PN_PATH}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
 +  DEPENDS ${PN_PATH}/src/codec/encodings.h.py
 +  )
 +
 +add_custom_command(
 +  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
 +  COMMAND python ${PN_PATH}/env.py PYTHONPATH=${PN_PATH} python ${PN_PATH}/src/protocol.h.py > ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
 +  DEPENDS ${PN_PATH}/src/protocol.h.py
 +  )
 +
 +set(COMPILE_WARNING_FLAGS "-Werror -Wall -pedantic-errors -Wno-comment -Wno-warn-absolute-paths")
 +
 +# Explicitly set PLATFORM_DEFINITIONS to Linux ones for emscripten as we don't
 +# want to inadvertently use Windows versions if we happen to be cross-compiling
 +# from a Windows platform
 +set(PLATFORM_DEFINITIONS "USE_CLOCK_GETTIME;USE_UUID_GENERATE;USE_STRERROR_R;USE_ATOLL")
 +
 +# The following is largely a copy from the the main proton-c/CMakeLists.txt.
 +# The main difference is prefixing paths with ${PN_PATH}/ as we can't use a
 +# relative path from this CMakeLists.txt.
 +
 +set(qpid-proton-platform
 +  ${pn_io_impl}
 +  ${pn_selector_impl}
 +  ${pn_driver_impl}
 +  ${PN_PATH}/src/platform.c
 +  ${pn_driver_ssl_impl}
 +  )
 +
 +set(qpid-proton-core
 +  ${PN_PATH}/src/object/object.c
 +  ${PN_PATH}/src/object/list.c
 +  ${PN_PATH}/src/object/map.c
 +  ${PN_PATH}/src/object/string.c
 +  ${PN_PATH}/src/object/iterator.c
++  ${PN_PATH}/src/object/record.c
 +
 +  ${PN_PATH}/src/util.c
 +  ${PN_PATH}/src/url.c
 +  ${PN_PATH}/src/error.c
 +  ${PN_PATH}/src/buffer.c
 +  ${PN_PATH}/src/parser.c
 +  ${PN_PATH}/src/scanner.c
 +  ${PN_PATH}/src/types.c
 +
 +  ${PN_PATH}/src/framing/framing.c
 +
 +  ${PN_PATH}/src/codec/codec.c
 +  ${PN_PATH}/src/codec/decoder.c
 +  ${PN_PATH}/src/codec/encoder.c
 +
 +  ${PN_PATH}/src/dispatcher/dispatcher.c
 +  ${PN_PATH}/src/engine/engine.c
 +  ${PN_PATH}/src/events/event.c
++  ${PN_PATH}/src/transport/autodetect.c
 +  ${PN_PATH}/src/transport/transport.c
 +  ${PN_PATH}/src/message/message.c
 +  ${PN_PATH}/src/sasl/sasl.c
 +
 +  ${PN_PATH}/src/messenger/messenger.c
 +  ${PN_PATH}/src/messenger/subscription.c
 +  ${PN_PATH}/src/messenger/store.c
 +  ${PN_PATH}/src/messenger/transform.c
 +  ${PN_PATH}/src/selectable.c
 +
 +  ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
 +  ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
 +  )
 +
 +set_source_files_properties(
 +  ${qpid-proton-core}
 +  PROPERTIES
 +  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS}"
 +  )
 +
 +set_source_files_properties(
 +  ${qpid-proton-platform}
 +  PROPERTIES
 +  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
 +  COMPILE_DEFINITIONS "${PLATFORM_DEFINITIONS}"
 +  )
 +
 +# Compile Proton into LLVM bitcode which will be used later in the linking stage
 +# of add_executable for compilation into Javascript.
 +add_library(
 +  qpid-proton-bitcode SHARED
 +
 +  ${qpid-proton-core}
 +  ${qpid-proton-platform}
 +  )
 +
 +set_target_properties(
 +  qpid-proton-bitcode
 +  PROPERTIES
 +  VERSION   "${PN_LIB_SOMAJOR}.${PN_LIB_SOMINOR}"
 +  SOVERSION "${PN_LIB_SOMAJOR}"
 +  LINK_FLAGS "${CATCH_UNDEFINED}"
 +  )
 +
 +
 +# Compile the send-async.c and recv-async.c examples into JavaScript
 +add_executable(send-async.js ${PN_PATH}/../examples/messenger/c/send-async.c)
 +target_link_libraries(send-async.js qpid-proton-bitcode)
 +
 +add_executable(recv-async.js ${PN_PATH}/../examples/messenger/c/recv-async.c)
 +target_link_libraries(recv-async.js qpid-proton-bitcode)
 +
 +set_target_properties(
 +  send-async.js recv-async.js
 +  PROPERTIES
 +  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
 +  RUNTIME_OUTPUT_DIRECTORY examples
 +  DEPENDS ws
 +
 +  LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -${EMSCRIPTEN_LINK_OPTIMISATIONS}"
 +  )
 +
 +# Build the main JavaScript library called proton.js
 +add_executable(proton.js binding.c)
 +target_link_libraries(proton.js qpid-proton-bitcode)
 +
 +set_target_properties(
 +  proton.js
 +  PROPERTIES
 +  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
 +
 +  # The --memory-init-file 0 stops emscripten emitting a separate memory
 +  # initialization file, if this was enabled it makes packaging harder as
 +  # applications would expect proton.js.mem to be served too. It's even more
 +  # fiddly with node.js packages. This behaviour might be reinstated if the
 +  # packaging mechanism improves.
 +
 +  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/module.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/error.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/message.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_get_version_major', '
 _pn_get_version_minor', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_messenger_set_passive', '_pn_messenger_selectable', '_pn_subscription_get_context', '_pn_subscriptio
 n_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_
 set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_
 pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump', '_pn_selectable_readable', '_pn_selectable_capacity', '_pn_selectable_writable', '_pn_selectable_pending', '_pn_
 selectable_is_terminal', '_pn_selectable_fd', '_pn_selectable_free']\""
 +  )
 +
 +# This command packages up the compiled proton.js into a node.js package called
 +# qpid-proton and copies it to the <proton>/node_modules directory. This allows
 +# the node.js test and example programs to do proton = require("qpid-proton");
 +add_custom_command(
 +    TARGET proton.js
 +    COMMAND ${CMAKE_COMMAND}
 +            -E copy_directory 
 +            ${CMAKE_CURRENT_SOURCE_DIR}/qpid-proton 
 +            ${PROJECT_SOURCE_DIR}/node_modules/qpid-proton
 +    COMMAND ${CMAKE_COMMAND}
 +            -E copy
 +            ${CMAKE_CURRENT_BINARY_DIR}/proton.js
 +            ${PROJECT_SOURCE_DIR}/node_modules/qpid-proton/lib
 +   COMMENT "Building qpid-proton package for node.js"
 +)
 +
 +# The cleanall target removes the qpid-proton package from <proton>/node_modules
 +add_custom_target(
 +    cleanall
 +    COMMAND echo "CLEAN NODE MODULES"
 +    COMMAND ${CMAKE_COMMAND}
 +            -E remove_directory
 +            ${PROJECT_SOURCE_DIR}/node_modules/qpid-proton
 +)
 +
 +# If the docs target is specified and the jsdoc3 package for node.js has been
 +# installed then build the JavaScript API documentation.
 +if (NODE_JSDOC_FOUND)
 +    set(JSDOC_EXE ${PROJECT_SOURCE_DIR}/node_modules/.bin/jsdoc)
 +
 +    message(STATUS "Documentation Enabled. Using ${JSDOC_EXE} to build JavaScript docs")
 +    add_custom_target(docs-js COMMAND ${JSDOC_EXE}
 +                      -d ${CMAKE_CURRENT_BINARY_DIR}/html
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/module.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/error.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/message.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/data.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js
 +                      ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js)
 +    add_dependencies(docs docs-js)
 +endif (NODE_JSDOC_FOUND)
 +


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


[23/51] [abbrv] qpid-proton git commit: Update with merge of latest proton codebase and checked against latest emscripten incoming branch

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingInboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingInboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingInboundTransformer.java
new file mode 100644
index 0000000..82c03c6
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingInboundTransformer.java
@@ -0,0 +1,102 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.jms;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.amqp.messaging.*;
+
+import javax.jms.*;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public class JMSMappingInboundTransformer extends InboundTransformer {
+
+    public JMSMappingInboundTransformer(JMSVendor vendor) {
+        super(vendor);
+    }
+
+    @Override
+    public Message transform(EncodedMessage amqpMessage) throws Exception {
+        org.apache.qpid.proton.message.Message amqp = amqpMessage.decode();
+
+        Message rc;
+        final Section body = amqp.getBody();
+        if( body == null ) {
+            rc = vendor.createMessage();
+        } else if( body instanceof Data ) {
+            Binary d = ((Data) body).getValue();
+            BytesMessage m = vendor.createBytesMessage();
+            m.writeBytes(d.getArray(), d.getArrayOffset(), d.getLength());
+            rc = m;
+        } else if (body instanceof AmqpSequence ) {
+            AmqpSequence sequence = (AmqpSequence) body;
+            StreamMessage m = vendor.createStreamMessage();
+            for( Object item : sequence.getValue()) {
+                m.writeObject(item);
+            }
+            rc = m;
+        } else if (body instanceof AmqpValue) {
+            Object value = ((AmqpValue) body).getValue();
+            if( value == null ) {
+                rc = vendor.createObjectMessage();
+            } if( value instanceof String ) {
+                TextMessage m = vendor.createTextMessage();
+                m.setText((String) value);
+                rc = m;
+            } else if( value instanceof Binary ) {
+                Binary d = (Binary) value;
+                BytesMessage m = vendor.createBytesMessage();
+                m.writeBytes(d.getArray(), d.getArrayOffset(), d.getLength());
+                rc = m;
+            } else if( value instanceof List) {
+                StreamMessage m = vendor.createStreamMessage();
+                for( Object item : (List) value) {
+                    m.writeObject(item);
+                }
+                rc = m;
+            } else if( value instanceof Map) {
+                MapMessage m = vendor.createMapMessage();
+                final Set<Map.Entry<String, Object>> set = ((Map) value).entrySet();
+                for (Map.Entry<String, Object> entry : set) {
+                    m.setObject(entry.getKey(), entry.getValue());
+                }
+                rc = m;
+            } else {
+                ObjectMessage m = vendor.createObjectMessage();
+                m.setObject((Serializable) value);
+                rc = m;
+            }
+        } else {
+            throw new RuntimeException("Unexpected body type: "+body.getClass());
+        }
+        rc.setJMSDeliveryMode(defaultDeliveryMode);
+        rc.setJMSPriority(defaultPriority);
+        rc.setJMSExpiration(defaultTtl);
+
+        populateMessage(rc, amqp);
+
+        rc.setLongProperty(prefixVendor + "MESSAGE_FORMAT", amqpMessage.getMessageFormat());
+        rc.setBooleanProperty(prefixVendor + "NATIVE", false);
+        return rc;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
new file mode 100644
index 0000000..47c487c
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
@@ -0,0 +1,246 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.jms;
+
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.codec.CompositeWritableBuffer;
+import org.apache.qpid.proton.codec.WritableBuffer;
+import org.apache.qpid.proton.codec.DroppingWritableBuffer;
+import org.apache.qpid.proton.message.ProtonJMessage;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedByte;
+import org.apache.qpid.proton.amqp.UnsignedInteger;
+import org.apache.qpid.proton.amqp.messaging.*;
+
+import javax.jms.*;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public class JMSMappingOutboundTransformer extends OutboundTransformer {
+
+    String prefixDeliveryAnnotations = "DA_";
+    String prefixMessageAnnotations= "MA_";
+    String prefixFooter = "FT_";
+
+    public JMSMappingOutboundTransformer(JMSVendor vendor) {
+        super(vendor);
+    }
+
+    @Override
+    public EncodedMessage transform(Message msg) throws Exception {
+        if( msg == null )
+            return null;
+        try {
+            if( msg.getBooleanProperty(prefixVendor + "NATIVE") ) {
+                return null;
+            }
+        } catch (MessageFormatException e) {
+            return null;
+        }
+        return transform(this, msg);
+    }
+
+    static EncodedMessage transform(JMSMappingOutboundTransformer options, Message msg) throws JMSException, UnsupportedEncodingException {
+        final JMSVendor vendor = options.vendor;
+
+        final String messageFormatKey = options.prefixVendor + "MESSAGE_FORMAT";
+        final String nativeKey = options.prefixVendor + "NATIVE";
+        final String firstAcquirerKey = options.prefixVendor + "FirstAcquirer";
+        final String prefixDeliveryAnnotationsKey = options.prefixVendor + options.prefixDeliveryAnnotations;
+        final String prefixMessageAnnotationsKey = options.prefixVendor + options.prefixMessageAnnotations;
+        final String subjectKey =  options.prefixVendor +"Subject";
+        final String contentTypeKey = options.prefixVendor +"ContentType";
+        final String contentEncodingKey = options.prefixVendor +"ContentEncoding";
+        final String replyToGroupIDKey = options.prefixVendor +"ReplyToGroupID";
+        final String prefixFooterKey = options.prefixVendor + options.prefixFooter;
+
+        long messageFormat;
+        try {
+            messageFormat = msg.getLongProperty(messageFormatKey);
+        } catch (MessageFormatException e) {
+            return null;
+        }
+
+        Header header = new Header();
+        Properties props=new Properties();
+        HashMap<Symbol, Object> daMap = null;
+        HashMap<Symbol, Object> maMap = null;
+        HashMap apMap = null;
+        Section body=null;
+        HashMap footerMap = null;
+        if( msg instanceof BytesMessage ) {
+            BytesMessage m = (BytesMessage)msg;
+            byte data[] = new byte[(int) m.getBodyLength()];
+            m.readBytes(data);
+            m.reset(); //Need to reset after readBytes or future readBytes calls (ex: redeliveries) will fail and return -1
+            body = new Data(new Binary(data));
+        } if( msg instanceof TextMessage ) {
+            body = new AmqpValue(((TextMessage) msg).getText());
+        } if( msg instanceof MapMessage ) {
+            final HashMap map = new HashMap();
+            final MapMessage m = (MapMessage) msg;
+            final Enumeration names = m.getMapNames();
+            while (names.hasMoreElements()) {
+                String key = (String) names.nextElement();
+                map.put(key, m.getObject(key));
+            }
+            body = new AmqpValue(map);
+        } if( msg instanceof StreamMessage ) {
+            ArrayList list = new ArrayList();
+            final StreamMessage m = (StreamMessage) msg;
+            try {
+                while(true) {
+                    list.add(m.readObject());
+                }
+            } catch(MessageEOFException e){}
+            body = new AmqpSequence(list);
+        } if( msg instanceof ObjectMessage ) {
+            body = new AmqpValue(((ObjectMessage) msg).getObject());
+        }
+
+        header.setDurable(msg.getJMSDeliveryMode() == DeliveryMode.PERSISTENT ? true : false);
+        header.setPriority(new UnsignedByte((byte) msg.getJMSPriority()));
+        if( msg.getJMSType()!=null ) {
+            if( maMap==null ) maMap = new HashMap<Symbol, Object>();
+            maMap.put(Symbol.valueOf("x-opt-jms-type"), msg.getJMSType());
+        }
+        if( msg.getJMSMessageID()!=null ) {
+            props.setMessageId(msg.getJMSMessageID());
+        }
+        if( msg.getJMSDestination()!=null ) {
+            props.setTo(vendor.toAddress(msg.getJMSDestination()));
+            if( maMap==null ) maMap = new HashMap();
+            maMap.put(Symbol.valueOf("x-opt-to-type"), destinationAttributes(msg.getJMSDestination()));
+        }
+        if( msg.getJMSReplyTo()!=null ) {
+            props.setReplyTo(vendor.toAddress(msg.getJMSReplyTo()));
+            if( maMap==null ) maMap = new HashMap();
+            maMap.put(Symbol.valueOf("x-opt-reply-type"), destinationAttributes(msg.getJMSReplyTo()));
+        }
+        if( msg.getJMSCorrelationID()!=null ) {
+            props.setCorrelationId(msg.getJMSCorrelationID());
+        }
+        if( msg.getJMSExpiration() != 0 ) {
+            long ttl = msg.getJMSExpiration() - System.currentTimeMillis();
+            if (ttl < 0) {
+                ttl = 1;
+            }
+            header.setTtl(new UnsignedInteger((int)ttl));
+
+            props.setAbsoluteExpiryTime(new Date(msg.getJMSExpiration()));
+        }
+        if( msg.getJMSTimestamp()!= 0 ) {
+            props.setCreationTime(new Date(msg.getJMSTimestamp()));
+        }
+
+        final Enumeration keys = msg.getPropertyNames();
+        while (keys.hasMoreElements()) {
+            String key = (String) keys.nextElement();
+            if( key.equals(messageFormatKey) || key.equals(nativeKey)) {
+                // skip..
+            } else if( key.equals(firstAcquirerKey) ) {
+                header.setFirstAcquirer(msg.getBooleanProperty(key));
+            } else if( key.startsWith("JMSXDeliveryCount") ) {
+                header.setDeliveryCount(new UnsignedInteger(msg.getIntProperty(key)));
+            } else if( key.startsWith("JMSXUserID") ) {
+                String value = msg.getStringProperty(key);
+                props.setUserId(new Binary(value.getBytes("UTF-8")));
+            } else if( key.startsWith("JMSXGroupID") ) {
+                String value = msg.getStringProperty(key);
+                props.setGroupId(value);
+                if( apMap==null ) apMap = new HashMap();
+                apMap.put(key, value);
+            } else if( key.startsWith("JMSXGroupSeq") ) {
+                UnsignedInteger value = new UnsignedInteger(msg.getIntProperty(key));
+                props.setGroupSequence(value);
+                if( apMap==null ) apMap = new HashMap();
+                apMap.put(key, value);
+            } else if( key.startsWith(prefixDeliveryAnnotationsKey) ) {
+                if( daMap == null ) daMap = new HashMap<Symbol, Object>();
+                String name = key.substring(prefixDeliveryAnnotationsKey.length());
+                daMap.put(Symbol.valueOf(name), msg.getObjectProperty(key));
+            } else if( key.startsWith(prefixMessageAnnotationsKey) ) {
+                if( maMap==null ) maMap = new HashMap<Symbol, Object>();
+                String name = key.substring(prefixMessageAnnotationsKey.length());
+                maMap.put(Symbol.valueOf(name), msg.getObjectProperty(key));
+            } else if( key.equals(subjectKey) ) {
+                props.setSubject(msg.getStringProperty(key));
+            } else if( key.equals(contentTypeKey) ) {
+                props.setContentType(Symbol.getSymbol(msg.getStringProperty(key)));
+            } else if( key.equals(contentEncodingKey) ) {
+                props.setContentEncoding(Symbol.getSymbol(msg.getStringProperty(key)));
+            } else if( key.equals(replyToGroupIDKey) ) {
+                props.setReplyToGroupId(msg.getStringProperty(key));
+            } else if( key.startsWith(prefixFooterKey) ) {
+                if( footerMap==null ) footerMap = new HashMap();
+                String name = key.substring(prefixFooterKey.length());
+                footerMap.put(name, msg.getObjectProperty(key));
+            } else {
+                if( apMap==null ) apMap = new HashMap();
+                apMap.put(key, msg.getObjectProperty(key));
+            }
+        }
+
+
+        MessageAnnotations ma=null;
+        if( maMap!=null ) ma = new MessageAnnotations(maMap);
+        DeliveryAnnotations da=null;
+        if( daMap!=null ) da = new DeliveryAnnotations(daMap);
+        ApplicationProperties ap=null;
+        if( apMap!=null ) ap = new ApplicationProperties(apMap);
+        Footer footer=null;
+        if( footerMap!=null ) footer = new Footer(footerMap);
+
+        ProtonJMessage amqp = (ProtonJMessage) org.apache.qpid.proton.message.Message.Factory.create(header, da, ma, props, ap, body, footer);
+
+        ByteBuffer buffer = ByteBuffer.wrap(new byte[1024*4]);
+        final DroppingWritableBuffer overflow = new DroppingWritableBuffer();
+        int c = amqp.encode(new CompositeWritableBuffer(new WritableBuffer.ByteBufferWrapper(buffer), overflow));
+        if( overflow.position() > 0 ) {
+            buffer = ByteBuffer.wrap(new byte[1024*4+overflow.position()]);
+            c = amqp.encode(new WritableBuffer.ByteBufferWrapper(buffer));
+        }
+
+        return new EncodedMessage(messageFormat, buffer.array(), 0, c);
+    }
+
+    private static String destinationAttributes(Destination destination) {
+        if( destination instanceof Queue ) {
+            if( destination instanceof TemporaryQueue ) {
+                return "temporary,queue";
+            } else {
+                return "queue";
+            }
+        }
+        if( destination instanceof Topic ) {
+            if( destination instanceof TemporaryTopic ) {
+                return "temporary,topic";
+            } else {
+                return "topic";
+            }
+        }
+        return "";
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSVendor.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSVendor.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSVendor.java
new file mode 100644
index 0000000..5d02069
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSVendor.java
@@ -0,0 +1,45 @@
+package org.apache.qpid.proton.jms;
+
+import javax.jms.*;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+ */
+abstract public class JMSVendor {
+
+    public abstract BytesMessage createBytesMessage();
+
+    public abstract StreamMessage createStreamMessage();
+
+    public abstract Message createMessage();
+
+    public abstract TextMessage createTextMessage();
+
+    public abstract ObjectMessage createObjectMessage();
+
+    public abstract MapMessage createMapMessage();
+
+    public abstract void setJMSXUserID(Message msg, String value);
+
+    @Deprecated
+    public Destination createDestination(String name) {
+        return null;
+    }
+
+    @SuppressWarnings("deprecation")
+    public <T extends Destination> T createDestination(String name, Class<T> kind) {
+        return kind.cast(createDestination(name));
+    }
+
+    public abstract void setJMSXGroupID(Message msg, String groupId);
+
+    public abstract void setJMSXGroupSequence(Message msg, int i);
+
+    public abstract void setJMSXDeliveryCount(Message rc, long l);
+
+    public abstract String toAddress(Destination msgDestination);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java
----------------------------------------------------------------------
diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java
new file mode 100644
index 0000000..87175b0
--- /dev/null
+++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.proton.jms;
+
+import org.apache.qpid.proton.engine.Delivery;
+
+import javax.jms.Message;
+
+/**
+* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
+*/
+public abstract class OutboundTransformer {
+
+    JMSVendor vendor;
+    String prefixVendor = "JMS_AMQP_";
+
+    public OutboundTransformer(JMSVendor vendor) {
+        this.vendor = vendor;
+    }
+
+    public abstract EncodedMessage transform(Message jms) throws Exception;
+
+    public String getPrefixVendor() {
+        return prefixVendor;
+    }
+
+    public void setPrefixVendor(String prefixVendor) {
+        this.prefixVendor = prefixVendor;
+    }
+
+    public JMSVendor getVendor() {
+        return vendor;
+    }
+
+    public void setVendor(JMSVendor vendor) {
+        this.vendor = vendor;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 4f7f948..7b01b00 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -19,4 +19,5 @@
 
 set (Proton_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
 add_subdirectory(messenger/c)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/java/recv
----------------------------------------------------------------------
diff --git a/examples/messenger/java/recv b/examples/messenger/java/recv
index 7092148..9c6409d 100755
--- a/examples/messenger/java/recv
+++ b/examples/messenger/java/recv
@@ -6,7 +6,7 @@
 
 HERE=$(cd $(dirname $0); pwd)
 TOP=$(cd $(dirname $0); cd  ../../..; pwd)
-LIBS=$HERE/target/classes:$TOP/proton-j/proton-api/target/classes:$TOP/proton-j/proton/target/classes
+LIBS=$HERE/target/classes:$TOP/proton-j/target/classes
 JFLAGS="-Djava.util.logging.config.file=$HERE/recv.trace.props -cp $LIBS"
 java -cp $LIBS org.apache.qpid.proton.example.Recv "$@"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/java/send
----------------------------------------------------------------------
diff --git a/examples/messenger/java/send b/examples/messenger/java/send
index 280eeba..d304f20 100755
--- a/examples/messenger/java/send
+++ b/examples/messenger/java/send
@@ -4,7 +4,7 @@
 
 HERE=$(cd $(dirname $0); pwd)
 TOP=$(cd $(dirname $0); cd  ../../..; pwd)
-LIBS=$HERE/target/classes:$TOP/proton-j/proton-api/target/classes:$TOP/proton-j/proton/target/classes
+LIBS=$HERE/target/classes:$TOP/proton-j/target/classes
 JFLAGS="-Djava.util.logging.config.file=$HERE/send.trace.props -cp $LIBS"
 java -cp $LIBS org.apache.qpid.proton.example.Send "$@"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java
----------------------------------------------------------------------
diff --git a/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java b/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java
index e0e1f42..56bce55 100644
--- a/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java
+++ b/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java
@@ -40,9 +40,9 @@ import java.util.logging.Logger;
 public class Send {
 
     private static Logger tracer = Logger.getLogger("proton.example");
-    private String address = "amqp://0.0.0.0/test";
+    private String address = "amqp://0.0.0.0";
     private String subject;
-    private String[] bodies;
+    private String[] bodies = new String[]{"Hello World!"};
 
     private static void usage() {
         System.err.println("Usage: send [-a ADDRESS] [-s SUBJECT] MSG+");
@@ -67,7 +67,11 @@ public class Send {
                 break;
             }
         }
-        bodies = Arrays.copyOfRange(args, i, args.length);
+
+        if(i != args.length)
+        {
+            bodies = Arrays.copyOfRange(args, i, args.length);
+        }
     }
 
     private void run() {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/javascript/send.html
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html
index b6aaef2..eff1fad 100644
--- a/examples/messenger/javascript/send.html
+++ b/examples/messenger/javascript/send.html
@@ -58,7 +58,17 @@ console.log("body = " + body);
     messenger.put(message);
 };
 
-messenger.on('error', function(error) {console.log("Received error " + error);});
+messenger.on('error', function(error) {
+    console.log("Received error " + error);
+
+message.free();
+messenger.free();
+message = new proton.Message();
+messenger = new proton.Messenger();
+messenger.start();
+console.log("Restarted");
+});
+
 messenger.start();
 
 </script>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/perl/recv.pl
----------------------------------------------------------------------
diff --git a/examples/messenger/perl/recv.pl b/examples/messenger/perl/recv.pl
index 6e4f273..801f6a2 100755
--- a/examples/messenger/perl/recv.pl
+++ b/examples/messenger/perl/recv.pl
@@ -18,9 +18,11 @@
 # under the License.
 #
 
-use strict;
 use warnings;
 
+use Scalar::Util qw(reftype);
+use Data::Dumper;
+
 use qpid_proton;
 
 sub usage {
@@ -48,10 +50,34 @@ for(;;)
     while ($messenger->incoming() > 0)
     {
         $messenger->get($msg);
+
+        print "\n";
         print "Address: " . $msg->get_address() . "\n";
-        print "Subject: " . $msg->get_subject() . "\n";
-        print "Content: " . $msg->get_content() . "\n";
-        print "Body:    " . $msg->get_body() . "\n";
+        print "Subject: " . $msg->get_subject() . "\n" unless !defined($msg->get_subject());
+        print "Body:    ";
+
+        my $body = $msg->get_body();
+        my $body_type = $msg->get_body_type();
+
+        if (!defined($body_type)) {
+            print "The body type wasn't defined!\n";
+        } elsif ($body_type == qpid::proton::BOOL) {
+            print "[BOOL]\n";
+            print "" . ($body ? "TRUE" : "FALSE") . "\n";
+        } elsif ($body_type == qpid::proton::MAP) {
+            print "[HASH]\n";
+            print Dumper(\%{$body}) . "\n";
+        } elsif ($body_type == qpid::proton::ARRAY) {
+            print "[ARRAY]\n";
+            print Data::Dumper->Dump($body) . "\n";
+        } elsif ($body_type == qpid::proton::LIST) {
+            print "[LIST]\n";
+            print Data::Dumper->Dump($body) . "\n";
+        } else {
+            print "[$body_type]\n";
+            print "$body\n";
+        }
+
         print "Properties:\n";
         my $props = $msg->get_properties();
         foreach (keys $props) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/perl/send.pl
----------------------------------------------------------------------
diff --git a/examples/messenger/perl/send.pl b/examples/messenger/perl/send.pl
index 9d907d6..b622b68 100755
--- a/examples/messenger/perl/send.pl
+++ b/examples/messenger/perl/send.pl
@@ -34,11 +34,14 @@ sub HELP_MESSAGE() {
     print "Options:\n";
     print "\t-s        - the message subject\n";
     print "\t-C        - the message content\n";
-    print "\t<ADDRESS> - amqp://<domain>[/<name>]";
+    print "\t<ADDRESS> - amqp://<domain>[/<name>]\n";
+    print "\t-h        - this message\n";
+
+    exit;
 }
 
 my %options = ();
-getopts("a:C:s:", \%options) or usage();
+getopts("a:C:s:h:", \%options) or HELP_MESSAGE();
 
 my $address = $options{a} || "amqp://0.0.0.0";
 my $subject = $options{s} || localtime(time);
@@ -58,7 +61,7 @@ foreach (@messages)
     $msg->set_subject($subject);
     $msg->set_content($content);
     # try a few different body types
-    my $body_type = int(rand(4));
+    my $body_type = int(rand(6));
     $msg->set_property("sent", "" . localtime(time));
     $msg->get_instructions->{"fold"} = "yes";
     $msg->get_instructions->{"spindle"} = "no";
@@ -68,12 +71,15 @@ foreach (@messages)
 
   SWITCH: {
       $body_type == 0 && do { $msg->set_body("It is now " . localtime(time));};
-      $body_type == 1 && do { $msg->set_body(rand(65536), qpid::proton::FLOAT); };
+      $body_type == 1 && do { $msg->set_body(rand(65536)); };
       $body_type == 2 && do { $msg->set_body(int(rand(2)), qpid::proton::BOOL); };
-      $body_type == 3 && do { $msg->set_body({"foo" => "bar"}, qpid::proton::MAP); };
+      $body_type == 3 && do { $msg->set_body({"foo" => "bar"}); };
+      $body_type == 4 && do { $msg->set_body([4, [1, 2, 3.1, 3.4E-5], 8, 15, 16, 23, 42]); };
+      $body_type == 5 && do { $msg->set_body(int(rand(65535))); }
     }
 
     $messenger->put($msg);
+    print "Sent: " . $msg->get_body . " [CONTENT TYPE: " . $msg->get_body_type . "]\n";
 }
 
 $messenger->send();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/perl/server.pl
----------------------------------------------------------------------
diff --git a/examples/messenger/perl/server.pl b/examples/messenger/perl/server.pl
index 25d1a44..c13d4d5 100755
--- a/examples/messenger/perl/server.pl
+++ b/examples/messenger/perl/server.pl
@@ -58,8 +58,10 @@ sub dispatch {
 
     $reply->set_properties($request->get_properties);
     print "Dispatched " . $request->get_subject . "\n";
-    foreach (keys $request->get_properties) {
-        print "\t$_:" . $request->get_properties->{$_} . "\n";
+    my $properties = $request->get_properties;
+    foreach (keys %{$properties}) {
+        my $value = $properties->{%_};
+        print "\t$_: $value\n";
     }
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 76b082b..9f74b10 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -58,26 +58,30 @@ configure_file (
   "${CMAKE_CURRENT_BINARY_DIR}/include/proton/version.h"
   )
 
-include_directories ("${CMAKE_CURRENT_BINARY_DIR}")
+include_directories ("${CMAKE_CURRENT_BINARY_DIR}/src")
 include_directories ("${CMAKE_CURRENT_BINARY_DIR}/include")
+include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/src")
 include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/include")
-include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../examples/include")
+
+# TODO: This is only needed because the proton executable can use getopt on windows
+# if/when this executable gets sorted out remove
+include_directories ("${CMAKE_SOURCE_DIR}/examples/include")
 
 add_custom_command (
-  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
-  COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
+  COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py
   )
 
 add_custom_command (
-  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
-  COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py > ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h
+  COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py > ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h
   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py
   )
 
 # Select driver
 if(PN_WINAPI)
-  set (pn_io_impl src/windows/io.c)
+  set (pn_io_impl src/windows/io.c src/windows/iocp.c src/windows/write_pipeline.c)
   set (pn_selector_impl src/windows/selector.c)
   set (pn_driver_impl src/windows/driver.c)
 else(PN_WINAPI)
@@ -89,6 +93,7 @@ endif(PN_WINAPI)
 # Link in openssl if present
 if (SSL_IMPL STREQUAL openssl)
   set (pn_driver_ssl_impl src/ssl/openssl.c)
+  include_directories ("${OPENSSL_INCLUDE_DIR}")
   set (SSL_LIB ${OPENSSL_LIBRARIES})
 else (SSL_IMPL STREQUAL openssl)
   set (pn_driver_ssl_impl src/ssl/ssl_stub.c)
@@ -220,7 +225,13 @@ if (CMAKE_COMPILER_IS_GNUCC)
 endif (CMAKE_COMPILER_IS_GNUCC)
 
 if (MSVC)
-	set(CMAKE_DEBUG_POSTFIX "d")
+    set(CMAKE_DEBUG_POSTFIX "d")
+    add_definitions(
+        /wd4244
+        /wd4267
+        /wd4800
+        /wd4996
+    )
 endif (MSVC)
 
 macro (pn_absolute_install_dir NAME VALUE PREFIX)
@@ -293,8 +304,8 @@ set (qpid-proton-core
   src/messenger/transform.c
   src/selectable.c
 
-  ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
-  ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
+  ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
+  ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h
   )
 
 set_source_files_properties (
@@ -368,6 +379,18 @@ install (TARGETS qpid-proton
   ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
   LIBRARY DESTINATION ${LIB_INSTALL_DIR})
 
+# Install windows qpid-proton pdb files
+if (MSVC)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpid-proton${CMAKE_DEBUG_POSTFIX}.pdb
+    DESTINATION bin 
+    CONFIGURATIONS Debug
+    OPTIONAL)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/qpid-proton.pdb
+    DESTINATION bin 
+    CONFIGURATIONS RelWithDebInfo
+    OPTIONAL)
+endif (MSVC)
+
 # Install header files
 file(GLOB headers "include/proton/*.[hi]")
 install (FILES ${headers} DESTINATION ${INCLUDE_INSTALL_DIR}/proton)
@@ -464,10 +487,10 @@ set (py_bin "${CMAKE_CURRENT_BINARY_DIR}/bindings/python")
 set (py_bld "${CMAKE_CURRENT_BINARY_DIR}${bld_suffix}") # For windows
 set (app_path "${pn_test_bin}/tools/apps/c${bld_suffix}")
 set (app_path "${app_path}:${pn_test_root}/tools/apps/python")
-set_path (py_path "$ENV{PATH}:${py_bin}:${py_bld}:${app_path}")
-set_path (py_pythonpath "$ENV{PYTHONPATH}:${py_root}:${py_src}:${py_bin}:${py_bld}")
+set_path (py_path "${py_bin}:${py_bld}:${app_path}:$ENV{PATH}")
+set_path (py_pythonpath "${py_root}:${py_src}:${py_bin}:${py_bld}|$ENV{PYTHONPATH}")
 if (CMAKE_SYSTEM_NAME STREQUAL Windows)
-  set_path (py_pythonpath "${py_pythonpath}:${py_bin}${bld_suffix}")
+  set_path (py_pythonpath "${py_bin}${bld_suffix}:${py_pythonpath}")
 endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
 add_test (python-test ${PYTHON_EXECUTABLE} ${env_py}
          "PATH=${py_path}" "PYTHONPATH=${py_pythonpath}" ${VALGRIND_ENV}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/CMakeLists.txt b/proton-c/bindings/CMakeLists.txt
index 70cc552..b5e6fba 100644
--- a/proton-c/bindings/CMakeLists.txt
+++ b/proton-c/bindings/CMakeLists.txt
@@ -62,7 +62,9 @@ if (RUBY_FOUND)
   if (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV)
     set (DEFAULT_RUBY_TESTING ON CACHE INTERNAL "")
   else()
+    message(STATUS "Skipping Ruby bindings due to missing dependencies...")
     set (DEFAULT_RUBY_TESTING OFF CACHE INTERNAL "")
+    set (DEFAULT_RUBY OFF)
   endif (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV)
 endif (RUBY_FOUND)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index ae24407..02f9ccb 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -43,10 +43,14 @@ set(CMAKE_C_COMPILER "${EMCC}")
 include(CMakeForceCompiler)
 CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang)
 
-if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
-    message(STATUS "DEBUG JavaScript build")
+# The Proton default build type is RelWithDebInfo, but for JavaScript the C debug
+# mechanism is irrelevant. If Debug is explicitly set we turn off optimisations
+# and don't run the closure compiler so any error/profiling messages are readable.
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+    message(STATUS "JavaScript build type is \"Debug\"")
 else()
-    message(STATUS "RELEASE JavaScript build")
+    set (CMAKE_BUILD_TYPE Release)
+    message(STATUS "JavaScript build type is \"Release\"")
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
     set(EMSCRIPTEN_LINK_OPTIMISATIONS "-O2 --closure 1")
 endif()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/CMakeLists.txt b/proton-c/bindings/perl/CMakeLists.txt
index 365439b..2a25327 100644
--- a/proton-c/bindings/perl/CMakeLists.txt
+++ b/proton-c/bindings/perl/CMakeLists.txt
@@ -43,7 +43,9 @@ if (NOT PERL_VENDORARCH_DIR)
 endif()
 
 set (CMAKE_C_FLAGS ${PERLCFLAGS})
-
+list(APPEND SWIG_MODULE_cproton_perl_EXTRA_DEPS
+    ${CMAKE_SOURCE_DIR}/proton-c/include/proton/cproton.i
+)
 swig_add_module(cproton_perl perl perl.i)
 swig_link_libraries(cproton_perl ${BINDING_DEPS} ${PERL_LIBRARY})
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid/proton/Constants.pm
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/lib/qpid/proton/Constants.pm b/proton-c/bindings/perl/lib/qpid/proton/Constants.pm
index 8397011..2cb93e7 100644
--- a/proton-c/bindings/perl/lib/qpid/proton/Constants.pm
+++ b/proton-c/bindings/perl/lib/qpid/proton/Constants.pm
@@ -20,6 +20,9 @@
 package qpid::proton;
 
 use constant {
+    VERSION_MAJOR => $cproton_perl::PN_VERSION_MAJOR,
+    VERSION_MINOR => $cproton_perl::PN_VERSION_MINOR,
+
     NULL       => $cproton_perl::PN_NULL,
     BOOL       => qpid::proton::Mapping->new(
         "bool",
@@ -129,8 +132,8 @@ use constant {
     LIST      => qpid::proton::Mapping->new(
         "list",
         $cproton_perl::PN_LIST,
-        "put_list",
-        "get_list"),
+        "put_list_helper",
+        "get_list_helper"),
     MAP      => qpid::proton::Mapping->new(
         "map",
         $cproton_perl::PN_MAP,

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid/proton/Data.pm
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/lib/qpid/proton/Data.pm b/proton-c/bindings/perl/lib/qpid/proton/Data.pm
index 90f5ecb..156e09a 100644
--- a/proton-c/bindings/perl/lib/qpid/proton/Data.pm
+++ b/proton-c/bindings/perl/lib/qpid/proton/Data.pm
@@ -17,7 +17,7 @@
 # under the License.
 #
 
-use Scalar::Util qw(looks_like_number);
+use Scalar::Util qw(reftype looks_like_number);
 
 =pod
 
@@ -321,9 +321,7 @@ Handles a boolean (B<true>/B<false>) node.
 sub put_bool {
     my ($self) = @_;
     my $impl = $self->{_impl};
-    my $value = $_[1];
-
-    die "bool must be defined" if !defined($value);
+    my $value = $_[1] || 0;
 
     cproton_perl::pn_data_put_bool($impl, $value);
 }
@@ -1159,16 +1157,90 @@ sub get_map {
     cproton_perl::pn_data_get_map($impl);
 }
 
+sub put_list_helper {
+    my ($self) = @_;
+    my ($array) = $_[1];
+
+    $self->put_list;
+    $self->enter;
+
+    for my $value (@{$array}) {
+        if (qpid::proton::is_num($value)) {
+            if (qpid::proton::is_float($value)) {
+                $self->put_float($value);
+            } else {
+                $self->put_int($value);
+            }
+        } elsif (!defined($value)) {
+            $self->put_null;
+        } elsif ($value eq '') {
+            $self->put_string($value);
+        } elsif (ref($value) eq 'HASH') {
+            $self->put_map_helper($value);
+        } elsif (ref($value) eq 'ARRAY') {
+            $self->put_list_helper($value);
+        } else {
+            $self->put_string($value);
+        }
+    }
+
+    $self->exit;
+}
+
+sub get_list_helper {
+    my ($self) = @_;
+    my $result = [];
+    my $type = $self->get_type;
+
+    if ($cproton_perl::PN_LIST == $type->get_type_value) {
+        my $size = $self->get_list;
+
+        $self->enter;
+
+        for(my $count = 0; $count < $size; $count++) {
+            if ($self->next) {
+                my $value_type = $self->get_type;
+                my $value = $value_type->get($self);
+
+                push(@{$result}, $value);
+            }
+        }
+
+        $self->exit;
+    }
+
+    return $result;
+}
+
 sub put_map_helper {
     my ($self) = @_;
-    my ($hash) = $_[1];
+    my $hash = $_[1];
 
     $self->put_map;
     $self->enter;
 
-    foreach(keys $hash) {
-        $self->put_string("$_");
-        $self->put_string("$hash->{$_}");
+    foreach(keys %{$hash}) {
+        my $key = $_;
+        my $value = $hash->{$key};
+
+        my $keytype = ::reftype($key);
+        my $valtype = ::reftype($value);
+
+        if ($keytype eq ARRAY) {
+            $self->put_list_helper($key);
+        } elsif ($keytype eq "HASH") {
+            $self->put_map_helper($key);
+        } else {
+            $self->put_string("$key");
+        }
+
+        if (::reftype($value) eq HASH) {
+            $self->put_map_helper($value);
+        } elsif (::reftype($value) eq ARRAY) {
+            $self->put_list_helper($value);
+        } else {
+            $self->put_string("$value");
+        }
     }
 
     $self->exit;
@@ -1193,9 +1265,10 @@ sub get_map_helper {
                 }
             }
         }
-    }
 
-    $self->exit;
+        $self->exit;
+
+    }
 
     return $result;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid/proton/Message.pm
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/lib/qpid/proton/Message.pm b/proton-c/bindings/perl/lib/qpid/proton/Message.pm
index 8a38988..49aeccd 100644
--- a/proton-c/bindings/perl/lib/qpid/proton/Message.pm
+++ b/proton-c/bindings/perl/lib/qpid/proton/Message.pm
@@ -443,7 +443,29 @@ B<qpid::proton::STRING>.
 sub set_body {
     my ($self) = @_;
     my $body = $_[1];
-    my $body_type = $_[2] || qpid::proton::STRING;
+    my $body_type = $_[2] || undef;
+
+    # if no body type was defined, then attempt to infer what it should
+    # be, which is going to be a best guess
+    if (!defined($body_type)) {
+        if (qpid::proton::is_num($body)) {
+            if (qpid::proton::is_float($body)) {
+                $body_type = qpid::proton::FLOAT;
+            } else {
+                $body_type = qpid::proton::INT;
+            }
+        } elsif (!defined($body)) {
+            $body_type =  qpid::proton::NULL;
+        } elsif ($body eq '') {
+            $body_type =  qpid::proton::STRING;
+        } elsif (ref($body) eq 'HASH') {
+            $body_type =  qpid::proton::MAP;
+        } elsif (ref($body) eq 'ARRAY') {
+            $body_type =  qpid::proton::LIST;
+        } else {
+            $body_type =  qpid::proton::STRING;
+        }
+    }
 
     $self->{_body} = $body;
     $self->{_body_type} = $body_type;
@@ -465,12 +487,12 @@ sub get_body_type {
 sub preencode() {
     my ($self) = @_;
     my $impl = $self->{_impl};
-
     my $my_body = $self->{_body};
     my $body_type = $self->{_body_type};
     my $body = new qpid::proton::Data(cproton_perl::pn_message_body($impl));
+
     $body->clear();
-    $body_type->put($body, $my_body) if($my_body && $body_type);
+    $body_type->put($body, $my_body) if(defined($my_body) && $body_type);
 
     my $my_props = $self->{_properties};
     my $props = new qpid::proton::Data(cproton_perl::pn_message_properties($impl));

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid/proton/utils.pm
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/lib/qpid/proton/utils.pm b/proton-c/bindings/perl/lib/qpid/proton/utils.pm
new file mode 100644
index 0000000..75af498
--- /dev/null
+++ b/proton-c/bindings/perl/lib/qpid/proton/utils.pm
@@ -0,0 +1,31 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+package qpid::proton;
+
+sub is_num {
+    my $val = $_[0];
+
+    return 0 if !defined($val);
+    return 0 if $val eq '';
+
+    $_[0] ^ $_[0] ? 0 : 1
+}
+
+1;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid_proton.pm
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/lib/qpid_proton.pm b/proton-c/bindings/perl/lib/qpid_proton.pm
index dc7fefb..de4e224 100644
--- a/proton-c/bindings/perl/lib/qpid_proton.pm
+++ b/proton-c/bindings/perl/lib/qpid_proton.pm
@@ -21,6 +21,7 @@ use strict;
 use warnings;
 use cproton_perl;
 
+use qpid::proton::utils;
 use qpid::proton::ExceptionHandling;
 use qpid::proton::Data;
 use qpid::proton::Mapping;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/perl.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/perl.i b/proton-c/bindings/perl/perl.i
index cc6a4d7..ad059f3 100644
--- a/proton-c/bindings/perl/perl.i
+++ b/proton-c/bindings/perl/perl.i
@@ -10,13 +10,6 @@
 #include <proton/driver_extras.h>
 %}
 
-typedef unsigned int size_t;
-typedef signed int ssize_t;
-typedef unsigned char uint8_t;
-typedef unsigned int uint32_t;
-typedef unsigned long int uint64_t;
-typedef int int32_t;
-
 %include <cstring.i>
 
 %typemap(in) pn_atom_t

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/php/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/php/CMakeLists.txt b/proton-c/bindings/php/CMakeLists.txt
index 762e05b..637f692 100644
--- a/proton-c/bindings/php/CMakeLists.txt
+++ b/proton-c/bindings/php/CMakeLists.txt
@@ -30,6 +30,9 @@ execute_process(COMMAND ${PHP_CONFIG_EXE} --includes
                 OUTPUT_STRIP_TRAILING_WHITESPACE)
 
 set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/php.i PROPERTIES SWIG_FLAGS "-I${PROJECT_SOURCE_DIR}/include")
+list(APPEND SWIG_MODULE_cproton_EXTRA_DEPS
+    ${CMAKE_SOURCE_DIR}/proton-c/include/proton/cproton.i
+)
 swig_add_module(cproton php ${CMAKE_CURRENT_SOURCE_DIR}/php.i)
 set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "${PHP_INCLUDES}")
 swig_link_libraries(cproton ${BINDING_DEPS})

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/php/proton.php
----------------------------------------------------------------------
diff --git a/proton-c/bindings/php/proton.php b/proton-c/bindings/php/proton.php
index 4c3e4ef..2e2a69a 100644
--- a/proton-c/bindings/php/proton.php
+++ b/proton-c/bindings/php/proton.php
@@ -286,7 +286,7 @@ class Message {
     if ($ann->next())
       $this->annotations = $ann->get_object();
     else
-      $self->annotations = null;
+      $this->annotations = null;
     if ($props->next())
       $this->properties = $props->get_object();
     else

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt
index 7853e18..b8cdb57 100644
--- a/proton-c/bindings/python/CMakeLists.txt
+++ b/proton-c/bindings/python/CMakeLists.txt
@@ -16,41 +16,38 @@
 # specific language governing permissions and limitations
 # under the License.
 #
+
+# NB For python the SWIG module name must have the same name as the
+# input .i file for CMake to generate the correct dependencies
+
 set(CMAKE_SWIG_FLAGS "-threads")
 
 include_directories (${PYTHON_INCLUDE_PATH})
 if (BUILD_WITH_CXX)
-   SET_SOURCE_FILES_PROPERTIES(python.i PROPERTIES CPLUSPLUS ON)
+   SET_SOURCE_FILES_PROPERTIES(cproton.i PROPERTIES CPLUSPLUS ON)
 endif (BUILD_WITH_CXX)
-swig_add_module(cproton python python.i)
+
+list(APPEND SWIG_MODULE_cproton_EXTRA_DEPS
+    ${CMAKE_SOURCE_DIR}/proton-c/include/proton/cproton.i
+)
+
+swig_add_module(cproton python cproton.i)
 swig_link_libraries(cproton ${BINDING_DEPS} ${PYTHON_LIBRARIES})
-set_target_properties(_cproton
+set_target_properties(${SWIG_MODULE_cproton_REAL_NAME}
     PROPERTIES
     LINK_FLAGS "${CATCH_UNDEFINED}")
 
 find_package(PythonInterp REQUIRED)
 
-if (CHECK_SYSINSTALL_PYTHON)
-  execute_process(COMMAND ${PYTHON_EXECUTABLE}
-    -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True)"
-    OUTPUT_VARIABLE PYTHON_SITEARCH_PACKAGES_DEFAULT
-    OUTPUT_STRIP_TRAILING_WHITESPACE)
-else ()
-  set (PYTHON_SITEARCH_PACKAGES_DEFAULT ${BINDINGS_DIR}/python)
-endif ()
-
-if (NOT PYTHON_SITEARCH_PACKAGES)
-  set (PYTHON_SITEARCH_PACKAGES ${PYTHON_SITEARCH_PACKAGES_DEFAULT})
-endif()
-
-install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cproton.py
-                              WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
-install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cproton.py
-                              WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
-install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile proton.py
-                              WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
-install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile proton.py
-                              WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
+# configure the files needed for generating Pypi packages. Packages
+# can be generated by running "python setup.py" from the build
+# directory.
+get_filename_component(PN_SWIG_PYTHON_C_WRAPPER
+                       ${swig_generated_file_fullname} NAME)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/proton.py
+               ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in
+               ${CMAKE_CURRENT_BINARY_DIR}/setup.py @ONLY)
 
 find_program(EPYDOC_EXE epydoc)
 mark_as_advanced (EPYDOC_EXE)
@@ -66,14 +63,37 @@ if (EPYDOC_EXE)
            ${OPTIONAL_ARG})
 endif (EPYDOC_EXE)
 
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton.py
-              ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyc
-              ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyo
-              ${CMAKE_CURRENT_SOURCE_DIR}/proton.py
-              ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyc
-              ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyo
-        DESTINATION ${PYTHON_SITEARCH_PACKAGES}
-        COMPONENT Python)
-install(TARGETS _cproton
-        DESTINATION ${PYTHON_SITEARCH_PACKAGES}
-        COMPONENT Python)
+if (CHECK_SYSINSTALL_PYTHON)
+  # use the python-native install paths:
+
+  install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} setup.py sdist
+                                WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
+  install(CODE "execute_process(COMMAND
+   ${PYTHON_EXECUTABLE} setup.py --proton-install-prefix ${CMAKE_INSTALL_PREFIX} install
+                          WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
+
+else ()
+  # install the bindings using the CMAKE path variables:
+  set (PYTHON_SITEARCH_PACKAGES ${BINDINGS_DIR}/python)
+
+  install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cproton.py
+                                WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
+  install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cproton.py
+                                WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
+  install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile proton.py
+                                WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
+  install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile proton.py
+                                WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
+
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton.py
+                ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyc
+                ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyo
+                ${CMAKE_CURRENT_SOURCE_DIR}/proton.py
+                ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyc
+                ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyo
+          DESTINATION ${PYTHON_SITEARCH_PACKAGES}
+          COMPONENT Python)
+  install(TARGETS ${SWIG_MODULE_cproton_REAL_NAME}
+          DESTINATION ${PYTHON_SITEARCH_PACKAGES}
+          COMPONENT Python)
+endif()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/python/cproton.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/cproton.i b/proton-c/bindings/python/cproton.i
new file mode 100644
index 0000000..496897f
--- /dev/null
+++ b/proton-c/bindings/python/cproton.i
@@ -0,0 +1,379 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+%module cproton
+%{
+/* Includes the header in the wrapper code */
+#if defined(_WIN32) && ! defined(__CYGWIN__)
+#include <winsock2.h>
+#endif
+#include <proton/engine.h>
+#include <proton/message.h>
+#include <proton/sasl.h>
+#include <proton/driver.h>
+#include <proton/driver_extras.h>
+#include <proton/messenger.h>
+#include <proton/ssl.h>
+%}
+
+%include <cstring.i>
+
+%cstring_output_withsize(char *OUTPUT, size_t *OUTPUT_SIZE)
+%cstring_output_allocate_size(char **ALLOC_OUTPUT, size_t *ALLOC_SIZE, free(*$1));
+%cstring_output_maxsize(char *OUTPUT, size_t MAX_OUTPUT_SIZE)
+
+// These are not used/needed in the python binding
+%ignore pn_message_get_id;
+%ignore pn_message_set_id;
+%ignore pn_message_get_correlation_id;
+%ignore pn_message_set_correlation_id;
+
+%typemap(in) pn_bytes_t {
+  if ($input == Py_None) {
+    $1.start = NULL;
+    $1.size = 0;
+  } else {
+    $1.start = PyString_AsString($input);
+    if (!$1.start) {
+      return NULL;
+    }
+    $1.size = PyString_Size($input);
+  }
+}
+
+%typemap(out) pn_bytes_t {
+  $result = PyString_FromStringAndSize($1.start, $1.size);
+}
+
+%typemap(out) pn_delivery_tag_t {
+  $result = PyString_FromStringAndSize($1.bytes, $1.size);
+}
+
+%typemap(in) pn_uuid_t {
+  memset($1.bytes, 0, 16);
+  if ($input == Py_None) {
+    ; // Already zeroed out
+  } else {
+    const char* b = PyString_AsString($input);
+    if (b) {
+        memmove($1.bytes, b, (PyString_Size($input) < 16 ? PyString_Size($input) : 16));
+    } else {
+        return NULL;
+    }
+  }
+}
+
+%typemap(out) pn_uuid_t {
+  $result = PyString_FromStringAndSize($1.bytes, 16);
+}
+
+%apply pn_uuid_t { pn_decimal128_t };
+
+int pn_message_load(pn_message_t *msg, char *STRING, size_t LENGTH);
+%ignore pn_message_load;
+
+int pn_message_load_data(pn_message_t *msg, char *STRING, size_t LENGTH);
+%ignore pn_message_load_data;
+
+int pn_message_load_text(pn_message_t *msg, char *STRING, size_t LENGTH);
+%ignore pn_message_load_text;
+
+int pn_message_load_amqp(pn_message_t *msg, char *STRING, size_t LENGTH);
+%ignore pn_message_load_amqp;
+
+int pn_message_load_json(pn_message_t *msg, char *STRING, size_t LENGTH);
+%ignore pn_message_load_json;
+
+int pn_message_encode(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_encode;
+
+int pn_message_save(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save;
+
+int pn_message_save_data(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save_data;
+
+int pn_message_save_text(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save_text;
+
+int pn_message_save_amqp(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save_amqp;
+
+int pn_message_save_json(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save_json;
+
+ssize_t pn_link_send(pn_link_t *transport, char *STRING, size_t LENGTH);
+%ignore pn_link_send;
+
+%rename(pn_link_recv) wrap_pn_link_recv;
+%inline %{
+  int wrap_pn_link_recv(pn_link_t *link, char *OUTPUT, size_t *OUTPUT_SIZE) {
+    ssize_t sz = pn_link_recv(link, OUTPUT, *OUTPUT_SIZE);
+    if (sz >= 0) {
+      *OUTPUT_SIZE = sz;
+    } else {
+      *OUTPUT_SIZE = 0;
+    }
+    return sz;
+  }
+%}
+%ignore pn_link_recv;
+
+ssize_t pn_transport_push(pn_transport_t *transport, char *STRING, size_t LENGTH);
+%ignore pn_transport_push;
+
+%rename(pn_transport_peek) wrap_pn_transport_peek;
+%inline %{
+  int wrap_pn_transport_peek(pn_transport_t *transport, char *OUTPUT, size_t *OUTPUT_SIZE) {
+    ssize_t sz = pn_transport_peek(transport, OUTPUT, *OUTPUT_SIZE);
+    if (sz >= 0) {
+      *OUTPUT_SIZE = sz;
+    } else {
+      *OUTPUT_SIZE = 0;
+    }
+    return sz;
+  }
+%}
+%ignore pn_transport_peek;
+
+%rename(pn_delivery) wrap_pn_delivery;
+%inline %{
+  pn_delivery_t *wrap_pn_delivery(pn_link_t *link, char *STRING, size_t LENGTH) {
+    return pn_delivery(link, pn_dtag(STRING, LENGTH));
+  }
+%}
+%ignore pn_delivery;
+
+%rename(pn_delivery_tag) wrap_pn_delivery_tag;
+%inline %{
+  void wrap_pn_delivery_tag(pn_delivery_t *delivery, char **ALLOC_OUTPUT, size_t *ALLOC_SIZE) {
+    pn_delivery_tag_t tag = pn_delivery_tag(delivery);
+    *ALLOC_OUTPUT = (char *) malloc(tag.size);
+    *ALLOC_SIZE = tag.size;
+    memcpy(*ALLOC_OUTPUT, tag.bytes, tag.size);
+  }
+%}
+%ignore pn_delivery_tag;
+
+%rename(pn_message_data) wrap_pn_message_data;
+%inline %{
+  int wrap_pn_message_data(char *STRING, size_t LENGTH, char *OUTPUT, size_t *OUTPUT_SIZE) {
+    ssize_t sz = pn_message_data(OUTPUT, *OUTPUT_SIZE, STRING, LENGTH);
+    if (sz >= 0) {
+      *OUTPUT_SIZE = sz;
+    } else {
+      *OUTPUT_SIZE = 0;
+    }
+    return sz;
+  }
+%}
+%ignore pn_message_data;
+
+%rename(pn_listener_set_context) wrap_pn_listener_set_context;
+%inline {
+  void wrap_pn_listener_set_context(pn_listener_t *l, PyObject *context) {
+    // don't incref context: we 'borrow' the reference - prevents
+    // reference loops.  Should be safe as the Python object must
+    // outlive the C object.
+    pn_listener_set_context(l, context);
+  }
+}
+%ignore pn_listener_set_context;
+
+%rename(pn_listener_context) wrap_pn_listener_context;
+%inline {
+  PyObject *wrap_pn_listener_context(pn_listener_t *l) {
+    PyObject *result = (PyObject *) pn_listener_context(l);
+    // incref the returned context, as the caller expects this
+    if (result) {
+      Py_INCREF(result);
+      return result;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+%ignore pn_listener_context;
+
+%rename(pn_connector_set_context) wrap_pn_connector_set_context;
+%inline {
+  void wrap_pn_connector_set_context(pn_connector_t *c, PyObject *context) {
+    // don't incref context: we 'borrow' the reference - prevents
+    // reference loops.  Should be safe as the Python object must
+    // outlive the C object.
+    pn_connector_set_context(c, context);
+  }
+}
+%ignore pn_connector_set_context;
+
+%rename(pn_connector_context) wrap_pn_connector_context;
+%inline {
+  PyObject *wrap_pn_connector_context(pn_connector_t *c) {
+    PyObject *result = (PyObject *) pn_connector_context(c);
+    // incref the returned context, as the caller expects this
+    if (result) {
+      Py_INCREF(result);
+      return result;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+%ignore pn_connector_context;
+
+%rename(pn_connection_get_context) wrap_pn_connection_get_context;
+%inline {
+  PyObject *wrap_pn_connection_get_context(pn_connection_t *c) {
+    PyObject *result = (PyObject *) pn_connection_get_context(c);
+    // incref the returned context, as the caller expects this
+    if (result) {
+      Py_INCREF(result);
+      return result;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+%ignore pn_connection_get_context;
+
+%rename(pn_connection_set_context) wrap_pn_connection_set_context;
+%inline {
+  void wrap_pn_connection_set_context(pn_connection_t *c, PyObject *context) {
+    // don't incref context: we 'borrow' the reference
+    pn_connection_set_context(c, context);
+  }
+}
+%ignore pn_connection_set_context;
+
+%rename(pn_session_get_context) wrap_pn_session_get_context;
+%inline {
+  PyObject *wrap_pn_session_get_context(pn_session_t *s) {
+    PyObject *result = (PyObject *) pn_session_get_context(s);
+    // incref the returned context, as the caller expects this
+    if (result) {
+      Py_INCREF(result);
+      return result;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+%ignore pn_session_get_context;
+
+%rename(pn_session_set_context) wrap_pn_session_set_context;
+%inline {
+  void wrap_pn_session_set_context(pn_session_t *s, PyObject *context) {
+    // don't incref context: we 'borrow' the reference
+    pn_session_set_context(s, context);
+  }
+}
+%ignore pn_session_set_context;
+
+%rename(pn_link_get_context) wrap_pn_link_get_context;
+%inline {
+  PyObject *wrap_pn_link_get_context(pn_link_t *l) {
+    PyObject *result = (PyObject *) pn_link_get_context(l);
+    // incref the returned context, as the caller expects this
+    if (result) {
+      Py_INCREF(result);
+      return result;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+%ignore pn_link_get_context;
+
+%rename(pn_link_set_context) wrap_pn_link_set_context;
+%inline {
+  void wrap_pn_link_set_context(pn_link_t *l, PyObject *context) {
+    // don't incref context: we 'borrow' the reference
+    pn_link_set_context(l, context);
+  }
+}
+%ignore pn_link_set_context;
+
+%rename(pn_delivery_get_context) wrap_pn_delivery_get_context;
+%inline {
+  PyObject *wrap_pn_delivery_get_context(pn_delivery_t *d) {
+    PyObject *result = (PyObject *) pn_delivery_get_context(d);
+    // incref the returned context, as the caller expects this
+    if (result) {
+      Py_INCREF(result);
+      return result;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+%ignore pn_delivery_get_context;
+
+%rename(pn_delivery_set_context) wrap_pn_delivery_set_context;
+%inline {
+  void wrap_pn_delivery_set_context(pn_delivery_t *d, PyObject *context) {
+    // don't incref context: we 'borrow' the reference
+    pn_delivery_set_context(d, context);
+  }
+}
+%ignore pn_delivery_set_context;
+
+ssize_t pn_data_decode(pn_data_t *data, char *STRING, size_t LENGTH);
+%ignore pn_data_decode;
+
+%rename(pn_data_encode) wrap_pn_data_encode;
+%inline %{
+  int wrap_pn_data_encode(pn_data_t *data, char *OUTPUT, size_t *OUTPUT_SIZE) {
+    ssize_t sz = pn_data_encode(data, OUTPUT, *OUTPUT_SIZE);
+    if (sz >= 0) {
+      *OUTPUT_SIZE = sz;
+    } else {
+      *OUTPUT_SIZE = 0;
+    }
+    return sz;
+  }
+%}
+%ignore pn_data_encode;
+
+%rename(pn_sasl_recv) wrap_pn_sasl_recv;
+%inline %{
+  int wrap_pn_sasl_recv(pn_sasl_t *sasl, char *OUTPUT, size_t *OUTPUT_SIZE) {
+    ssize_t sz = pn_sasl_recv(sasl, OUTPUT, *OUTPUT_SIZE);
+    if (sz >= 0) {
+      *OUTPUT_SIZE = sz;
+    } else {
+      *OUTPUT_SIZE = 0;
+    }
+    return sz;
+  }
+%}
+%ignore pn_sasl_recv;
+
+int pn_data_format(pn_data_t *data, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_data_format;
+
+bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE);
+%ignore pn_ssl_get_cipher_name;
+
+bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE);
+%ignore pn_ssl_get_protocol_name;
+
+int pn_ssl_get_peer_hostname(pn_ssl_t *ssl, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_ssl_get_peer_hostname;
+
+
+%include "proton/cproton.i"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/python/proton.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton.py b/proton-c/bindings/python/proton.py
index 12da599..7294d45 100644
--- a/proton-c/bindings/python/proton.py
+++ b/proton-c/bindings/python/proton.py
@@ -464,6 +464,7 @@ first message.
     sub_impl = pn_messenger_subscribe(self._mng, source)
     if not sub_impl:
       self._check(pn_error_code(pn_messenger_error(self._mng)))
+      raise MessengerException("Cannot subscribe to %s"%source)
     return Subscription(sub_impl)
 
   def put(self, message):
@@ -760,8 +761,7 @@ first message.
       return None
 
 class Message(object):
-  """
-  The L{Message} class is a mutable holder of message content.
+  """The L{Message} class is a mutable holder of message content.
 
   @ivar instructions: delivery instructions for the message
   @type instructions: dict
@@ -780,7 +780,10 @@ class Message(object):
 
   DEFAULT_PRIORITY = PN_DEFAULT_PRIORITY
 
-  def __init__(self):
+  def __init__(self, **kwargs):
+    """
+    @param kwargs: Message property name/value pairs to initialise the Message
+    """
     self._msg = pn_message()
     self._id = Data(pn_message_id(self._msg))
     self._correlation_id = Data(pn_message_correlation_id(self._msg))
@@ -788,6 +791,9 @@ class Message(object):
     self.annotations = None
     self.properties = None
     self.body = None
+    for k,v in kwargs.iteritems():
+      getattr(self, k)          # Raise exception if it's not a valid attribute.
+      setattr(self, k, v)
 
   def __del__(self):
     if hasattr(self, "_msg"):
@@ -860,7 +866,14 @@ class Message(object):
   def _set_inferred(self, value):
     self._check(pn_message_set_inferred(self._msg, bool(value)))
 
-  inferred = property(_is_inferred, _set_inferred)
+  inferred = property(_is_inferred, _set_inferred,"""
+The inferred flag for a message indicates how the message content
+is encoded into AMQP sections. If inferred is true then binary and
+list values in the body of the message will be encoded as AMQP DATA
+and AMQP SEQUENCE sections, respectively. If inferred is false,
+then all values in the body of the message will be encoded as AMQP
+VALUE sections regardless of their type.
+""")
 
   def _is_durable(self):
     return pn_message_is_durable(self._msg)
@@ -2165,6 +2178,16 @@ class Endpoint(object):
 
   def __init__(self):
     self.condition = None
+    self._release_invoked = False
+
+  def _release(self):
+    """Release the underlying C Engine resource."""
+    if not self._release_invoked:
+      for c in self._children:
+        c._release()
+      self._free_resource()
+      self.connection._releasing(self)
+      self._release_invoked = True
 
   def _update_cond(self):
     obj2cond(self.condition, self._get_cond_impl())
@@ -2256,13 +2279,32 @@ class Connection(Endpoint):
 
   def __del__(self):
     if hasattr(self, "_conn") and self._conn:
-      # pn_connection_free will release all child sessions in the C Engine, so
-      # free all child python Sessions to avoid dangling references
-      if hasattr(self, "_sessions") and self._sessions:
-        for s in self._sessions:
-          s._release()
-      pn_connection_set_context(self._conn, None)
-      pn_connection_free(self._conn)
+      self._release()
+
+  def free(self):
+    self._release()
+
+  @property
+  def _children(self):
+    return self._sessions
+
+  @property
+  def connection(self):
+    return self
+
+  def _free_resource(self):
+    pn_connection_free(self._conn)
+
+  def _released(self):
+    self._conn = None
+
+  def _releasing(self, child):
+    coll = getattr(self, "_collector", None)
+    if coll: coll = coll()
+    if coll:
+      coll._contexts.add(child)
+    else:
+      child._released()
 
   def _check(self, err):
     if err < 0:
@@ -2282,9 +2324,7 @@ class Connection(Endpoint):
       pn_connection_collect(self._conn, None)
     else:
       pn_connection_collect(self._conn, collector._impl)
-    # XXX: we can't let coll go out of scope or the connection will be
-    # pointing to garbage
-    self._collector = collector
+    self._collector = weakref.ref(collector)
 
   def _get_container(self):
     return pn_connection_get_container(self._conn)
@@ -2376,16 +2416,15 @@ class Session(Endpoint):
     self._links = set()
     self.connection._sessions.add(self)
 
-  def _release(self):
-    """Release the underlying C Engine resource."""
-    if self._ssn:
-      # pn_session_free will release all child links in the C Engine, so free
-      # all child python Links to avoid dangling references
-      for l in self._links:
-        l._release()
-      pn_session_set_context(self._ssn, None)
-      pn_session_free(self._ssn)
-      self._ssn = None
+  @property
+  def _children(self):
+    return self._links
+
+  def _free_resource(self):
+    pn_session_free(self._ssn)
+
+  def _released(self):
+    self._ssn = None
 
   def free(self):
     """Release the Session, freeing its resources.
@@ -2477,16 +2516,15 @@ class Link(Endpoint):
     self._deliveries = set()
     self.session._links.add(self)
 
-  def _release(self):
-    """Release the underlying C Engine resource."""
-    if self._link:
-      # pn_link_free will settle all child deliveries in the C Engine, so free
-      # all child python deliveries to avoid dangling references
-      for d in self._deliveries:
-        d._release()
-      pn_link_set_context(self._link, None)
-      pn_link_free(self._link)
-      self._link = None
+  @property
+  def _children(self):
+    return self._deliveries
+
+  def _free_resource(self):
+    pn_link_free(self._link)
+
+  def _released(self):
+    self._link = None
 
   def free(self):
     """Release the Link, freeing its resources"""
@@ -2536,6 +2574,10 @@ class Link(Endpoint):
   def session(self):
     return Session._wrap_session(pn_link_session(self._link))
 
+  @property
+  def connection(self):
+    return self.session.connection
+
   def delivery(self, tag):
     return Delivery._wrap_delivery(pn_delivery(self._link, tag))
 
@@ -2719,13 +2761,38 @@ class Receiver(Link):
   def draining(self):
     return pn_link_draining(self._link)
 
+class NamedInt(int):
+
+  values = {}
+
+  def __new__(cls, i, name):
+    ni = super(NamedInt, cls).__new__(cls, i)
+    cls.values[i] = ni
+    return ni
+
+  def __init__(self, i, name):
+    self.name = name
+
+  def __repr__(self):
+    return self.name
+
+  def __str__(self):
+    return self.name
+
+  @classmethod
+  def get(cls, i):
+    return cls.values.get(i, i)
+
+class DispositionType(NamedInt):
+  values = {}
+
 class Disposition(object):
 
-  RECEIVED = PN_RECEIVED
-  ACCEPTED = PN_ACCEPTED
-  REJECTED = PN_REJECTED
-  RELEASED = PN_RELEASED
-  MODIFIED = PN_MODIFIED
+  RECEIVED = DispositionType(PN_RECEIVED, "RECEIVED")
+  ACCEPTED = DispositionType(PN_ACCEPTED, "ACCEPTED")
+  REJECTED = DispositionType(PN_REJECTED, "REJECTED")
+  RELEASED = DispositionType(PN_RELEASED, "RELEASED")
+  MODIFIED = DispositionType(PN_MODIFIED, "MODIFIED")
 
   def __init__(self, impl, local):
     self._impl = impl
@@ -2736,7 +2803,7 @@ class Disposition(object):
 
   @property
   def type(self):
-    return pn_disposition_type(self._impl)
+    return DispositionType.get(pn_disposition_type(self._impl))
 
   def _get_section_number(self):
     return pn_disposition_get_section_number(self._impl)
@@ -2824,12 +2891,13 @@ class Delivery(object):
     self.remote = Disposition(pn_delivery_remote(self._dlv), False)
     self.link._deliveries.add(self)
 
+  def __del__(self):
+    pn_delivery_set_context(self._dlv, None)
+
   def _release(self):
     """Release the underlying C Engine resource."""
     if self._dlv:
-      pn_delivery_set_context(self._dlv, None)
       pn_delivery_settle(self._dlv)
-      self._dlv = None
 
   @property
   def tag(self):
@@ -2863,11 +2931,11 @@ class Delivery(object):
 
   @property
   def local_state(self):
-    return pn_delivery_local_state(self._dlv)
+    return DispositionType.get(pn_delivery_local_state(self._dlv))
 
   @property
   def remote_state(self):
-    return pn_delivery_remote_state(self._dlv)
+    return DispositionType.get(pn_delivery_remote_state(self._dlv))
 
   @property
   def settled(self):
@@ -2891,6 +2959,7 @@ class TransportException(ProtonException):
 
 class Transport(object):
 
+  TRACE_OFF = PN_TRACE_OFF
   TRACE_DRV = PN_TRACE_DRV
   TRACE_FRM = PN_TRACE_FRM
   TRACE_RAW = PN_TRACE_RAW
@@ -2955,7 +3024,9 @@ class Transport(object):
       return self._check(c)
 
   def push(self, bytes):
-    self._check(pn_transport_push(self._trans, bytes))
+    n = self._check(pn_transport_push(self._trans, bytes))
+    if n != len(bytes):
+      raise OverflowError("unable to process all bytes")
 
   def close_tail(self):
     self._check(pn_transport_close_tail(self._trans))
@@ -2981,26 +3052,9 @@ class Transport(object):
   def close_head(self):
     self._check(pn_transport_close_head(self._trans))
 
-  def output(self, size):
-    p = self.pending()
-    if p < 0:
-      return None
-    else:
-      out = self.peek(min(size, p))
-      self.pop(len(out))
-      return out
-
-  def input(self, bytes):
-    if not bytes:
-      self.close_tail()
-      return None
-    else:
-      c = self.capacity()
-      if (c < 0):
-        return None
-      trimmed = bytes[:c]
-      self.push(trimmed)
-      return len(trimmed)
+  @property
+  def closed(self):
+    return pn_transport_closed(self._trans)
 
   # AMQP 1.0 max-frame-size
   def _get_max_frame_size(self):
@@ -3078,6 +3132,7 @@ class SASL(object):
 
   OK = PN_SASL_OK
   AUTH = PN_SASL_AUTH
+  SKIPPED = PN_SASL_SKIPPED
 
   def __new__(cls, transport):
     """Enforce a singleton SASL object per Transport"""
@@ -3103,6 +3158,9 @@ class SASL(object):
   def server(self):
     pn_sasl_server(self._sasl)
 
+  def allow_skip(self, allow):
+    pn_sasl_allow_skip(self._sasl, allow)
+
   def plain(self, user, password):
     pn_sasl_plain(self._sasl, user, password)
 
@@ -3265,6 +3323,7 @@ class Collector:
 
   def __init__(self):
     self._impl = pn_collector()
+    self._contexts = set()
 
   def peek(self):
     event = pn_collector_peek(self._impl)
@@ -3285,6 +3344,9 @@ class Collector:
                  transport=tp)
 
   def pop(self):
+    ev = self.peek()
+    if ev is not None:
+      ev._popped(self)
     pn_collector_pop(self._impl)
 
   def __del__(self):
@@ -3292,15 +3354,34 @@ class Collector:
 
 class Event:
 
-  CATEGORY_PROTOCOL = PN_EVENT_CATEGORY_PROTOCOL
-
-  CONNECTION_LOCAL_STATE = PN_CONNECTION_LOCAL_STATE
-  CONNECTION_REMOTE_STATE = PN_CONNECTION_REMOTE_STATE
-  SESSION_LOCAL_STATE = PN_SESSION_LOCAL_STATE
-  SESSION_REMOTE_STATE = PN_SESSION_REMOTE_STATE
-  LINK_LOCAL_STATE = PN_LINK_LOCAL_STATE
-  LINK_REMOTE_STATE = PN_LINK_REMOTE_STATE
+  CATEGORY_CONNECTION = PN_EVENT_CATEGORY_CONNECTION
+  CATEGORY_SESSION = PN_EVENT_CATEGORY_SESSION
+  CATEGORY_LINK = PN_EVENT_CATEGORY_LINK
+  CATEGORY_DELIVERY = PN_EVENT_CATEGORY_DELIVERY
+  CATEGORY_TRANSPORT = PN_EVENT_CATEGORY_TRANSPORT
+
+  CONNECTION_INIT = PN_CONNECTION_INIT
+  CONNECTION_OPEN = PN_CONNECTION_OPEN
+  CONNECTION_CLOSE = PN_CONNECTION_CLOSE
+  CONNECTION_REMOTE_OPEN = PN_CONNECTION_REMOTE_OPEN
+  CONNECTION_REMOTE_CLOSE = PN_CONNECTION_REMOTE_CLOSE
+  CONNECTION_FINAL = PN_CONNECTION_FINAL
+
+  SESSION_INIT = PN_SESSION_INIT
+  SESSION_OPEN = PN_SESSION_OPEN
+  SESSION_CLOSE = PN_SESSION_CLOSE
+  SESSION_REMOTE_OPEN = PN_SESSION_REMOTE_OPEN
+  SESSION_REMOTE_CLOSE = PN_SESSION_REMOTE_CLOSE
+  SESSION_FINAL = PN_SESSION_FINAL
+
+  LINK_INIT = PN_LINK_INIT
+  LINK_OPEN = PN_LINK_OPEN
+  LINK_CLOSE = PN_LINK_CLOSE
+  LINK_REMOTE_OPEN = PN_LINK_REMOTE_OPEN
+  LINK_REMOTE_CLOSE = PN_LINK_REMOTE_CLOSE
   LINK_FLOW = PN_LINK_FLOW
+  LINK_FINAL = PN_LINK_FINAL
+
   DELIVERY = PN_DELIVERY
   TRANSPORT = PN_TRANSPORT
 
@@ -3314,6 +3395,19 @@ class Event:
     self.delivery = delivery
     self.transport = transport
 
+  def _popped(self, collector):
+    if self.type == Event.LINK_FINAL:
+      ctx = self.link
+    elif self.type == Event.SESSION_FINAL:
+      ctx = self.session
+    elif self.type == Event.CONNECTION_FINAL:
+      ctx = self.connection
+    else:
+      return
+
+    collector._contexts.remove(ctx)
+    ctx._released()
+
   def __repr__(self):
     objects = [self.connection, self.session, self.link, self.delivery,
                self.transport]
@@ -3544,6 +3638,8 @@ __all__ = [
            "Messenger",
            "MessengerException",
            "ProtonException",
+           "PN_VERSION_MAJOR",
+           "PN_VERSION_MINOR",
            "Receiver",
            "SASL",
            "Sender",

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/python/python.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/python.i b/proton-c/bindings/python/python.i
deleted file mode 100644
index 878b34c..0000000
--- a/proton-c/bindings/python/python.i
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-%module cproton
-%{
-/* Includes the header in the wrapper code */
-#if defined(_WIN32) && ! defined(__CYGWIN__)
-#include <winsock2.h>
-#endif
-#include <proton/engine.h>
-#include <proton/message.h>
-#include <proton/sasl.h>
-#include <proton/driver.h>
-#include <proton/driver_extras.h>
-#include <proton/messenger.h>
-#include <proton/ssl.h>
-%}
-
-%include <cstring.i>
-
-%cstring_output_withsize(char *OUTPUT, size_t *OUTPUT_SIZE)
-%cstring_output_allocate_size(char **ALLOC_OUTPUT, size_t *ALLOC_SIZE, free(*$1));
-%cstring_output_maxsize(char *OUTPUT, size_t MAX_OUTPUT_SIZE)
-
-%typemap(in) pn_bytes_t {
-  if ($input == Py_None) {
-    $1.start = NULL;
-    $1.size = 0;
-  } else {
-    $1.start = PyString_AsString($input);
-    if (!$1.start) {
-      return NULL;
-    }
-    $1.size = PyString_Size($input);
-  }
-}
-
-%typemap(out) pn_bytes_t {
-  $result = PyString_FromStringAndSize($1.start, $1.size);
-}
-
-%typemap(in) pn_decimal128_t {
-  memmove($1.bytes, PyString_AsString($input), 16);
-}
-
-%typemap(out) pn_decimal128_t {
-  $result = PyString_FromStringAndSize($1.bytes, 16);
-}
-
-%typemap(in) pn_uuid_t {
-  memmove($1.bytes, PyString_AsString($input), 16);
-}
-
-%typemap(out) pn_uuid_t {
-  $result = PyString_FromStringAndSize($1.bytes, 16);
-}
-
-int pn_message_load(pn_message_t *msg, char *STRING, size_t LENGTH);
-%ignore pn_message_load;
-
-int pn_message_load_data(pn_message_t *msg, char *STRING, size_t LENGTH);
-%ignore pn_message_load_data;
-
-int pn_message_load_text(pn_message_t *msg, char *STRING, size_t LENGTH);
-%ignore pn_message_load_text;
-
-int pn_message_load_amqp(pn_message_t *msg, char *STRING, size_t LENGTH);
-%ignore pn_message_load_amqp;
-
-int pn_message_load_json(pn_message_t *msg, char *STRING, size_t LENGTH);
-%ignore pn_message_load_json;
-
-int pn_message_encode(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
-%ignore pn_message_encode;
-
-int pn_message_save(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
-%ignore pn_message_save;
-
-int pn_message_save_data(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
-%ignore pn_message_save_data;
-
-int pn_message_save_text(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
-%ignore pn_message_save_text;
-
-int pn_message_save_amqp(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
-%ignore pn_message_save_amqp;
-
-int pn_message_save_json(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
-%ignore pn_message_save_json;
-
-ssize_t pn_link_send(pn_link_t *transport, char *STRING, size_t LENGTH);
-%ignore pn_link_send;
-
-%rename(pn_link_recv) wrap_pn_link_recv;
-%inline %{
-  int wrap_pn_link_recv(pn_link_t *link, char *OUTPUT, size_t *OUTPUT_SIZE) {
-    ssize_t sz = pn_link_recv(link, OUTPUT, *OUTPUT_SIZE);
-    if (sz >= 0) {
-      *OUTPUT_SIZE = sz;
-    } else {
-      *OUTPUT_SIZE = 0;
-    }
-    return sz;
-  }
-%}
-%ignore pn_link_recv;
-
-int pn_transport_push(pn_transport_t *transport, char *STRING, size_t LENGTH);
-%ignore pn_transport_push;
-
-%rename(pn_transport_peek) wrap_pn_transport_peek;
-%inline %{
-  int wrap_pn_transport_peek(pn_transport_t *transport, char *OUTPUT, size_t *OUTPUT_SIZE) {
-    return pn_transport_peek(transport, OUTPUT, *OUTPUT_SIZE);
-  }
-%}
-%ignore pn_transport_peek;
-
-ssize_t pn_transport_input(pn_transport_t *transport, char *STRING, size_t LENGTH);
-%ignore pn_transport_input;
-
-%rename(pn_transport_output) wrap_pn_transport_output;
-%inline %{
-  int wrap_pn_transport_output(pn_transport_t *transport, char *OUTPUT, size_t *OUTPUT_SIZE) {
-    ssize_t sz = pn_transport_output(transport, OUTPUT, *OUTPUT_SIZE);
-    if (sz >= 0) {
-      *OUTPUT_SIZE = sz;
-    } else {
-      *OUTPUT_SIZE = 0;
-    }
-    return sz;
-  }
-%}
-%ignore pn_transport_output;
-
-%rename(pn_delivery) wrap_pn_delivery;
-%inline %{
-  pn_delivery_t *wrap_pn_delivery(pn_link_t *link, char *STRING, size_t LENGTH) {
-    return pn_delivery(link, pn_dtag(STRING, LENGTH));
-  }
-%}
-%ignore pn_delivery;
-
-// Suppress "Warning(451): Setting a const char * variable may leak memory." on pn_delivery_tag_t
-%warnfilter(451) pn_delivery_tag_t;
-%rename(pn_delivery_tag) wrap_pn_delivery_tag;
-%inline %{
-  void wrap_pn_delivery_tag(pn_delivery_t *delivery, char **ALLOC_OUTPUT, size_t *ALLOC_SIZE) {
-    pn_delivery_tag_t tag = pn_delivery_tag(delivery);
-    *ALLOC_OUTPUT = (char *) malloc(tag.size);
-    *ALLOC_SIZE = tag.size;
-    memcpy(*ALLOC_OUTPUT, tag.bytes, tag.size);
-  }
-%}
-%ignore pn_delivery_tag;
-
-%rename(pn_message_data) wrap_pn_message_data;
-%inline %{
-  int wrap_pn_message_data(char *STRING, size_t LENGTH, char *OUTPUT, size_t *OUTPUT_SIZE) {
-    ssize_t sz = pn_message_data(OUTPUT, *OUTPUT_SIZE, STRING, LENGTH);
-    if (sz >= 0) {
-      *OUTPUT_SIZE = sz;
-    } else {
-      *OUTPUT_SIZE = 0;
-    }
-    return sz;
-  }
-%}
-%ignore pn_message_data;
-
-%rename(pn_listener_set_context) wrap_pn_listener_set_context;
-%inline {
-  void wrap_pn_listener_set_context(pn_listener_t *l, PyObject *context) {
-    // don't incref context: we 'borrow' the reference - prevents
-    // reference loops.  Should be safe as the Python object must
-    // outlive the C object.
-    pn_listener_set_context(l, context);
-  }
-}
-%ignore pn_listener_set_context;
-
-%rename(pn_listener_context) wrap_pn_listener_context;
-%inline {
-  PyObject *wrap_pn_listener_context(pn_listener_t *l) {
-    PyObject *result = (PyObject *) pn_listener_context(l);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_listener_context;
-
-%rename(pn_connector_set_context) wrap_pn_connector_set_context;
-%inline {
-  void wrap_pn_connector_set_context(pn_connector_t *c, PyObject *context) {
-    // don't incref context: we 'borrow' the reference - prevents
-    // reference loops.  Should be safe as the Python object must
-    // outlive the C object.
-    pn_connector_set_context(c, context);
-  }
-}
-%ignore pn_connector_set_context;
-
-%rename(pn_connector_context) wrap_pn_connector_context;
-%inline {
-  PyObject *wrap_pn_connector_context(pn_connector_t *c) {
-    PyObject *result = (PyObject *) pn_connector_context(c);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_connector_context;
-
-%rename(pn_connection_get_context) wrap_pn_connection_get_context;
-%inline {
-  PyObject *wrap_pn_connection_get_context(pn_connection_t *c) {
-    PyObject *result = (PyObject *) pn_connection_get_context(c);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_connection_get_context;
-
-%rename(pn_connection_set_context) wrap_pn_connection_set_context;
-%inline {
-  void wrap_pn_connection_set_context(pn_connection_t *c, PyObject *context) {
-    // don't incref context: we 'borrow' the reference
-    pn_connection_set_context(c, context);
-  }
-}
-%ignore pn_connection_set_context;
-
-%rename(pn_session_get_context) wrap_pn_session_get_context;
-%inline {
-  PyObject *wrap_pn_session_get_context(pn_session_t *s) {
-    PyObject *result = (PyObject *) pn_session_get_context(s);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_session_get_context;
-
-%rename(pn_session_set_context) wrap_pn_session_set_context;
-%inline {
-  void wrap_pn_session_set_context(pn_session_t *s, PyObject *context) {
-    // don't incref context: we 'borrow' the reference
-    pn_session_set_context(s, context);
-  }
-}
-%ignore pn_session_set_context;
-
-%rename(pn_link_get_context) wrap_pn_link_get_context;
-%inline {
-  PyObject *wrap_pn_link_get_context(pn_link_t *l) {
-    PyObject *result = (PyObject *) pn_link_get_context(l);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_link_get_context;
-
-%rename(pn_link_set_context) wrap_pn_link_set_context;
-%inline {
-  void wrap_pn_link_set_context(pn_link_t *l, PyObject *context) {
-    // don't incref context: we 'borrow' the reference
-    pn_link_set_context(l, context);
-  }
-}
-%ignore pn_link_set_context;
-
-%rename(pn_delivery_get_context) wrap_pn_delivery_get_context;
-%inline {
-  PyObject *wrap_pn_delivery_get_context(pn_delivery_t *d) {
-    PyObject *result = (PyObject *) pn_delivery_get_context(d);
-    // incref the returned context, as the caller expects this
-    if (result) {
-      Py_INCREF(result);
-      return result;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-%ignore pn_delivery_get_context;
-
-%rename(pn_delivery_set_context) wrap_pn_delivery_set_context;
-%inline {
-  void wrap_pn_delivery_set_context(pn_delivery_t *d, PyObject *context) {
-    // don't incref context: we 'borrow' the reference
-    pn_delivery_set_context(d, context);
-  }
-}
-%ignore pn_delivery_set_context;
-
-ssize_t pn_data_decode(pn_data_t *data, char *STRING, size_t LENGTH);
-%ignore pn_data_decode;
-
-%rename(pn_data_encode) wrap_pn_data_encode;
-%inline %{
-  int wrap_pn_data_encode(pn_data_t *data, char *OUTPUT, size_t *OUTPUT_SIZE) {
-    ssize_t sz = pn_data_encode(data, OUTPUT, *OUTPUT_SIZE);
-    if (sz >= 0) {
-      *OUTPUT_SIZE = sz;
-    } else {
-      *OUTPUT_SIZE = 0;
-    }
-    return sz;
-  }
-%}
-%ignore pn_data_encode;
-
-%rename(pn_sasl_recv) wrap_pn_sasl_recv;
-%inline %{
-  int wrap_pn_sasl_recv(pn_sasl_t *sasl, char *OUTPUT, size_t *OUTPUT_SIZE) {
-    ssize_t sz = pn_sasl_recv(sasl, OUTPUT, *OUTPUT_SIZE);
-    if (sz >= 0) {
-      *OUTPUT_SIZE = sz;
-    } else {
-      *OUTPUT_SIZE = 0;
-    }
-    return sz;
-  }
-%}
-%ignore pn_sasl_recv;
-
-int pn_data_format(pn_data_t *data, char *OUTPUT, size_t *OUTPUT_SIZE);
-%ignore pn_data_format;
-
-bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE);
-%ignore pn_ssl_get_cipher_name;
-
-bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE);
-%ignore pn_ssl_get_protocol_name;
-
-int pn_ssl_get_peer_hostname(pn_ssl_t *ssl, char *OUTPUT, size_t *OUTPUT_SIZE);
-%ignore pn_ssl_get_peer_hostname;
-
-
-%include "proton/cproton.i"


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


[17/51] [abbrv] qpid-proton git commit: Update with merge of latest proton codebase and checked against latest emscripten incoming branch

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/systemtests/SimpleTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/SimpleTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/SimpleTest.java
index a334606..2a4df7e 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/SimpleTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/SimpleTest.java
@@ -20,10 +20,9 @@ package org.apache.qpid.proton.systemtests;
 
 import static org.junit.Assert.assertEquals;
 
-import org.apache.qpid.proton.ProtonFactoryLoader;
+import org.apache.qpid.proton.Proton;
 import org.apache.qpid.proton.engine.Connection;
 import org.apache.qpid.proton.engine.EndpointState;
-import org.apache.qpid.proton.engine.EngineFactory;
 import org.apache.qpid.proton.engine.Transport;
 import org.junit.Test;
 
@@ -33,14 +32,12 @@ public class SimpleTest
     @Test
     public void test()
     {
-        EngineFactory engineFactory = new ProtonFactoryLoader<EngineFactory>(EngineFactory.class).loadFactory();
-
-        Connection connection1 = engineFactory.createConnection();
-        Connection connection2 = engineFactory.createConnection();;
-        Transport transport1 = engineFactory.createTransport();
+        Connection connection1 = Proton.connection();
+        Connection connection2 = Proton.connection();;
+        Transport transport1 = Proton.transport();
         transport1.bind(connection1);
 
-        Transport transport2 = engineFactory.createTransport();
+        Transport transport2 = Proton.transport();
         transport2.bind(connection2);
 
         assertEquals(EndpointState.UNINITIALIZED, connection1.getLocalState());

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/ConnectionTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/ConnectionTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/ConnectionTest.java
index 57e0eb1..6bf5077 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/ConnectionTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/ConnectionTest.java
@@ -23,8 +23,6 @@ import static java.util.EnumSet.of;
 import static org.apache.qpid.proton.engine.EndpointState.ACTIVE;
 import static org.apache.qpid.proton.engine.EndpointState.CLOSED;
 import static org.apache.qpid.proton.engine.EndpointState.UNINITIALIZED;
-import static org.apache.qpid.proton.systemtests.engine.ProtonFactoryTestFixture.isProtonC;
-import static org.apache.qpid.proton.systemtests.engine.ProtonFactoryTestFixture.isProtonJ;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -34,6 +32,7 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.qpid.proton.Proton;
 import org.apache.qpid.proton.amqp.Symbol;
 import org.apache.qpid.proton.amqp.transport.Close;
 import org.apache.qpid.proton.amqp.transport.ErrorCondition;
@@ -41,7 +40,6 @@ import org.apache.qpid.proton.amqp.transport.Open;
 import org.apache.qpid.proton.engine.Connection;
 import org.apache.qpid.proton.engine.Endpoint;
 import org.apache.qpid.proton.engine.EndpointState;
-import org.apache.qpid.proton.engine.EngineFactory;
 import org.apache.qpid.proton.engine.Session;
 import org.apache.qpid.proton.engine.Transport;
 import org.apache.qpid.proton.engine.TransportException;
@@ -59,18 +57,13 @@ public class ConnectionTest
     private static final String SERVER_CONTAINER = "serverContainer";
     private static final String CLIENT_CONTAINER = "clientContainer";
 
-    private final ProtonFactoryTestFixture _protonFactoryTestFixture = new ProtonFactoryTestFixture();
-
-    private EngineFactory _clientFactory = _protonFactoryTestFixture.getFactory1();
-    private EngineFactory _serverFactory = _protonFactoryTestFixture.getFactory2();
-
-    private final Transport _clientTransport = _clientFactory.createTransport();
-    private final Transport _serverTransport = _serverFactory.createTransport();
+    private final Transport _clientTransport = Proton.transport();
+    private final Transport _serverTransport = Proton.transport();
 
     private final TransportPumper _pumper = new TransportPumper(_clientTransport, _serverTransport);
 
-    private final Connection _clientConnection = _clientFactory.createConnection();
-    private final Connection _serverConnection = _serverFactory.createConnection();
+    private final Connection _clientConnection = Proton.connection();
+    private final Connection _serverConnection = Proton.connection();
 
     private final AmqpFramer _framer = new AmqpFramer();
 
@@ -87,7 +80,7 @@ public class ConnectionTest
 
 
     /** Container id is a mandatory field so this should cause an error */
-    @Test(expected=TransportException.class)
+    @Test
     public void testReceiptOfOpenWithoutContainerId_causesTODO()
     {
         _pumper.pumpAll();
@@ -97,7 +90,7 @@ public class ConnectionTest
 
         int serverConsumed = _serverTransport.input(openFrameBuffer, 0, openFrameBuffer.length);
         assertEquals(openFrameBuffer.length, serverConsumed);
-        assumeTrue(isProtonJ(_serverFactory));
+        assertEquals(_serverTransport.capacity(), Transport.END_OF_STREAM);
     }
 
     /**
@@ -268,10 +261,7 @@ public class ConnectionTest
         _pumper.pumpOnceFromClientToServer();
 
         assertEnpointState(_clientConnection, CLOSED, UNINITIALIZED);
-        if (!isProtonC(_serverFactory))
-        {
-            assertEnpointState(_serverConnection, UNINITIALIZED, CLOSED);
-        }
+        assertEnpointState(_serverConnection, UNINITIALIZED, CLOSED);
     }
 
     /**
@@ -341,9 +331,6 @@ public class ConnectionTest
     @SuppressWarnings({ "rawtypes", "unchecked" })
     public void testCloseConnectionWithErrorCode_causesCloseFrameContainingErrorCodeToBeSent()
     {
-        // TODO Proton-c fails if no remote condition is set
-        assumeTrue(isProtonJ(_clientFactory) && isProtonJ(_serverFactory));
-
         bindAndOpenConnections();
 
         /*
@@ -411,8 +398,6 @@ public class ConnectionTest
         Close surprisingClose = new Close();
 
         byte[] buf = _framer.generateFrame(0, surprisingClose);
-        assumeTrue(isProtonJ(_serverFactory));
-        // TODO Proton-C: function pn_do_close causes a SEGV fault if you try and close an unopened connection
         _serverTransport.input(buf, 0, buf.length);
 
         // TODO server should indicate error

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/ProtonFactoryTestFixture.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/ProtonFactoryTestFixture.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/ProtonFactoryTestFixture.java
deleted file mode 100644
index e977d21..0000000
--- a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/ProtonFactoryTestFixture.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton.systemtests.engine;
-
-import static org.apache.qpid.proton.ProtonFactory.ImplementationType.PROTON_C;
-import static org.apache.qpid.proton.ProtonFactory.ImplementationType.PROTON_J;
-
-import org.apache.qpid.proton.ProtonFactoryLoader;
-import org.apache.qpid.proton.engine.EngineFactory;
-
-public class ProtonFactoryTestFixture
-{
-    private final EngineFactory _engineFactory = new ProtonFactoryLoader<EngineFactory>(EngineFactory.class).loadFactory();
-
-    public static boolean isProtonC(EngineFactory engineFactory)
-    {
-        return engineFactory.getImplementationType() == PROTON_C;
-    }
-
-    public static boolean isProtonJ(EngineFactory engineFactory)
-    {
-        return engineFactory.getImplementationType() == PROTON_J;
-    }
-
-    /**
-     * TODO support different implementations for factory1 and factory2
-     */
-    public EngineFactory getFactory1()
-    {
-        return _engineFactory;
-    }
-
-    public EngineFactory getFactory2()
-    {
-        return _engineFactory;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/TransportTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/TransportTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/TransportTest.java
index e603f9e..01852bb 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/TransportTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/TransportTest.java
@@ -22,7 +22,7 @@ package org.apache.qpid.proton.systemtests.engine;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 
-import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.Proton;
 import org.apache.qpid.proton.engine.Transport;
 import org.apache.qpid.proton.engine.TransportException;
 import org.junit.Ignore;
@@ -34,9 +34,7 @@ import org.junit.Test;
  */
 public class TransportTest
 {
-    private final ProtonFactoryTestFixture _protonFactoryTestFixture = new ProtonFactoryTestFixture();
-    private final EngineFactory _factory = _protonFactoryTestFixture.getFactory1();
-    private final Transport _transport = _factory.createTransport();
+    private final Transport _transport = Proton.transport();
 
     /**
      * Note that Proton does not yet give the application explicit control over protocol version negotiation

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/tests/java/org/apache/qpid/proton/InteropTest.java
----------------------------------------------------------------------
diff --git a/tests/java/org/apache/qpid/proton/InteropTest.java b/tests/java/org/apache/qpid/proton/InteropTest.java
index 49804de..c875092 100644
--- a/tests/java/org/apache/qpid/proton/InteropTest.java
+++ b/tests/java/org/apache/qpid/proton/InteropTest.java
@@ -19,13 +19,11 @@
 package org.apache.qpid.proton;
 
 import org.apache.qpid.proton.TestDecoder;
-import org.apache.qpid.proton.ProtonFactoryLoader;
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.DescribedType;
 import org.apache.qpid.proton.amqp.Symbol;
 import org.apache.qpid.proton.amqp.messaging.AmqpValue;
 import org.apache.qpid.proton.message.Message;
-import org.apache.qpid.proton.message.MessageFactory;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertArrayEquals;
@@ -69,8 +67,7 @@ public class InteropTest
     Message decodeMessage(String name) throws IOException
     {
         byte[] data = getBytes(name);
-        MessageFactory mf = new ProtonFactoryLoader<MessageFactory>(MessageFactory.class).loadFactory();
-        Message m = mf.createMessage();
+        Message m = Proton.message();
         m.decode(data, 0, data.length);
         return m;
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/tests/python/proton_tests/common.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/common.py b/tests/python/proton_tests/common.py
index d597c2f..05e01fd 100644
--- a/tests/python/proton_tests/common.py
+++ b/tests/python/proton_tests/common.py
@@ -21,7 +21,7 @@ from random import randint
 from threading import Thread
 from socket import socket, AF_INET, SOCK_STREAM
 from subprocess import Popen,PIPE,STDOUT
-import sys, os
+import sys, os, string
 from proton import Driver, Connection, Transport, SASL, Endpoint, Delivery, \
     SSLDomain, SSLUnavailable
 
@@ -46,42 +46,37 @@ def free_tcp_ports(count=1):
     s.close()
   return ports
 
+def pump_uni(src, dst, buffer_size=1024):
+  p = src.pending()
+  c = dst.capacity()
+
+  if c < 0:
+    if p < 0:
+      return False
+    else:
+      src.close_head()
+      return True
+
+  if p < 0:
+    dst.close_tail()
+  elif p == 0 or c == 0:
+    return False
+  else:
+    bytes = src.peek(min(c, buffer_size))
+    dst.push(bytes)
+    src.pop(len(bytes))
+
+  return True
 
 def pump(transport1, transport2, buffer_size=1024):
   """ Transfer all pending bytes between two Proton engines
-      by repeatedly calling input and output.
+      by repeatedly calling peek/pop and push.
       Asserts that each engine accepts some bytes every time
       (unless it's already closed).
   """
-
-  out1_leftover_by_t2 = ""
-  out2_leftover_by_t1 = ""
-  i = 0
-
-  while True:
-    out1 = out1_leftover_by_t2 + (transport1.output(buffer_size) or "")
-    out2 = out2_leftover_by_t1 + (transport2.output(buffer_size) or "")
-
-    if out1:
-      number_t2_consumed = transport2.input(out1)
-      if number_t2_consumed is None:
-        # special None return value means input is closed so discard the leftovers
-        out1_leftover_by_t2 = ""
-      else:
-        assert number_t2_consumed > 0, (number_t2_consumed, len(out1), out1[:100])
-        out1_leftover_by_t2 = out1[number_t2_consumed:]
-
-    if out2:
-      number_t1_consumed = transport1.input(out2)
-      if number_t1_consumed is None:
-        # special None return value means input is closed so discard the leftovers
-        out2_leftover_by_t1 = ""
-      else:
-        assert number_t1_consumed > 0, (number_t1_consumed, len(out1), out1[:100])
-        out2_leftover_by_t1 = out2[number_t1_consumed:]
-
-    if not out1 and not out2: break
-    i = i + 1
+  while (pump_uni(transport1, transport2, buffer_size) or
+         pump_uni(transport2, transport1, buffer_size)):
+    pass
 
 def isSSLPresent():
     """ True if a suitable SSL library is available.
@@ -335,6 +330,16 @@ class MessengerApp(object):
         self.password = None
         self._output = None
 
+    def findfile(self, filename, searchpath):
+        """Find filename in the searchpath
+            return absolute path to the file or None
+        """
+        paths = string.split(searchpath, os.pathsep)
+        for path in paths:
+            if os.path.exists(os.path.join(path, filename)):
+                return os.path.abspath(os.path.join(path, filename))
+        return None
+
     def start(self, verbose=False):
         """ Begin executing the test """
         cmd = self.cmdline()
@@ -343,8 +348,20 @@ class MessengerApp(object):
             print("COMMAND='%s'" % str(cmd))
         #print("ENV='%s'" % str(os.environ.copy()))
         try:
+            if os.name=="nt":
+                # Windows handles python launch by replacing script 'filename' with
+                # 'python abspath-to-filename' in cmdline arg list.
+                if cmd[0].endswith('.py'):
+                    foundfile = self.findfile(cmd[0], os.environ['PATH'])
+                    if foundfile is None:
+                        foundfile = self.findfile(cmd[0], os.environ['PYTHONPATH'])
+                        assert foundfile is not None, "Unable to locate file '%s' in PATH or PYTHONPATH" % cmd[0]
+                    del cmd[0:1]
+                    cmd.insert(0, foundfile)
+                    cmd.insert(0, sys.executable)
             self._process = Popen(cmd, stdout=PIPE, stderr=STDOUT, bufsize=4096)
         except OSError, e:
+            print("ERROR: '%s'" % e)
             assert False, "Unable to execute command '%s', is it in your PATH?" % cmd[0]
         self._ready()  # wait for it to initialize
 
@@ -514,7 +531,7 @@ class MessengerReceiver(MessengerApp):
     def _ready(self):
         """ wait for subscriptions to complete setup. """
         r = self._process.stdout.readline()
-        assert r == "READY\n", "Unexpected input while waiting for receiver to initialize: %s" % r
+        assert r == "READY" + os.linesep, "Unexpected input while waiting for receiver to initialize: %s" % r
 
 class MessengerSenderC(MessengerSender):
     def __init__(self):

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/tests/python/proton_tests/engine.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/engine.py b/tests/python/proton_tests/engine.py
index 243e5bc..44157e7 100644
--- a/tests/python/proton_tests/engine.py
+++ b/tests/python/proton_tests/engine.py
@@ -389,7 +389,7 @@ class LinkTest(Test):
   def teardown(self):
     self.cleanup()
     gc.collect()
-    assert not gc.garbage
+    assert not gc.garbage, gc.garbage
 
   def test_open_close(self):
     assert self.snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
@@ -1081,11 +1081,9 @@ class IdleTimeoutTest(Test):
     # now expire sndr
     clock = 1.499
     t_snd.tick(clock)
-    try:
-      self.pump()
-      assert False, "Expected connection timeout did not happen!"
-    except TransportException:
-      pass
+    self.pump()
+    assert self.c2.state & Endpoint.REMOTE_CLOSED
+    assert self.c2.remote_condition.name == "amqp:resource-limit-exceeded"
 
 class CreditTest(Test):
 
@@ -2069,51 +2067,66 @@ class DeliveryTest(Test):
   def testCustom(self):
     self.testDisposition(type=0x12345, value=CustomValue([1, 2, 3]))
 
-class EventTest(Test):
+class CollectorTest(Test):
 
-  def teardown(self):
-    self.cleanup()
+  def setup(self):
+    self.collector = Collector()
 
-  def list(self, collector):
+  def drain(self):
     result = []
     while True:
-      e = collector.peek()
+      e = self.collector.peek()
       if e:
         result.append(e)
-        collector.pop()
+        self.collector.pop()
       else:
         break
     return result
 
-  def expect(self, collector, *types):
-    events = self.list(collector)
-    assert types == tuple([e.type for e in events]), (types, events)
-    if len(events) == 1:
-      return events[0]
-    elif len(events) > 1:
-      return events
+  def expect(self, *types):
+    return self.expect_oneof(types)
+
+  def expect_oneof(self, *sequences):
+    events = self.drain()
+    types = tuple([e.type for e in events])
+
+    for alternative in sequences:
+      if types == alternative:
+        if len(events) == 1:
+          return events[0]
+        elif len(events) > 1:
+          return events
+        else:
+          return
+
+    assert False, "actual events %s did not match any of the expected sequences: %s" % (events, sequences)
+
+class EventTest(CollectorTest):
+
+  def teardown(self):
+    self.cleanup()
 
   def testEndpointEvents(self):
     c1, c2 = self.connection()
-    coll = Collector()
-    c1.collect(coll)
-    self.expect(coll)
+    c1.collect(self.collector)
+    self.expect(Event.CONNECTION_INIT)
     self.pump()
-    self.expect(coll)
+    self.expect()
     c2.open()
     self.pump()
-    self.expect(coll, Event.CONNECTION_REMOTE_STATE)
+    self.expect(Event.CONNECTION_REMOTE_OPEN)
     self.pump()
-    self.expect(coll)
+    self.expect()
 
     ssn = c2.session()
     snd = ssn.sender("sender")
     ssn.open()
     snd.open()
 
-    self.expect(coll)
+    self.expect()
     self.pump()
-    self.expect(coll, Event.SESSION_REMOTE_STATE, Event.LINK_REMOTE_STATE)
+    self.expect(Event.SESSION_INIT, Event.SESSION_REMOTE_OPEN,
+                Event.LINK_INIT, Event.LINK_REMOTE_OPEN)
 
     c1.open()
     ssn2 = c1.session()
@@ -2121,61 +2134,188 @@ class EventTest(Test):
     rcv = ssn2.receiver("receiver")
     rcv.open()
     self.pump()
-    self.expect(coll,
-                Event.CONNECTION_LOCAL_STATE,
-                Event.TRANSPORT,
-                Event.SESSION_LOCAL_STATE,
-                Event.TRANSPORT,
-                Event.LINK_LOCAL_STATE,
+    self.expect(Event.CONNECTION_OPEN, Event.TRANSPORT,
+                Event.SESSION_INIT, Event.SESSION_OPEN,
+                Event.TRANSPORT, Event.LINK_INIT, Event.LINK_OPEN,
                 Event.TRANSPORT)
 
+    rcv.close()
+    self.expect(Event.LINK_CLOSE, Event.TRANSPORT)
+    self.pump()
+    rcv.free()
+    del rcv
+    self.expect(Event.LINK_FINAL)
+    ssn2.free()
+    del ssn2
+    self.pump()
+    c1.free()
+    c1._transport.unbind()
+    self.expect(Event.SESSION_FINAL, Event.LINK_FINAL, Event.SESSION_FINAL,
+                Event.CONNECTION_FINAL)
+
+  def testConnectionINIT_FINAL(self):
+    c = Connection()
+    c.collect(self.collector)
+    self.expect(Event.CONNECTION_INIT)
+    c.free()
+    self.expect(Event.CONNECTION_FINAL)
+
+  def testSessionINIT_FINAL(self):
+    c = Connection()
+    c.collect(self.collector)
+    self.expect(Event.CONNECTION_INIT)
+    s = c.session()
+    self.expect(Event.SESSION_INIT)
+    s.free()
+    self.expect(Event.SESSION_FINAL)
+    c.free()
+    self.expect(Event.CONNECTION_FINAL)
+
+  def testLinkINIT_FINAL(self):
+    c = Connection()
+    c.collect(self.collector)
+    self.expect(Event.CONNECTION_INIT)
+    s = c.session()
+    self.expect(Event.SESSION_INIT)
+    r = s.receiver("asdf")
+    self.expect(Event.LINK_INIT)
+    r.free()
+    self.expect(Event.LINK_FINAL)
+    c.free()
+    self.expect(Event.SESSION_FINAL, Event.CONNECTION_FINAL)
+
   def testFlowEvents(self):
     snd, rcv = self.link("test-link")
-    coll = Collector()
-    snd.session.connection.collect(coll)
+    snd.session.connection.collect(self.collector)
     rcv.open()
     rcv.flow(10)
     self.pump()
-    self.expect(coll, Event.LINK_REMOTE_STATE, Event.LINK_FLOW)
+    self.expect(Event.CONNECTION_INIT, Event.SESSION_INIT,
+                Event.LINK_INIT, Event.LINK_REMOTE_OPEN, Event.LINK_FLOW)
     rcv.flow(10)
     self.pump()
-    self.expect(coll, Event.LINK_FLOW)
-    return snd, rcv, coll
+    self.expect(Event.LINK_FLOW)
+    return snd, rcv
 
   def testDeliveryEvents(self):
     snd, rcv = self.link("test-link")
-    coll = Collector()
-    rcv.session.connection.collect(coll)
+    rcv.session.connection.collect(self.collector)
     rcv.open()
     rcv.flow(10)
     self.pump()
-    self.expect(coll, Event.LINK_LOCAL_STATE, Event.TRANSPORT, Event.TRANSPORT)
+    self.expect(Event.CONNECTION_INIT, Event.SESSION_INIT,
+                Event.LINK_INIT, Event.LINK_OPEN, Event.TRANSPORT)
     snd.delivery("delivery")
     snd.send("Hello World!")
     snd.advance()
     self.pump()
-    self.expect(coll)
+    self.expect()
     snd.open()
     self.pump()
-    self.expect(coll, Event.LINK_REMOTE_STATE, Event.DELIVERY)
+    self.expect(Event.LINK_REMOTE_OPEN, Event.DELIVERY)
+    rcv.session.connection._transport.unbind()
+    rcv.session.connection.free()
+    self.expect(Event.TRANSPORT, Event.LINK_FINAL, Event.SESSION_FINAL,
+                Event.CONNECTION_FINAL)
 
   def testDeliveryEventsDisp(self):
-    snd, rcv, coll = self.testFlowEvents()
+    snd, rcv = self.testFlowEvents()
     snd.open()
     dlv = snd.delivery("delivery")
     snd.send("Hello World!")
     assert snd.advance()
-    self.expect(coll,
-                Event.LINK_LOCAL_STATE,
-                Event.TRANSPORT,
-                Event.TRANSPORT,
-                Event.TRANSPORT)
+    self.expect(Event.LINK_OPEN, Event.TRANSPORT)
     self.pump()
-    self.expect(coll)
+    self.expect(Event.LINK_FLOW)
     rdlv = rcv.current
     assert rdlv != None
     assert rdlv.tag == "delivery"
     rdlv.update(Delivery.ACCEPTED)
     self.pump()
-    event = self.expect(coll, Event.DELIVERY)
+    event = self.expect(Event.DELIVERY)
     assert event.delivery == dlv
+
+class PeerTest(CollectorTest):
+
+  def setup(self):
+    CollectorTest.setup(self)
+    self.connection = Connection()
+    self.connection.collect(self.collector)
+    self.transport = Transport()
+    self.transport.bind(self.connection)
+    self.peer = Connection()
+    self.peer_transport = Transport()
+    self.peer_transport.bind(self.peer)
+    self.peer_transport.trace(Transport.TRACE_OFF)
+
+  def pump(self):
+    pump(self.transport, self.peer_transport)
+
+class TeardownLeakTest(PeerTest):
+
+  def doLeak(self, local, remote):
+    self.connection.open()
+    self.expect(Event.CONNECTION_INIT, Event.CONNECTION_OPEN, Event.TRANSPORT)
+
+    ssn = self.connection.session()
+    ssn.open()
+    self.expect(Event.SESSION_INIT, Event.SESSION_OPEN, Event.TRANSPORT)
+
+    snd = ssn.sender("sender")
+    snd.open()
+    self.expect(Event.LINK_INIT, Event.LINK_OPEN, Event.TRANSPORT)
+
+
+    self.pump()
+
+    self.peer.open()
+    self.peer.session_head(0).open()
+    self.peer.link_head(0).open()
+
+    self.pump()
+    self.expect_oneof((Event.CONNECTION_REMOTE_OPEN, Event.SESSION_REMOTE_OPEN,
+                       Event.LINK_REMOTE_OPEN, Event.LINK_FLOW),
+                      (Event.CONNECTION_REMOTE_OPEN, Event.SESSION_REMOTE_OPEN,
+                       Event.LINK_REMOTE_OPEN))
+
+    if local:
+      snd.close() # ha!!
+      self.expect(Event.LINK_CLOSE, Event.TRANSPORT)
+    ssn.close()
+    self.expect(Event.SESSION_CLOSE, Event.TRANSPORT)
+    self.connection.close()
+    self.expect(Event.CONNECTION_CLOSE, Event.TRANSPORT)
+
+    if remote:
+      self.peer.link_head(0).close() # ha!!
+    self.peer.session_head(0).close()
+    self.peer.close()
+
+    self.pump()
+
+    if remote:
+      self.expect_oneof((Event.LINK_REMOTE_CLOSE, Event.SESSION_REMOTE_CLOSE,
+                         Event.CONNECTION_REMOTE_CLOSE),
+                        (Event.LINK_REMOTE_CLOSE, Event.LINK_FINAL,
+                         Event.SESSION_REMOTE_CLOSE,
+                         Event.CONNECTION_REMOTE_CLOSE))
+    else:
+      self.expect(Event.SESSION_REMOTE_CLOSE, Event.CONNECTION_REMOTE_CLOSE)
+
+    self.connection.free()
+    self.transport.unbind()
+
+    self.expect_oneof((Event.LINK_FINAL, Event.SESSION_FINAL, Event.CONNECTION_FINAL),
+                      (Event.SESSION_FINAL, Event.CONNECTION_FINAL))
+
+  def testLocalRemoteLeak(self):
+    self.doLeak(True, True)
+
+  def testLocalLeak(self):
+    self.doLeak(True, False)
+
+  def testRemoteLeak(self):
+    self.doLeak(False, True)
+
+  def testLeak(self):
+    self.doLeak(False, False)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/tests/python/proton_tests/messenger.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/messenger.py b/tests/python/proton_tests/messenger.py
index ba2ef1b..f3dcda4 100644
--- a/tests/python/proton_tests/messenger.py
+++ b/tests/python/proton_tests/messenger.py
@@ -124,10 +124,13 @@ class MessengerTest(Test):
       self.server.put(msg)
       self.server.settle()
 
-  def testSendReceive(self, size=None):
+  def testSendReceive(self, size=None, address_size=None):
     self.start()
     msg = Message()
-    msg.address="amqp://0.0.0.0:12345"
+    if address_size:
+      msg.address="amqp://0.0.0.0:12345/%s" % ("x"*address_size)
+    else:
+      msg.address="amqp://0.0.0.0:12345"
     msg.reply_to = "~"
     msg.subject="Hello World!"
     body = "First the world, then the galaxy!"
@@ -166,6 +169,9 @@ class MessengerTest(Test):
   def testSendReceive1M(self):
     self.testSendReceive(1024*1024)
 
+  def testSendReceiveLargeAddress(self):
+    self.testSendReceive(address_size=2048)
+
   # PROTON-285 - prevent continually failing test
   def xtestSendBogus(self):
     self.start()
@@ -689,26 +695,37 @@ class NBMessengerTest(common.Test):
 
   def setup(self):
     self.client = Messenger("client")
+    self.client2 = Messenger("client2")
     self.server = Messenger("server")
+    self.messengers = [self.client, self.client2, self.server]
     self.client.blocking = False
+    self.client2.blocking = False
     self.server.blocking = False
     self.server.start()
     self.client.start()
+    self.client2.start()
     self.address = "amqp://0.0.0.0:12345"
     self.server.subscribe("amqp://~0.0.0.0:12345")
 
+  def _pump(self, timeout, work_triggers_exit):
+    for msgr in self.messengers:
+      if msgr.work(timeout) and work_triggers_exit:
+        return True
+    return False
+
   def pump(self, timeout=0):
-    while self.client.work(0) or self.server.work(0): pass
-    self.client.work(timeout)
-    self.server.work(timeout)
-    while self.client.work(0) or self.server.work(0): pass
+    while self._pump(0, True): pass
+    self._pump(timeout, False)
+    while self._pump(0, True): pass
 
   def teardown(self):
     self.server.stop()
     self.client.stop()
+    self.client2.stop()
     self.pump()
     assert self.server.stopped
     assert self.client.stopped
+    assert self.client2.stopped
 
   def testSmoke(self, count=1):
     self.server.recv()
@@ -842,16 +859,10 @@ class NBMessengerTest(common.Test):
     assert self.server.receiving == 8, self.server.receiving
 
     # and none for this new client
-    client2 = Messenger("client2")
-    client2.blocking = False
-    client2.start()
     msg3 = Message()
     msg3.address = self.address + "/msg3"
-    client2.put(msg3)
-    while client2.work(0):
-        self.pump()
-    assert self.server.incoming == 1, self.server.incoming
-    assert self.server.receiving == 8, self.server.receiving
+    self.client2.put(msg3)
+    self.pump()
 
     # eventually, credit will rebalance and all links will
     # send a message
@@ -859,7 +870,6 @@ class NBMessengerTest(common.Test):
     while time() < deadline:
         sleep(.1)
         self.pump()
-        client2.work(0)
         if self.server.incoming == 3:
             break;
     assert self.server.incoming == 3, self.server.incoming
@@ -867,7 +877,7 @@ class NBMessengerTest(common.Test):
 
     # now tear down client two, this should cause its outstanding credit to be
     # made available to the other links
-    client2.stop()
+    self.client2.stop()
     self.pump()
 
     for i in range(4):
@@ -1017,3 +1027,59 @@ class SelectableMessengerTest(common.Test):
 
   def testSelectable4096(self):
     self.testSelectable(count=4096)
+
+
+class IdleTimeoutTest(common.Test):
+
+  def testIdleTimeout(self):
+    """
+    Verify that a Messenger connection is kept alive using empty idle frames
+    when a idle_timeout is advertised by the remote peer.
+    """
+    if "java" in sys.platform:
+      raise Skipped()
+    idle_timeout_secs = self.delay
+
+    try:
+      idle_server = common.TestServerDrain(idle_timeout=idle_timeout_secs)
+      idle_server.timeout = self.timeout
+      idle_server.start()
+
+      idle_client = Messenger("idle_client")
+      idle_client.timeout = self.timeout
+      idle_client.start()
+
+      idle_client.subscribe("amqp://%s:%s/foo" %
+                            (idle_server.host, idle_server.port))
+      idle_client.work(idle_timeout_secs/10)
+
+      # wait up to 3x the idle timeout and hence verify that everything stays
+      # connected during that time by virtue of no Exception being raised
+      duration = 3 * idle_timeout_secs
+      deadline = time() + duration
+      while time() <= deadline:
+        idle_client.work(idle_timeout_secs/10)
+        continue
+
+      # confirm link is still active
+      cxtr = idle_server.driver.head_connector()
+      assert not cxtr.closed, "Connector has unexpectedly been closed"
+      conn = cxtr.connection
+      assert conn.state == (Endpoint.LOCAL_ACTIVE
+                            | Endpoint.REMOTE_ACTIVE
+                            ), "Connection has unexpectedly terminated"
+      link = conn.link_head(0)
+      while link:
+        assert link.state != (Endpoint.REMOTE_CLOSED
+                              ), "Link unexpectedly closed"
+        link = link.next(0)
+
+    finally:
+      try:
+        idle_client.stop()
+      except:
+        pass
+      try:
+        idle_server.stop()
+      except:
+        pass

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/tests/python/proton_tests/sasl.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/sasl.py b/tests/python/proton_tests/sasl.py
index 9fb548a..5e353d5 100644
--- a/tests/python/proton_tests/sasl.py
+++ b/tests/python/proton_tests/sasl.py
@@ -45,16 +45,16 @@ class SaslTest(Test):
     self.s2.server()
     self.s2.done(SASL.OK)
 
-    out1 = self.t1.output(1024)
-    out2 = self.t2.output(1024)
+    out1 = self.t1.peek(1024)
+    self.t1.pop(len(out1))
+    out2 = self.t2.peek(1024)
+    self.t2.pop(len(out2))
 
-    n = self.t2.input(out1)
-    assert n == len(out1), (n, out1)
+    self.t2.push(out1)
 
     assert self.s1.outcome is None
 
-    n = self.t1.input(out2)
-    assert n == len(out2), (n, out2)
+    self.t1.push(out2)
 
     assert self.s2.outcome == SASL.OK
 
@@ -67,8 +67,9 @@ class SaslTest(Test):
     self.s2.done(SASL.OK)
 
     # send the server's OK to the client
-    out2 = self.t2.output(1024)
-    self.t1.input(out2)
+    out2 = self.t2.peek(1024)
+    self.t2.pop(len(out2))
+    self.t1.push(out2)
 
     # do some work to generate AMQP data
     c1 = Connection()
@@ -84,15 +85,17 @@ class SaslTest(Test):
     out1_sasl_and_amqp = ""
     t1_still_producing = True
     while t1_still_producing:
-      out1 = self.t1.output(1024)
+      out1 = self.t1.peek(1024)
+      self.t1.pop(len(out1))
       out1_sasl_and_amqp += out1
       t1_still_producing = out1
 
     t2_still_consuming = True
     while t2_still_consuming:
-      num_consumed = self.t2.input(out1_sasl_and_amqp)
-      out1_sasl_and_amqp = out1_sasl_and_amqp[num_consumed:]
-      t2_still_consuming = num_consumed > 0 and len(out1_sasl_and_amqp) > 0
+      num = min(self.t2.capacity(), len(out1_sasl_and_amqp))
+      self.t2.push(out1_sasl_and_amqp[:num])
+      out1_sasl_and_amqp = out1_sasl_and_amqp[num:]
+      t2_still_consuming = num > 0 and len(out1_sasl_and_amqp) > 0
 
     assert len(out1_sasl_and_amqp) == 0, (len(out1_sasl_and_amqp), out1_sasl_and_amqp)
 
@@ -129,9 +132,9 @@ class SaslTest(Test):
     self.s1.mechanisms("ANONYMOUS")
     self.s1.client()
 
-    out1 = self.t1.output(1024)
-    n = self.t2.input(out1)
-    assert n == len(out1)
+    out1 = self.t1.peek(1024)
+    self.t1.pop(len(out1))
+    self.t2.push(out1)
 
     self.s2.mechanisms("ANONYMOUS")
     self.s2.server()
@@ -140,11 +143,11 @@ class SaslTest(Test):
     c2.open()
     self.t2.bind(c2)
 
-    out2 = self.t2.output(1024)
-    n = self.t1.input(out2)
-    assert n == len(out2)
+    out2 = self.t2.peek(1024)
+    self.t2.pop(len(out2))
+    self.t1.push(out2)
 
-    out1 = self.t1.output(1024)
+    out1 = self.t1.peek(1024)
     assert len(out1) > 0
 
   def testFracturedSASL(self):
@@ -156,17 +159,23 @@ class SaslTest(Test):
 
     # self.t1.trace(Transport.TRACE_FRM)
 
-    out = self.t1.output(1024)
-    self.t1.input("AMQP\x03\x01\x00\x00")
-    out = self.t1.output(1024)
-    self.t1.input("\x00\x00\x00")
-    out = self.t1.output(1024)
-    self.t1.input("A\x02\x01\x00\x00\x00S@\xc04\x01\xe01\x06\xa3\x06GSSAPI\x05PLAIN\x0aDIGEST-MD5\x08AMQPLAIN\x08CRAM-MD5\x04NTLM")
-    out = self.t1.output(1024)
-    self.t1.input("\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00")
-    out = self.t1.output(1024)
+    out = self.t1.peek(1024)
+    self.t1.pop(len(out))
+    self.t1.push("AMQP\x03\x01\x00\x00")
+    out = self.t1.peek(1024)
+    self.t1.pop(len(out))
+    self.t1.push("\x00\x00\x00")
+    out = self.t1.peek(1024)
+    self.t1.pop(len(out))
+    self.t1.push("A\x02\x01\x00\x00\x00S@\xc04\x01\xe01\x06\xa3\x06GSSAPI\x05PLAIN\x0aDIGEST-MD5\x08AMQPLAIN\x08CRAM-MD5\x04NTLM")
+    out = self.t1.peek(1024)
+    self.t1.pop(len(out))
+    self.t1.push("\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00")
+    out = self.t1.peek(1024)
+    self.t1.pop(len(out))
     while out:
-      out = self.t1.output(1024)
+      out = self.t1.peek(1024)
+      self.t1.pop(len(out))
 
     assert self.s1.outcome == SASL.OK, self.s1.outcome
 
@@ -182,3 +191,13 @@ class SaslTest(Test):
       sasl1 = transport.sasl()
       sasl2 = SASL(transport)
       assert sasl1 is sasl2
+
+  def testSaslSkipped(self):
+    """Verify that the server (with SASL) correctly handles a client without SASL"""
+    self.t1 = Transport()
+    self.s2.mechanisms("ANONYMOUS")
+    self.s2.server()
+    self.s2.allow_skip(True)
+    self.pump()
+    assert self.s2.outcome == SASL.SKIPPED
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/tests/python/proton_tests/ssl.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl.py b/tests/python/proton_tests/ssl.py
index ed2e25d..f5fae3f 100644
--- a/tests/python/proton_tests/ssl.py
+++ b/tests/python/proton_tests/ssl.py
@@ -73,6 +73,8 @@ class SslTest(common.Test):
         client.connection.open()
         server.connection.open()
         self._pump(client, server)
+        if client.transport.closed:
+            return
         assert client.ssl.protocol_name() is not None
         client.connection.close()
         server.connection.close()
@@ -214,11 +216,11 @@ class SslTest(common.Test):
 
         client.connection.open()
         server.connection.open()
-        try:
-            self._pump( client, server )
-            assert False, "Server failed to reject bad certificate."
-        except TransportException, e:
-            pass
+        self._pump( client, server )
+        assert client.transport.closed
+        assert server.transport.closed
+        assert client.connection.state & Endpoint.REMOTE_UNINIT
+        assert server.connection.state & Endpoint.REMOTE_UNINIT
 
     def test_client_authentication_fail_no_cert(self):
         """ Ensure that the server will fail a client that does not provide a
@@ -239,11 +241,11 @@ class SslTest(common.Test):
 
         client.connection.open()
         server.connection.open()
-        try:
-            self._pump( client, server )
-            assert False, "Server failed to reject bad certificate."
-        except TransportException, e:
-            pass
+        self._pump( client, server )
+        assert client.transport.closed
+        assert server.transport.closed
+        assert client.connection.state & Endpoint.REMOTE_UNINIT
+        assert server.connection.state & Endpoint.REMOTE_UNINIT
 
     def test_client_server_authentication(self):
         """ Require both client and server to mutually identify themselves.
@@ -314,11 +316,11 @@ class SslTest(common.Test):
 
         client.connection.open()
         server.connection.open()
-        try:
-            self._pump( client, server )
-            assert False, "Client failed to reject bad certificate."
-        except TransportException, e:
-            pass
+        self._pump( client, server )
+        assert client.transport.closed
+        assert server.transport.closed
+        assert client.connection.state & Endpoint.REMOTE_UNINIT
+        assert server.connection.state & Endpoint.REMOTE_UNINIT
 
         del server
         del client
@@ -409,11 +411,11 @@ class SslTest(common.Test):
 
         client.connection.open()
         server.connection.open()
-        try:
-            self._pump( client, server )
-            assert False, "Server did not reject client as expected."
-        except TransportException:
-            pass
+        self._pump( client, server )
+        assert client.transport.closed
+        assert server.transport.closed
+        assert client.connection.state & Endpoint.REMOTE_UNINIT
+        assert server.connection.state & Endpoint.REMOTE_UNINIT
 
     def test_session_resume(self):
         """ Test resume of client session.
@@ -563,11 +565,11 @@ class SslTest(common.Test):
         client = SslTest.SslTestConnection( self.client_domain )
 
         client.ssl.peer_hostname = "A1.Good.Server.domain.comX"
-        try:
-            self._do_handshake( client, server )
-            assert False, "Expected connection to fail due to hostname mismatch"
-        except TransportException:
-            pass
+        self._do_handshake( client, server )
+        assert client.transport.closed
+        assert server.transport.closed
+        assert client.connection.state & Endpoint.REMOTE_UNINIT
+        assert server.connection.state & Endpoint.REMOTE_UNINIT
         del server
         del client
         self.teardown()
@@ -659,11 +661,11 @@ class SslTest(common.Test):
         client = SslTest.SslTestConnection( self.client_domain )
 
         client.ssl.peer_hostname = "FOO.PREfi.domain.com"
-        try:
-            self._do_handshake( client, server )
-            assert False, "Expected connection to fail due to hostname mismatch"
-        except TransportException:
-            pass
+        self._do_handshake( client, server )
+        assert client.transport.closed
+        assert server.transport.closed
+        assert client.connection.state & Endpoint.REMOTE_UNINIT
+        assert server.connection.state & Endpoint.REMOTE_UNINIT
         del server
         del client
         self.teardown()
@@ -680,11 +682,11 @@ class SslTest(common.Test):
         client = SslTest.SslTestConnection( self.client_domain )
 
         client.ssl.peer_hostname = "PREfix.domain.COM"
-        try:
-            self._do_handshake( client, server )
-            assert False, "Expected connection to fail due to hostname mismatch"
-        except TransportException:
-            pass
+        self._do_handshake( client, server )
+        assert client.transport.closed
+        assert server.transport.closed
+        assert client.connection.state & Endpoint.REMOTE_UNINIT
+        assert server.connection.state & Endpoint.REMOTE_UNINIT
         self.teardown()
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/tests/python/proton_tests/transport.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/transport.py b/tests/python/proton_tests/transport.py
index f2b964a..e5bbe24 100644
--- a/tests/python/proton_tests/transport.py
+++ b/tests/python/proton_tests/transport.py
@@ -27,37 +27,53 @@ class TransportTest(Test):
 
   def setup(self):
     self.transport = Transport()
+    self.peer = Transport()
+    self.conn = Connection()
+    self.peer.bind(self.conn)
 
   def teardown(self):
     self.transport = None
+    self.peer = None
+    self.conn = None
+
+  def drain(self):
+    while True:
+      p = self.transport.pending()
+      if p < 0:
+        return
+      elif p > 0:
+        bytes = self.transport.peek(p)
+        self.peer.push(bytes)
+        self.transport.pop(len(bytes))
+      else:
+        assert False
+
+  def assert_error(self, name):
+    assert self.conn.remote_container is None, self.conn.remote_container
+    self.drain()
+    # verify that we received an open frame
+    assert self.conn.remote_container is not None, self.conn.remote_container
+    # verify that we received a close frame
+    assert self.conn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_CLOSED, self.conn.state
+    # verify that a framing error was reported
+    assert self.conn.remote_condition.name == name, self.conn.remote_condition
 
   def testEOS(self):
-    try:
-      n = self.transport.input("")
-      assert False, n
-    except TransportException:
-      pass
+    self.transport.push("") # should be a noop
+    self.transport.close_tail() # should result in framing error
+    self.assert_error(u'amqp:connection:framing-error')
 
   def testPartial(self):
-    n = self.transport.input("AMQ")
-    assert n == 3, n
-    try:
-      n = self.transport.input("")
-      assert False, n
-    except TransportException:
-      pass
+    self.transport.push("AMQ") # partial header
+    self.transport.close_tail() # should result in framing error
+    self.assert_error(u'amqp:connection:framing-error')
 
   def testGarbage(self, garbage="GARBAGE_"):
-    try:
-      n = self.transport.input(garbage)
-      assert False, n
-    except TransportException, e:
-      assert "AMQP header mismatch" in str(e), str(e)
-    try:
-      n = self.transport.input("")
-      assert False, n
-    except TransportException, e:
-      pass
+    self.transport.push(garbage)
+    self.assert_error(u'amqp:connection:framing-error')
+    assert self.transport.pending() < 0
+    self.transport.close_tail()
+    assert self.transport.pending() < 0
 
   def testSmallGarbage(self):
     self.testGarbage("XXX")
@@ -66,16 +82,12 @@ class TransportTest(Test):
     self.testGarbage("GARBAGE_XXX")
 
   def testHeader(self):
-    n = self.transport.input("AMQP\x00\x01\x00\x00")
-    assert n == 8, n
-    try:
-      n = self.transport.input("")
-      assert False, n
-    except TransportException, e:
-      assert "connection aborted" in str(e)
+    self.transport.push("AMQP\x00\x01\x00\x00")
+    self.transport.close_tail()
+    self.assert_error(u'amqp:connection:framing-error')
 
-  def testOutput(self):
-    out = self.transport.output(1024)
+  def testPeek(self):
+    out = self.transport.peek(1024)
     assert out is not None
 
   def testBindAfterOpen(self):
@@ -87,16 +99,10 @@ class TransportTest(Test):
     conn.hostname = "test-hostname"
     trn = Transport()
     trn.bind(conn)
-    out = trn.output(1024)
+    out = trn.peek(1024)
     assert "test-container" in out, repr(out)
     assert "test-hostname" in out, repr(out)
-    n = self.transport.input(out)
-    assert n > 0, n
-    out = out[n:]
-
-    if out:
-      n = self.transport.input(out)
-      assert n == 0
+    self.transport.push(out)
 
     c = Connection()
     assert c.remote_container == None
@@ -105,10 +111,6 @@ class TransportTest(Test):
     self.transport.bind(c)
     assert c.remote_container == "test-container"
     assert c.remote_hostname == "test-hostname"
-    if out:
-      assert c.session_head(0) == None
-      n = self.transport.input(out)
-      assert n == len(out), (n, out)
     assert c.session_head(0) != None
 
   def testCloseHead(self):
@@ -130,3 +132,32 @@ class TransportTest(Test):
       assert "aborted" in str(e), str(e)
     n = self.transport.capacity()
     assert n < 0, n
+
+  def testUnpairedPop(self):
+    conn = Connection()
+    self.transport.bind(conn)
+
+    conn.hostname = "hostname"
+    conn.open()
+
+    dat1 = self.transport.peek(1024)
+
+    ssn = conn.session()
+    ssn.open()
+
+    dat2 = self.transport.peek(1024)
+
+    assert dat2[:len(dat1)] == dat1
+
+    snd = ssn.sender("sender")
+    snd.open()
+
+    self.transport.pop(len(dat1))
+    self.transport.pop(len(dat2) - len(dat1))
+    dat3 = self.transport.peek(1024)
+    self.transport.pop(len(dat3))
+    assert self.transport.peek(1024) == ""
+
+    self.peer.push(dat1)
+    self.peer.push(dat2[len(dat1):])
+    self.peer.push(dat3)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/tests/tools/apps/c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/tests/tools/apps/c/CMakeLists.txt b/tests/tools/apps/c/CMakeLists.txt
index 8f5fdab..deafe24 100644
--- a/tests/tools/apps/c/CMakeLists.txt
+++ b/tests/tools/apps/c/CMakeLists.txt
@@ -19,6 +19,8 @@
 
 include(CheckIncludeFiles)
 
+include_directories(${CMAKE_SOURCE_DIR}/examples/include)
+
 CHECK_INCLUDE_FILES("inttypes.h" INTTYPES_AVAILABLE)
 if (INTTYPES_AVAILABLE)
   list(APPEND PLATFORM_DEFINITIONS "USE_INTTYPES")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/tests/tools/apps/c/msgr-common.h
----------------------------------------------------------------------
diff --git a/tests/tools/apps/c/msgr-common.h b/tests/tools/apps/c/msgr-common.h
index 0066ea4..d3f483a 100644
--- a/tests/tools/apps/c/msgr-common.h
+++ b/tests/tools/apps/c/msgr-common.h
@@ -28,9 +28,13 @@
 #endif
 
 #ifdef _MSC_VER
+#if !defined(PRIu64)
 #define PRIu64 "I64u"
+#endif
+#if !defined(SCNu64)
 #define SCNu64 "I64u"
 #endif
+#endif
 
 /* If still not defined, best guess */
 #if !defined(SCNu64)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/version.txt
----------------------------------------------------------------------
diff --git a/version.txt b/version.txt
index eb49d7c..aec258d 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-0.7
+0.8


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


[16/51] [abbrv] qpid-proton git commit: The qpid-config port is largely complete except for xml binding support, it also needs a bit of tidying up. Added a simple soak test to send and receive messages from a broker ad-infinitum and a simple html send me

Posted by rh...@apache.org.
The qpid-config port is largely complete except for xml binding support, it also needs a bit of tidying up. Added a simple soak test to send and receive messages from a broker ad-infinitum and a simple html send message example

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1621865 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/4a78327f
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/4a78327f
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/4a78327f

Branch: refs/heads/master
Commit: 4a78327f5a6f2369ef15ede360f4bc86d288f7c4
Parents: c3efc08
Author: fadams <fa...@unknown>
Authored: Mon Sep 1 18:32:04 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Mon Sep 1 18:32:04 2014 +0000

----------------------------------------------------------------------
 examples/messenger/javascript/qpid-config.js | 227 +++++--
 examples/messenger/javascript/send.html      | 110 ++++
 examples/messenger/javascript/send.js        |   6 +-
 proton-c/bindings/javascript/CMakeLists.txt  |  43 +-
 proton-c/bindings/javascript/binding.js      |  39 +-
 proton-c/bindings/javascript/my-library.js   | 755 ----------------------
 tests/javascript/soak.js                     |  99 +++
 7 files changed, 448 insertions(+), 831 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4a78327f/examples/messenger/javascript/qpid-config.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/qpid-config.js b/examples/messenger/javascript/qpid-config.js
index 466f8b6..eb0951f 100755
--- a/examples/messenger/javascript/qpid-config.js
+++ b/examples/messenger/javascript/qpid-config.js
@@ -41,7 +41,11 @@ if (typeof exports !== "undefined" && exports !== null) {
     proton = require("qpid-proton");
 }
 
-var address = 'amqp://0.0.0.0:5673/qmf.default.direct';
+var addr = 'guest:guest@localhost:5673';
+//var addr = 'localhost:5673';
+var address = 'amqp://' + addr + '/qmf.default.direct';
+console.log(address);
+
 var replyTo = '';
 var subscription;
 var subscribed = false;
@@ -52,13 +56,14 @@ var messenger = new proton.Messenger();
 /**
  * The correlator object is a mechanism used to correlate requests with their
  * aynchronous responses. It might possible be better to make use of Promises
- * to implement part of this behaviour but a mechanism would still be meeded to
+ * to implement part of this behaviour but a mechanism would still be needed to
  * correlate a request with its response callback in order to wrap things up in
  * a Promise, so much of the behaviour of this object would still be required.
  * In addition it seemed to make sense to make this QMF2 implementation fairly
  * free of dependencies and using Promises would require external libraries.
- * Instead the correlator implements Promise-like semantics, you might call it
+ * Instead the correlator implements "Promise-like" semantics, you might call it
  * a broken Promise :-)
+ * <p>
  * in particular the request method behaves a *bit* like Promise.all() though it
  * is mostly fake and takes an array of functions that call the add() method
  * which is really the method used to associate response objects by correlationID.
@@ -155,6 +160,7 @@ var getObjects = function(packageName, className) {
     message.setReplyTo(replyTo);
     message.setCorrelationID(className);
     message.properties = {
+        "routing-key": "broker", // Added for Java Broker
         "x-amqp-0-10.app-id": "qmf2",
         "method": "request",
         "qmf.opcode": "_query_request",
@@ -178,6 +184,7 @@ var invokeMethod = function(object, method, arguments) {
     message.setReplyTo(replyTo);
     message.setCorrelationID(correlationID);
     message.properties = {
+        "routing-key": "broker", // Added for Java Broker
         "x-amqp-0-10.app-id": "qmf2",
         "method": "request",
         "qmf.opcode": "_method_request",
@@ -197,7 +204,7 @@ messenger.on('work', pumpData);
 messenger.setOutgoingWindow(1024);
 messenger.start();
 
-subscription = messenger.subscribe('amqp://0.0.0.0:5673/#');
+subscription = messenger.subscribe('amqp://' + addr + '/#');
 messenger.recv(); // Receive as many messages as messenger can buffer.
 
 
@@ -358,11 +365,24 @@ var _options =
 '                        output\n';
 
 var REPLICATE_LEVELS = {"none" : true, "configuration": true, "all": true};
-var DEFAULT_PROPERTIES = {"exchange":["name", "type", "durable"], "queue":["name", "durable", "autoDelete"]};
+var DEFAULT_PROPERTIES = {"exchange": {"name": true, "type": true, "durable": true},
+                             "queue": {"name": true, "durable": true, "autoDelete": true}};
+
+var getValue = function(r) {
+    var value = null;
+    if (r.length === 2) {
+        value = r[1];
+        if (!isNaN(value)) {
+            value = parseInt(value);
+        }
+    }
+
+    return value;
+};
 
 var config = {
     _recursive      : false,
-    _host           : 'localhost',
+    _host           : 'localhost:5673', // Note 5673 not 5672 as we use WebSocket transport.
     _connTimeout    : 10,
     _ignoreDefault  : false,
     _altern_ex      : null,
@@ -389,17 +409,13 @@ var config = {
     _extra_arguments: [],
     _start_replica  : null,
     _returnCode     : 0,
-    _list_properties: [],
+    _list_properties: null,
 
     getOptions: function() {
         var options = {};
         for (var a = 0; a < this._extra_arguments.length; a++) {
             var r = this._extra_arguments[a].split('=');
-            var value = null;
-            if (r.length === 2) {
-                value = r[1]; 
-            }
-            options[r[0]] = value;
+            options[r[0]] = getValue(r);
         }
         return options;
     }
@@ -471,7 +487,7 @@ var idMap = function(list) {
     return map;
 };
 
-var renderArguments = function(obj, list) {
+var renderObject = function(obj, list) {
     if (!obj) {
         return '';
     }
@@ -493,7 +509,7 @@ var renderArguments = function(obj, list) {
     }
 
     if (addComma) {
-        return ' {' + string + '}';
+        return '{' + string + '}';
     } else {
         if (list) {
             return string;
@@ -645,7 +661,7 @@ var exchangeListRecurse = function(filter) {
                         var queue = queues[oid(bind.queueRef)];
                         var queueName = queue ? queue._values.name : "<unknown>";
                         console.log("    bind [" + bind.bindingKey + "] => " + queueName + 
-                                    renderArguments(bind.arguments));
+                                    " " + renderObject(bind.arguments));
                     }   
                 }
             }
@@ -743,7 +759,7 @@ var queueList = function(filter) {
                 if (args[SHARED_MSG_GROUP] === 1) {
                     string += ' --shared-groups';
                 }
-                string += renderArguments(args, true);
+                string += ' ' + renderObject(args, true);
                 console.log(string);
             }
         }
@@ -785,7 +801,7 @@ var queueListRecurse = function(filter) {
                         }
 
                         console.log("    bind [" + bind.bindingKey + "] => " + exchangeName + 
-                                    renderArguments(bind.arguments));
+                                    " " + renderObject(bind.arguments));
                     }   
                 }
             }
@@ -824,10 +840,10 @@ console.log("Method result");
     if (response._arguments) {
         //console.log(response._arguments);
     } if (response._values) {
-        console.error("Exception from Agent: " + renderArguments(response._values));
+        console.error("Exception from Agent: " + renderObject(response._values));
     }
     // Mostly we want to stop the Messenger Event loop and exit when a QMF method
-    // call returns, but sometimes we don't.
+    // returns, but sometimes we don't, the dontStop flag prevents this behaviour.
     if (!dontStop) {
         messenger.stop();
     }
@@ -846,11 +862,7 @@ var addExchange = function(args) {
 
     for (var a = 0; a < config._extra_arguments.length; a++) {
         var r = config._extra_arguments[a].split('=');
-        var value = null;
-        if (r.length === 2) {
-            value = r[1]; 
-        }
-        declArgs[r[0]] = value;
+        declArgs[r[0]] = getValue(r);
     }
 
     if (config._msgSequence) {
@@ -918,11 +930,7 @@ var addQueue = function(args) {
 
     for (var a = 0; a < config._extra_arguments.length; a++) {
         var r = config._extra_arguments[a].split('=');
-        var value = null;
-        if (r.length === 2) {
-            value = r[1]; 
-        }
-        declArgs[r[0]] = value;
+        declArgs[r[0]] = getValue(r);
     }
 
     if (config._durable) {
@@ -1201,21 +1209,141 @@ console.log(args);
  * The following methods are "generic" create and delete methods to for arbitrary
  * Management Objects e.g. Incoming, Outgoing, Domain, Topic, QueuePolicy,
  * TopicPolicy etc. use --argument k1=v1 --argument k2=v2 --argument k3=v3 to
- * pass arbitrary arguments as key/value pairs to the Object being created/deleted.
+ * pass arbitrary arguments as key/value pairs to the Object being created/deleted,
+ * for example to add a topic object that uses the fanout exchange:
+ * ./qpid-config.js add topic fanout --argument exchange=amq.fanout \
+ * --argument qpid.max_size=1000000 --argument qpid.policy_type=ring
  */
 
 var createObject = function(type, name, args) {
-console.log("createObject");
-console.log(type);
-console.log(name);
-console.log(args);
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker')
+    ).then(function(objects) {
+        var broker = objects.broker[0];
+        correlator.request(
+            // Create an object of the specified type.
+            invokeMethod(broker, 'create', {
+                "type":       type,
+                "name":       name,
+                "properties": args,
+                "strict":     true})
+        ).then(handleMethodResponse);
+    });
+};
 
+var deleteObject = function(type, name, args) {
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker')
+    ).then(function(objects) {
+        var broker = objects.broker[0];
+        correlator.request(
+            // Create an object of the specified type and name.
+            invokeMethod(broker, 'delete', {
+                "type":    type,
+                "name":    name,
+                "options": args})
+        ).then(handleMethodResponse);
+    });
 };
 
-var deleteObject = function(args) {
-console.log("deleteObject");
-console.log(args);
+/**
+ * This is a "generic" mechanism for listing arbitrary Management Objects.
+ */
+var listObjects = function(type) {
+    correlator.request(
+        getObjects('org.apache.qpid.broker', type)
+    ).then(function(objects) {
+        // The correlator passes an object containing responses for all of the
+        // supplied requests so we index it by the supplied type to get our response.
+        objects = objects[type];
+
+        // Collect available attributes, stringify the values and compute the max
+        // length of the value of each attribute so that we can later create a table.
+        var attributes = {};
+        var lengths = {};
+        for (var i = 0; i < objects.length; i++) {
+            var object = objects[i];
+            object = object._values;
+            for (var prop in object) {
+                if (typeof object[prop] === 'object') { // Stringify Object properties.
+                    // Check if property is an ObjectID (reference property),
+                    // if so replace with the "name" part of the OID.
+                    if (object[prop]['_object_name']) {
+                        var parts = object[prop]['_object_name'].split(':');
+                        object[prop] = parts[parts.length - 1];
+                    } else {
+                        // Stringify general Object properties.
+                        object[prop] = renderObject(object[prop]);
+                    }
+                } else {
+                    object[prop] = object[prop].toString(); // Stringify other property types.
+                }
+
+                if (!lengths[prop] || object[prop].length > lengths[prop]) { // Compute lengths.
+                    lengths[prop] = object[prop].length > prop.length ? object[prop].length : prop.length;
+                }
+
+                if (!config._list_properties || config._list_properties[prop]) { // Do we want this property?
+                    attributes[prop] = true;
+                }
+            }
+        }
 
+        if (!config._list_properties && DEFAULT_PROPERTIES[type]) {
+            attributes = DEFAULT_PROPERTIES[type];
+        }
+
+        // Using the information we've previously prepared now render a table
+        // showing the required property values.
+        var desired = [];
+        var header = ''; // Table header showing the property names.
+        if (attributes['name']) {
+            desired.push('name');
+            delete attributes['name'];
+            header += 'name' + Array(lengths['name'] + 2 - 4).join(' ');
+        }
+
+        for (var prop in attributes) {
+            desired.push(prop);
+            header += prop + Array(lengths[prop] + 2 - prop.length).join(' ');
+        }
+
+        console.log("Objects of type '" + type + "'");
+        console.log(header);
+        console.log(Array(header.length).join('='));
+        for (var i = 0; i < objects.length; i++) {
+            var object = objects[i];
+            object = object._values;
+            var string = '';
+            for (var j = 0; j < desired.length; j++) {
+                var key = desired[j];
+                string += object[key] + Array(lengths[key] + 2 - object[key].length).join(' ');
+            }
+
+            console.log(string);
+        }
+
+        messenger.stop();
+    });
+};
+
+var reloadAcl = function() {
+    correlator.request(
+        getObjects('org.apache.qpid.acl', 'acl')
+    ).then(function(objects) {
+        if (objects.acl.length > 0) {
+            var acl = objects.acl[0];
+            correlator.request(
+                // Create an object of the specified type.
+                invokeMethod(acl, 'reloadACLFile', {})
+            ).then(handleMethodResponse);
+        } else {
+            console.log("Failed: No ACL Loaded in Broker");
+            messenger.stop();
+        }
+    });
 };
 
 
@@ -1263,10 +1391,9 @@ if (args.length > 0) {
                 if (config._connTimeout === 0) {
                     config._connTimeout = null;
                 }
-            } else if (arg === '-b' || arg === '--broker' || arg === '-b' || arg === '--broker-addr') {
-                config._host = val;
-                if (config._host == null) {
-                    config._host = 'localhost:5672';
+            } else if (arg === '-b' || arg === '--broker' || arg === '-a' || arg === '--broker-addr') {
+                if (val != null) {
+                    config._host = val;
                 }
             } else if (arg === '--alternate-exchange') {
                 config._altern_ex = val;
@@ -1306,7 +1433,10 @@ if (args.length > 0) {
             } else if (arg === '--f' || arg === '--file') { // TODO Won't work in node.js
                 config._file = val;
             } else if (arg === '--show-property') {
-                config._list_properties = val;
+                if (config._list_properties === null) {
+                    config._list_properties = {};
+                }
+                config._list_properties[val] = true;
             }
         } else {
             params.push(arg);
@@ -1316,9 +1446,6 @@ if (args.length > 0) {
 
 config._extra_arguments = extra_arguments;
 
-console.log("params");
-console.log(params);
-
 // The command only *actually* gets called when the QMF connection has actually
 // been established so we wrap up the function we want to get called in a lambda.
 var command = function() {overview();};
@@ -1365,11 +1492,19 @@ if (params.length > 0) {
         command = function() {bind(Array.prototype.slice.apply(params, [1]));};
     } else if (cmd === 'unbind') {
         command = function() {unbind(Array.prototype.slice.apply(params, [1]));};
+    } else if (cmd === 'reload-acl') {
+        command = function() {reloadAcl();};
+    } else if (cmd === 'list' && params.length > 1) {
+        command = function() {listObjects(modifier);};
+    } else {
+        usage();
     }
 }
 
+//console.log(config._host);
+
+
 var onSubscription = function() {
     command();
 };
 
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4a78327f/examples/messenger/javascript/send.html
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html
new file mode 100644
index 0000000..b6aaef2
--- /dev/null
+++ b/examples/messenger/javascript/send.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html> <!-- HTML5 doctype -->
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+    http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<html>
+
+<head>
+	<title>Simple Proton Messenger Send Example</title>
+	<meta http-equiv="content-type" content="text/html;charset=utf-8" />
+
+<!--
+  Import JavaScript Messenger Binding proton.js. Note that this simple example pulls
+  it from the node_modules/qpid-proton/lib which is created by the build process
+  so that the node.js based examples "just work", in a real Web App you would need
+  to copy the proton.js to your own server. 
+  In actual fact the CMake build actually builds proton.js into the directory:
+  <build>/proton-c/bindings/javascript
+  where <build> is the build directory created to run cmake from.
+-->
+<script type="text/javascript" src="../../../node_modules/qpid-proton/lib/proton.js"></script>
+
+<script type="text/javascript">
+
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+
+var sendMessage = function() {
+    var address = document.getElementById("address").value;
+    var subject = document.getElementById("subject").value;
+    var body = document.getElementById("body").value;
+
+console.log("sendMessage");
+console.log("address = " + address);
+console.log("subject = " + subject);
+console.log("body = " + body);
+
+    message.setAddress(address);
+    message.setSubject(subject);
+    message.body = body;
+
+    messenger.put(message);
+};
+
+messenger.on('error', function(error) {console.log("Received error " + error);});
+messenger.start();
+
+</script>
+
+<style>
+body
+{
+	font: 13px/1.5 Helvetica, Arial, 'Liberation Sans', FreeSans, sans-serif;
+    overflow-x: hidden; /* Hide horizontal scrollbar */
+    background: #dddddd;
+}
+
+label
+{
+    display: block;
+	font-size: 17px;
+}
+
+input, textarea
+{
+	font-size: 13px;
+    margin-bottom: 10px;
+}
+</style>
+
+</head>
+
+<body>
+<div>
+    <label for="address">Address:</label>
+    <input type="text" id="address" size="40"
+           placeholder="amqp://user:password@host:port"
+           name="address" value="amqp://guest:guest@0.0.0.0" />
+</div>
+<div>    
+    <label for="subject">Subject:</label>
+    <input type="text" id="subject" size="40"
+           name="subject" value="Browser Message" />
+</div>
+<div>
+    <label for="body">Message:</label>
+    <textarea id="body" name="body" rows="4" cols="40">Hello From Browser!</textarea>
+</div>
+<div>
+    <input type="button" value="send" onclick="sendMessage()"/>
+</div>
+</body>
+
+</html>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4a78327f/examples/messenger/javascript/send.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.js b/examples/messenger/javascript/send.js
index 77a605c..5a93333 100644
--- a/examples/messenger/javascript/send.js
+++ b/examples/messenger/javascript/send.js
@@ -33,6 +33,10 @@ var running = true;
 var message = new proton.Message();
 var messenger = new proton.Messenger();
 
+// Because this is an asynchronous send we can't simply call messenger.put(message)
+// then exit. The following callback function (and messenger.setOutgoingWindow())
+// gives us a means to wait until the consumer has received the message before
+// exiting. The recv.js example explicitly accepts messages it receives.
 var pumpData = function() {
     var status = messenger.status(tracker);
     if (status != proton.Status.PENDING) {
@@ -81,7 +85,7 @@ console.log("Content: " + msgtext);
 
 messenger.on('error', function(error) {console.log(error);});
 messenger.on('work', pumpData);
-messenger.setOutgoingWindow(1024);
+messenger.setOutgoingWindow(1024); // So we can track status of send message.
 messenger.start();
 
 message.setAddress(address);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4a78327f/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index 4e4dc0f..ae24407 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -19,7 +19,7 @@
  
 # This file allows cross-compiling of proton to JavaScript using emscripten
 # (https://github.com/kripken/emscripten). As it is really a cross-compilation
-# (as opposed to a binding a la swig) the approach is rather different and
+# (as opposed to a binding like with swig) the approach is rather different and
 # somewhat replicates the main build in the proton-c/CMakeLists.txt using quite
 # a bit of "copy and paste reuse".
 # TODO refactor this file (and proton-c/CMakeLists.txt) to keep the main
@@ -27,8 +27,8 @@
 
 message(STATUS "Found emscripten, using that to build JavaScript binding")
 
-# Find and install node.js packages that we might need. We can assume that
-# node.js is installed because Emscripten has a dependency on it.
+# Find and install the node.js packages that we might need. We can assume that
+# node.js itself is installed because Emscripten has a dependency on it.
 find_package(NodePackages)
 
 # Describe the target OS we are building to - Emscripten mimics the Linux platform.
@@ -43,6 +43,14 @@ set(CMAKE_C_COMPILER "${EMCC}")
 include(CMakeForceCompiler)
 CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang)
 
+if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
+    message(STATUS "DEBUG JavaScript build")
+else()
+    message(STATUS "RELEASE JavaScript build")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
+    set(EMSCRIPTEN_LINK_OPTIMISATIONS "-O2 --closure 1")
+endif()
+
 # From this point we should be using emscripten compilation tools.
 message(STATUS "emscripten compilation environment:")
 message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
@@ -193,21 +201,9 @@ set_target_properties(
   RUNTIME_OUTPUT_DIRECTORY examples
   DEPENDS ws
 
-  # This build shows socket messages - useful for debugging.
-  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -s SOCKET_DEBUG=1"
-
-  # Optimised build - takes somewhat longer to build.
-  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1"
-
-  # This build shows up emscripten warnings when building - should be able to remove it.
-  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -s VERBOSE=1 -O2"
-
-  # This build is optimised but not minified
-  LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2"
+  LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -${EMSCRIPTEN_LINK_OPTIMISATIONS}"
   )
 
-
-
 # Build the main JavaScript library called proton.js
 add_executable(proton.js binding.c)
 target_link_libraries(proton.js qpid-proton-bitcode)
@@ -217,16 +213,13 @@ set_target_properties(
   PROPERTIES
   COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
 
-  # This build is optimised and minified. The --memory-init-file 0 stops emscripten
-  # emitting a separate memory initialization file, if this was enabled it makes
-  # packaging harder as applications would expect proton.js.mem to be served too.
-  # It's even more fiddly with node.js packages. This behaviour might be reinstated
-  # if the packaging mechanism improves.
-
-  # --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js
-  #LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --memory-init-file 0 --pre-js
+  # The --memory-init-file 0 stops emscripten emitting a separate memory
+  # initialization file, if this was enabled it makes packaging harder as
+  # applications would expect proton.js.mem to be served too. It's even more
+  # fiddly with node.js packages. This behaviour might be reinstated if the
+  # packaging mechanism improves.
 
-  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '
 _pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_messa
 ge_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array',
  '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_deci
 mal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messen
 ger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_rep
 ly_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data
 _put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_
 pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
   )
 
 # This command packages up the compiled proton.js into a node.js package called

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4a78327f/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index eceda54..4caafa6 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -477,6 +477,14 @@ _Messenger_['setIncomingWindow'] = function(window) {
  */
 _Messenger_['start'] = function() {
     this._check(_pn_messenger_start(this._messenger));
+
+    // This call ensures that the emscripten network callback functions are set
+    // up even if a client hasn't explicity added a work function via a call to
+    // messenger.on('work', <work function>);
+    // Doing this means that pn_messenger_work() will still get called when any
+    // WebSocket events occur, which keeps things more reliable when things like
+    // reconnections occur.
+    Module.EventDispatch.addListener(this);
 };
 
 /**
@@ -541,8 +549,7 @@ _Messenger_['subscribe'] = function(source) {
  * Places the content contained in the message onto the outgoing queue
  * of the Messenger. This method will never block, however it will send any
  * unblocked Messages in the outgoing queue immediately and leave any blocked
- * Messages remaining in the outgoing queue. The send call may be used to
- * block until the outgoing queue is empty. The outgoing property may be
+ * Messages remaining in the outgoing queue. The outgoing property may be
  * used to check the depth of the outgoing queue.
  * <p>
  * When the content in a given Message object is copied to the outgoing
@@ -554,13 +561,23 @@ _Messenger_['subscribe'] = function(source) {
  * @method put
  * @memberof! proton.Messenger#
  * @param {proton.Message} message a Message to send.
+ * @param {boolean} flush if this is set true or is undefined then messages are
+ *        flushed (this is the default). If explicitly set to false then messages
+ *        may not be sent immediately and might require an explicit call to work().
+ *        This may be used to "batch up" messages and *may* be more efficient.
  * @returns {proton.Data.Long} a tracker.
  */
-_Messenger_['put'] = function(message) {
+_Messenger_['put'] = function(message, flush) {
+    flush = flush === false ? false : true;
     message._preEncode();
     this._checkErrors = true;
     this._check(_pn_messenger_put(this._messenger, message._message));
 
+    // If flush is set invoke pn_messenger_work.
+    if (flush) {
+        _pn_messenger_work(this._messenger, 0);
+    }
+
     // Getting the tracker is a little tricky as it is a 64 bit number. The way
     // emscripten handles this is to return the low 32 bits directly and pass
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
@@ -578,6 +595,12 @@ _Messenger_['put'] = function(message) {
  * @returns {proton.Status} one of None, PENDING, REJECTED, or ACCEPTED.
  */
 _Messenger_['status'] = function(tracker) {
+    if (tracker == null) {
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+    }
+
     return _pn_messenger_status(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits());
 };
 
@@ -589,6 +612,12 @@ _Messenger_['status'] = function(tracker) {
  * @returns {boolean} true if delivery is still buffered.
  */
 _Messenger_['isBuffered'] = function(tracker) {
+    if (tracker == null) {
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+    }
+
     return (_pn_messenger_buffered(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits()) > 0);
 };
 
@@ -982,7 +1011,9 @@ Module.EventDispatch = new function() { // Note the use of new to create a Singl
             };
         }
 
-        _messengers[name].callbacks.push(callback);
+        if (callback) {
+            _messengers[name].callbacks.push(callback);
+        }
     };
 
     /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4a78327f/proton-c/bindings/javascript/my-library.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/my-library.js b/proton-c/bindings/javascript/my-library.js
deleted file mode 100644
index af89ef4..0000000
--- a/proton-c/bindings/javascript/my-library.js
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-
-mergeInto(LibraryManager.library, {
-// Add to main emscripten library.js
-
-
-// Hacks below
-// -----------------------------------------------------------------------------------------------------------------
-
-  $SOCKFS__postset: '__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });',
-  $SOCKFS__deps: ['$FS'],
-  $SOCKFS: {
-    mount: function(mount) {
-      // If Module['websocket'] has already been defined (e.g. for configuring
-      // subprotocol/url) use that, if not initialise it to a new object.
-      Module['websocket'] = (Module['websocket'] && 
-                             ('object' === typeof Module['websocket'])) ? Module['websocket'] : {};
-
-      // Add Event registration mechanism to the exported websocket configuration
-      // object so we can register network callbacks from native JavaScript too.
-      Module['websocket']._callbacks = {};
-      Module['websocket'].on = function(event, callback) {
-	    if ('function' === typeof callback) {
-		  this._callbacks[event] = callback;
-        }
-	    return this;
-      };
-
-      Module['websocket'].emit = function(event, param) {
-	    if ('function' === typeof this._callbacks[event]) {
-		  this._callbacks[event].call(this, param);
-        }
-      };
-
-      // Register default null callbacks for each Event
-      Module['websocket'].on("error", function(error) {
-console.log("Websocket error " + error);
-	  });
-
-      Module['websocket'].on("open", function(fd) {
-console.log("Websocket open fd = " + fd);
-	  });
-
-      Module['websocket'].on("connection", function(fd) {
-console.log("Websocket connection fd = " + fd);
-	  });
-
-      Module['websocket'].on("message", function(fd) {
-console.log("Websocket message fd = " + fd);
-	  });
-
-      Module['websocket'].on("close", function(fd) {
-console.log("Websocket close fd = " + fd);
-	  });
-
-      return FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
-    },
-    createSocket: function(family, type, protocol) {
-      var streaming = type == {{{ cDefine('SOCK_STREAM') }}};
-      if (protocol) {
-        assert(streaming == (protocol == {{{ cDefine('IPPROTO_TCP') }}})); // if SOCK_STREAM, must be tcp
-      }
-
-      // create our internal socket structure
-      var sock = {
-        family: family,
-        type: type,
-        protocol: protocol,
-        server: null,
-        peers: {},
-        pending: [],
-        recv_queue: [],
-#if SOCKET_WEBRTC
-#else
-        sock_ops: SOCKFS.websocket_sock_ops
-#endif
-      };
-
-      // create the filesystem node to store the socket structure
-      var name = SOCKFS.nextname();
-      var node = FS.createNode(SOCKFS.root, name, {{{ cDefine('S_IFSOCK') }}}, 0);
-      node.sock = sock;
-
-      // and the wrapping stream that enables library functions such
-      // as read and write to indirectly interact with the socket
-      var stream = FS.createStream({
-        path: name,
-        node: node,
-        flags: FS.modeStringToFlags('r+'),
-        seekable: false,
-        stream_ops: SOCKFS.stream_ops
-      });
-
-      // map the new stream to the socket structure (sockets have a 1:1
-      // relationship with a stream)
-      sock.stream = stream;
-
-      return sock;
-    },
-    getSocket: function(fd) {
-      var stream = FS.getStream(fd);
-      if (!stream || !FS.isSocket(stream.node.mode)) {
-        return null;
-      }
-      return stream.node.sock;
-    },
-    // node and stream ops are backend agnostic
-    stream_ops: {
-      poll: function(stream) {
-        var sock = stream.node.sock;
-        return sock.sock_ops.poll(sock);
-      },
-      ioctl: function(stream, request, varargs) {
-console.log('stream_ops.ioctl');
-        var sock = stream.node.sock;
-        return sock.sock_ops.ioctl(sock, request, varargs);
-      },
-      read: function(stream, buffer, offset, length, position /* ignored */) {
-        var sock = stream.node.sock;
-        var msg = sock.sock_ops.recvmsg(sock, length);
-        if (!msg) {
-          // socket is closed
-          return 0;
-        }
-#if USE_TYPED_ARRAYS == 2
-        buffer.set(msg.buffer, offset);
-#else
-        for (var i = 0; i < size; i++) {
-          buffer[offset + i] = msg.buffer[i];
-        }
-#endif
-        return msg.buffer.length;
-      },
-      write: function(stream, buffer, offset, length, position /* ignored */) {
-        var sock = stream.node.sock;
-        return sock.sock_ops.sendmsg(sock, buffer, offset, length);
-      },
-      close: function(stream) {
-console.log('stream_ops.close');
-        var sock = stream.node.sock;
-        sock.sock_ops.close(sock);
-      }
-    },
-    nextname: function() {
-      if (!SOCKFS.nextname.current) {
-        SOCKFS.nextname.current = 0;
-      }
-      return 'socket[' + (SOCKFS.nextname.current++) + ']';
-    },
-    // backend-specific stream ops
-    websocket_sock_ops: {
-      //
-      // peers are a small wrapper around a WebSocket to help in
-      // emulating dgram sockets
-      //
-      // these functions aren't actually sock_ops members, but we're
-      // abusing the namespace to organize them
-      //
-      createPeer: function(sock, addr, port) {
-        var ws;
-
-        if (typeof addr === 'object') {
-          ws = addr;
-          addr = null;
-          port = null;
-        }
-
-        if (ws) {
-          // for sockets that've already connected (e.g. we're the server)
-          // we can inspect the _socket property for the address
-          if (ws._socket) {
-            addr = ws._socket.remoteAddress;
-            port = ws._socket.remotePort;
-          }
-          // if we're just now initializing a connection to the remote,
-          // inspect the url property
-          else {
-            var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
-            if (!result) {
-              throw new Error('WebSocket URL must be in the format ws(s)://address:port');
-            }
-            addr = result[1];
-            port = parseInt(result[2], 10);
-          }
-        } else {
-          // Create the actual websocket object and connect.
-          try {
-            // runtimeConfig gets set to true if WebSocket runtime configuration is available.
-            var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
-
-            // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
-            // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
-            var url = '{{{ WEBSOCKET_URL }}}'.replace('#', '//');
-
-            if (runtimeConfig) {
-              if ('string' === typeof Module['websocket']['url']) {
-                url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
-              }
-            }
-
-            if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
-              url = url + addr + ':' + port;
-            }
-
-            // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
-            var subProtocols = '{{{ WEBSOCKET_SUBPROTOCOL }}}'; // The default value is 'binary'
-
-            if (runtimeConfig) {
-              if ('string' === typeof Module['websocket']['subprotocol']) {
-                subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
-              }
-            }
-
-            // The regex trims the string (removes spaces at the beginning and end, then splits the string by
-            // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
-            subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
-
-            // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
-            var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
-
-#if SOCKET_DEBUG
-            Module.print('connect: ' + url + ', ' + subProtocols.toString());
-#endif
-            // If node we use the ws library.
-            var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
-            ws = new WebSocket(url, opts);
-            ws.binaryType = 'arraybuffer';
-          } catch (e) {
-console.log('e: ' + e);
-            throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
-          }
-        }
-
-#if SOCKET_DEBUG
-        Module.print('websocket adding peer: ' + addr + ':' + port);
-#endif
-
-        var peer = {
-          addr: addr,
-          port: port,
-          socket: ws,
-          dgram_send_queue: []
-        };
-
-        SOCKFS.websocket_sock_ops.addPeer(sock, peer);
-        SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
-
-        // if this is a bound dgram socket, send the port number first to allow
-        // us to override the ephemeral port reported to us by remotePort on the
-        // remote end.
-        if (sock.type === {{{ cDefine('SOCK_DGRAM') }}} && typeof sock.sport !== 'undefined') {
-#if SOCKET_DEBUG
-          Module.print('websocket queuing port message (port ' + sock.sport + ')');
-#endif
-          peer.dgram_send_queue.push(new Uint8Array([
-              255, 255, 255, 255,
-              'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
-              ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
-          ]));
-        }
-
-        return peer;
-      },
-      getPeer: function(sock, addr, port) {
-        return sock.peers[addr + ':' + port];
-      },
-      addPeer: function(sock, peer) {
-        sock.peers[peer.addr + ':' + peer.port] = peer;
-      },
-      removePeer: function(sock, peer) {
-        delete sock.peers[peer.addr + ':' + peer.port];
-      },
-      handlePeerEvents: function(sock, peer) {
-        var first = true;
-
-        var handleOpen = function () {
-#if SOCKET_DEBUG
-          Module.print('websocket handle open');
-#endif
-          try {
-            var queued = peer.dgram_send_queue.shift();
-            while (queued) {
-#if SOCKET_DEBUG
-              Module.print('websocket sending queued data (' + queued.byteLength + ' bytes): ' + [Array.prototype.slice.call(new Uint8Array(queued))]);
-#endif
-              peer.socket.send(queued);
-              queued = peer.dgram_send_queue.shift();
-            }
-          } catch (e) {
-            // not much we can do here in the way of proper error handling as we've already
-            // lied and said this data was sent. shut it down.
-            peer.socket.close();
-          }
-
-
-
-          if (Module['networkCallback']) {
-console.log("handleOpen triggering networkCallback");
-
-            Module['networkCallback']();
-          }
-
-          Module['websocket'].emit('open', 10);
-
-        };
-
-        function handleMessage(data) {
-          assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
-          data = new Uint8Array(data);  // make a typed array view on the array buffer
-
-#if SOCKET_DEBUG
-          //Module.print('websocket handle message (' + data.byteLength + ' bytes): ' + [Array.prototype.slice.call(data)]);
-          //Module.print('websocket handle message (' + data.byteLength + ' bytes)');
-#endif
-
-          // if this is the port message, override the peer's port with it
-          var wasfirst = first;
-          first = false;
-          if (wasfirst &&
-              data.length === 10 &&
-              data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
-              data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
-            // update the peer's port and it's key in the peer map
-            var newport = ((data[8] << 8) | data[9]);
-            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
-            peer.port = newport;
-            SOCKFS.websocket_sock_ops.addPeer(sock, peer);
-            return;
-          }
-
-          sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
-
-
-
-          if (Module['networkCallback']) {
-console.log("handleMessage triggering networkCallback");
-
-            Module['networkCallback']();
-          }
-
-          Module['websocket'].emit('message', 10);
-
-
-        };
-
-        if (ENVIRONMENT_IS_NODE) {
-          peer.socket.on('open', handleOpen);
-          peer.socket.on('message', function(data, flags) {
-            if (!flags.binary) {
-              return;
-            }
-            handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
-          });
-          peer.socket.on('close', function() {
-            Module['websocket'].emit('close', 10);
-          });
-          peer.socket.on('error', function(error) {
-            Module['websocket'].emit('error', error);
-            // don't throw
-          });
-        } else {
-          peer.socket.onopen = handleOpen;
-          peer.socket.onclose = function() {
-            Module['websocket'].emit('close', 10);
-          };
-          peer.socket.onmessage = function peer_socket_onmessage(event) {
-            handleMessage(event.data);
-          };
-          peer.socket.onerror = function(error) {
-            Module['websocket'].emit('error', error);
-          };
-        }
-      },
-
-      //
-      // actual sock ops
-      //
-      poll: function(sock) {
-        if (sock.type === {{{ cDefine('SOCK_STREAM') }}} && sock.server) {
-          // listen sockets should only say they're available for reading
-          // if there are pending clients.
-          return sock.pending.length ? ({{{ cDefine('POLLRDNORM') }}} | {{{ cDefine('POLLIN') }}}) : 0;
-        }
-
-        var mask = 0;
-        var dest = sock.type === {{{ cDefine('SOCK_STREAM') }}} ?  // we only care about the socket state for connection-based sockets
-          SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
-          null;
-
-        if (sock.recv_queue.length ||
-            !dest ||  // connection-less sockets are always ready to read
-            (dest && dest.socket.readyState === dest.socket.CLOSING) ||
-            (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
-          mask |= ({{{ cDefine('POLLRDNORM') }}} | {{{ cDefine('POLLIN') }}});
-        }
-
-        if (!dest ||  // connection-less sockets are always ready to write
-            (dest && dest.socket.readyState === dest.socket.OPEN)) {
-          mask |= {{{ cDefine('POLLOUT') }}};
-        }
-
-        if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
-            (dest && dest.socket.readyState === dest.socket.CLOSED)) {
-          mask |= {{{ cDefine('POLLHUP') }}};
-        }
-        return mask;
-      },
-      ioctl: function(sock, request, arg) {
-console.log('ioctl');
-        switch (request) {
-          case {{{ cDefine('FIONREAD') }}}:
-            var bytes = 0;
-            if (sock.recv_queue.length) {
-              bytes = sock.recv_queue[0].data.length;
-            }
-            {{{ makeSetValue('arg', '0', 'bytes', 'i32') }}};
-            return 0;
-          default:
-            return ERRNO_CODES.EINVAL;
-        }
-      },
-      close: function(sock) {
-console.log('close');
-        // if we've spawned a listen server, close it
-        if (sock.server) {
-          try {
-            sock.server.close();
-          } catch (e) {
-          }
-          sock.server = null;
-        }
-        // close any peer connections
-        var peers = Object.keys(sock.peers);
-        for (var i = 0; i < peers.length; i++) {
-          var peer = sock.peers[peers[i]];
-          try {
-            peer.socket.close();
-          } catch (e) {
-          }
-          SOCKFS.websocket_sock_ops.removePeer(sock, peer);
-        }
-        return 0;
-      },
-      bind: function(sock, addr, port) {
-        if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
-          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
-        }
-        sock.saddr = addr;
-        sock.sport = port || _mkport();
-        // in order to emulate dgram sockets, we need to launch a listen server when
-        // binding on a connection-less socket
-        // note: this is only required on the server side
-        if (sock.type === {{{ cDefine('SOCK_DGRAM') }}}) {
-          // close the existing server if it exists
-          if (sock.server) {
-            sock.server.close();
-            sock.server = null;
-          }
-          // swallow error operation not supported error that occurs when binding in the
-          // browser where this isn't supported
-          try {
-            sock.sock_ops.listen(sock, 0);
-          } catch (e) {
-            if (!(e instanceof FS.ErrnoError)) throw e;
-            if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
-          }
-        }
-      },
-      connect: function(sock, addr, port) {
-        if (sock.server) {
-          throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
-        }
-
-        // TODO autobind
-        // if (!sock.addr && sock.type == {{{ cDefine('SOCK_DGRAM') }}}) {
-        // }
-
-        // early out if we're already connected / in the middle of connecting
-        if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
-          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
-          if (dest) {
-            if (dest.socket.readyState === dest.socket.CONNECTING) {
-              throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
-            } else {
-              throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
-            }
-          }
-        }
-
-        // add the socket to our peer list and set our
-        // destination address / port to match
-        var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
-        sock.daddr = peer.addr;
-        sock.dport = peer.port;
-
-        // always "fail" in non-blocking mode
-        throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
-      },
-      listen: function(sock, backlog) {
-        if (!ENVIRONMENT_IS_NODE) {
-          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
-        }
-        if (sock.server) {
-           throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
-        }
-
-        var WebSocketServer = require('ws').Server;
-        var host = sock.saddr;
-#if SOCKET_DEBUG
-        console.log('listen: ' + host + ':' + sock.sport);
-#endif
-        sock.server = new WebSocketServer({
-          host: host,
-          port: sock.sport
-          // TODO support backlog
-        });
-
-        sock.server.on('connection', function(ws) {
-#if SOCKET_DEBUG
-          console.log('received connection from: ' + ws._socket.remoteAddress + ':' + ws._socket.remotePort);
-#endif
-          if (sock.type === {{{ cDefine('SOCK_STREAM') }}}) {
-            var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
-
-            // create a peer on the new socket
-            var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
-            newsock.daddr = peer.addr;
-            newsock.dport = peer.port;
-
-            // push to queue for accept to pick up
-            sock.pending.push(newsock);
-          } else {
-            // create a peer on the listen socket so calling sendto
-            // with the listen socket and an address will resolve
-            // to the correct client
-            SOCKFS.websocket_sock_ops.createPeer(sock, ws);
-          }
-
-          if (Module['networkCallback']) {
-console.log("On connection triggering networkCallback");
-
-            Module['networkCallback']();
-          }
-
-          Module['websocket'].emit('connection', 10);
-
-
-        });
-        sock.server.on('closed', function() {
-console.log('sock.server closed');
-          Module['websocket'].emit('close', 10);
-          sock.server = null;
-        });
-        sock.server.on('error', function(error) {
-console.log('sock.server error');
-          Module['websocket'].emit('error', error);
-          // don't throw
-        });
-      },
-      accept: function(listensock) {
-        if (!listensock.server) {
-          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
-        }
-
-        var newsock = listensock.pending.shift();
-        newsock.stream.flags = listensock.stream.flags;
-        return newsock;
-      },
-      getname: function(sock, peer) {
-console.log('getname');
-        var addr, port;
-        if (peer) {
-          if (sock.daddr === undefined || sock.dport === undefined) {
-            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
-          }
-          addr = sock.daddr;
-          port = sock.dport;
-        } else {
-          // TODO saddr and sport will be set for bind()'d UDP sockets, but what
-          // should we be returning for TCP sockets that've been connect()'d?
-          addr = sock.saddr || 0;
-          port = sock.sport || 0;
-        }
-        return { addr: addr, port: port };
-      },
-      sendmsg: function(sock, buffer, offset, length, addr, port) {
-        if (sock.type === {{{ cDefine('SOCK_DGRAM') }}}) {
-          // connection-less sockets will honor the message address,
-          // and otherwise fall back to the bound destination address
-          if (addr === undefined || port === undefined) {
-            addr = sock.daddr;
-            port = sock.dport;
-          }
-          // if there was no address to fall back to, error out
-          if (addr === undefined || port === undefined) {
-            throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
-          }
-        } else {
-          // connection-based sockets will only use the bound
-          addr = sock.daddr;
-          port = sock.dport;
-        }
-
-        // find the peer for the destination address
-        var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
-
-        // early out if not connected with a connection-based socket
-        if (sock.type === {{{ cDefine('SOCK_STREAM') }}}) {
-          if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
-            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
-          } else if (dest.socket.readyState === dest.socket.CONNECTING) {
-            throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
-          }
-        }
-
-        // create a copy of the incoming data to send, as the WebSocket API
-        // doesn't work entirely with an ArrayBufferView, it'll just send
-        // the entire underlying buffer
-        var data;
-        if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
-          data = buffer.slice(offset, offset + length);
-        } else {  // ArrayBufferView
-          data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
-        }
-
-        // if we're emulating a connection-less dgram socket and don't have
-        // a cached connection, queue the buffer to send upon connect and
-        // lie, saying the data was sent now.
-        if (sock.type === {{{ cDefine('SOCK_DGRAM') }}}) {
-          if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
-            // if we're not connected, open a new connection
-            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
-              dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
-            }
-#if SOCKET_DEBUG
-            Module.print('websocket queuing (' + length + ' bytes): ' + [Array.prototype.slice.call(new Uint8Array(data))]);
-#endif
-            dest.dgram_send_queue.push(data);
-            return length;
-          }
-        }
-
-        try {
-#if SOCKET_DEBUG
-          Module.print('websocket send (' + length + ' bytes): ' + [Array.prototype.slice.call(new Uint8Array(data))]);
-#endif
-
-          // send the actual data
-          dest.socket.send(data);
-
-          return length;
-        } catch (e) {
-          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
-        }
-      },
-      recvmsg: function(sock, length) {
-        // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
-        if (sock.type === {{{ cDefine('SOCK_STREAM') }}} && sock.server) {
-          // tcp servers should not be recv()'ing on the listen socket
-          throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
-        }
-
-        var queued = sock.recv_queue.shift();
-        if (!queued) {
-          if (sock.type === {{{ cDefine('SOCK_STREAM') }}}) {
-            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
-
-            if (!dest) {
-              // if we have a destination address but are not connected, error out
-              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
-            }
-            else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
-              // return null if the socket has closed
-              return null;
-            }
-            else {
-              // else, our socket is in a valid state but truly has nothing available
-              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
-            }
-          } else {
-            throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
-          }
-        }
-
-        // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
-        // requeued TCP data it'll be an ArrayBufferView
-        var queuedLength = queued.data.byteLength || queued.data.length;
-        var queuedOffset = queued.data.byteOffset || 0;
-        var queuedBuffer = queued.data.buffer || queued.data;
-        var bytesRead = Math.min(length, queuedLength);
-        var res = {
-          buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
-          addr: queued.addr,
-          port: queued.port
-        };
-
-#if SOCKET_DEBUG
-        Module.print('websocket read (' + bytesRead + ' bytes): ' + [Array.prototype.slice.call(res.buffer)]);
-#endif
-
-        // push back any unread data for TCP connections
-        if (sock.type === {{{ cDefine('SOCK_STREAM') }}} && bytesRead < queuedLength) {
-          var bytesRemaining = queuedLength - bytesRead;
-#if SOCKET_DEBUG
-          Module.print('websocket read: put back ' + bytesRemaining + ' bytes');
-#endif
-          queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
-          sock.recv_queue.unshift(queued);
-        }
-
-        return res;
-      }
-    }
-  },
-
-  emscripten_set_network_callback: function(func) {
-
-    function _func() {
-      try {
-        Runtime.dynCall('v', func);
-      } catch (e) {
-        if (e instanceof ExitStatus) {
-          return;
-        } else {
-          if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
-          throw e;
-        }
-      }
-    };
-
-    Module['noExitRuntime'] = true;
-    Module['networkCallback'] = _func;
-  }
-
-});

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4a78327f/tests/javascript/soak.js
----------------------------------------------------------------------
diff --git a/tests/javascript/soak.js b/tests/javascript/soak.js
new file mode 100755
index 0000000..c561989
--- /dev/null
+++ b/tests/javascript/soak.js
@@ -0,0 +1,99 @@
+#!/usr/bin/env node
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("qpid-proton");
+}
+
+var addr = 'guest:guest@localhost:5673';
+//var addr = 'localhost:5673';
+var address = 'amqp://' + addr;
+console.log(address);
+
+var subscriptionQueue = '';
+var subscription;
+var subscribed = false;
+var count = 0;
+var start = 0; // Start Time.
+
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+
+var pumpData = function() {
+    if (!subscribed) {
+        var subscriptionAddress = subscription.getAddress();
+        if (subscriptionAddress) {
+            subscribed = true;
+            var splitAddress = subscriptionAddress.split('/');
+            subscriptionQueue = splitAddress[splitAddress.length - 1];
+            onSubscription();
+        }
+    }
+
+    while (messenger.incoming()) {
+        // The second parameter forces Binary payloads to be decoded as strings
+        // this is useful because the broker QMF Agent encodes strings as AMQP
+        // binary, which is a right pain from an interoperability perspective.
+        var t = messenger.get(message, true);
+        //console.log("Address: " + message.getAddress());
+        //console.log("Content: " + message.body);
+        messenger.accept(t);
+
+        if (count % 1000 === 0) {
+            var time = +new Date();
+            console.log("count = " + count + ", duration = " + (time - start) + ", rate = " + ((count*1000)/(time - start)));
+        }
+
+        sendMessage();
+    }
+
+    if (messenger.isStopped()) {
+        message.free();
+        messenger.free();
+    }
+};
+
+var sendMessage = function() {
+    var msgtext = "Message Number " + count;
+    count++;
+
+    message.setAddress(address + '/' + subscriptionQueue);
+    message.body = msgtext;
+    messenger.put(message);
+//messenger.settle();
+};
+
+messenger.on('error', function(error) {console.log(error);});
+messenger.on('work', pumpData);
+//messenger.setOutgoingWindow(1024);
+messenger.setIncomingWindow(1024); // The Java Broker seems to need this.
+messenger.start();
+
+subscription = messenger.subscribe('amqp://' + addr + '/#');
+messenger.recv(); // Receive as many messages as messenger can buffer.
+
+var onSubscription = function() {
+    console.log("Subscription Queue: " + subscriptionQueue);
+    start = +new Date();
+    sendMessage();
+};
+


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


[08/51] [abbrv] qpid-proton git commit: Add packaging for npm and improve serialisation of numerical types

Posted by rh...@apache.org.
Add packaging for npm and improve serialisation of numerical types

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1591980 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/80c99528
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/80c99528
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/80c99528

Branch: refs/heads/master
Commit: 80c995287c2ad4efee2a479b74bed3bf1984f2fd
Parents: 33c895e
Author: fadams <fa...@unknown>
Authored: Fri May 2 17:30:42 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Fri May 2 17:30:42 2014 +0000

----------------------------------------------------------------------
 examples/messenger/c/CMakeLists.txt             |   4 +
 examples/messenger/javascript/drain.js          |  62 ++++++
 examples/messenger/javascript/spout.js          | 104 ++++++++++
 proton-c/bindings/javascript/CMakeLists.txt     |  32 ++-
 proton-c/bindings/javascript/README             |  40 ++--
 proton-c/bindings/javascript/binding.js         | 118 +++++++++--
 proton-c/bindings/javascript/drain.js           |  63 ------
 .../bindings/javascript/qpid-proton/LICENSE     | 203 +++++++++++++++++++
 .../bindings/javascript/qpid-proton/README.md   |   4 +
 .../javascript/qpid-proton/package.json         |  11 +
 proton-c/bindings/javascript/spout.js           | 100 ---------
 proton-c/src/messenger/messenger.c              |   4 +
 tools/cmake/Modules/FindNodePackages.cmake      |  70 ++++---
 13 files changed, 572 insertions(+), 243 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/examples/messenger/c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/messenger/c/CMakeLists.txt b/examples/messenger/c/CMakeLists.txt
index 4f40924..1b32d0c 100644
--- a/examples/messenger/c/CMakeLists.txt
+++ b/examples/messenger/c/CMakeLists.txt
@@ -21,8 +21,12 @@ find_package(Proton REQUIRED)
 
 add_executable(recv recv.c)
 add_executable(send send.c)
+add_executable(recv-async recv-async.c)
+add_executable(send-async send-async.c)
 
 include_directories(${Proton_INCLUDE_DIRS})
 
 target_link_libraries(recv ${Proton_LIBRARIES})
 target_link_libraries(send ${Proton_LIBRARIES})
+target_link_libraries(recv-async ${Proton_LIBRARIES})
+target_link_libraries(send-async ${Proton_LIBRARIES})

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/examples/messenger/javascript/drain.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/drain.js b/examples/messenger/javascript/drain.js
new file mode 100644
index 0000000..eacd8a2
--- /dev/null
+++ b/examples/messenger/javascript/drain.js
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("qpid-proton");
+}
+
+try {
+    var address = "amqp://~0.0.0.0";
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    function _process() {
+//        console.log("                          *** process ***");
+
+        // Process incoming messages
+
+        while (messenger.incoming()) {
+console.log("in while loop\n");
+
+            var tracker = messenger.get(message);
+console.log("tracker = " + tracker);
+
+            console.log("Address: " + message.getAddress());
+            console.log("Subject: " + message.getSubject());
+            console.log("Content: " + message.body);
+
+            messenger.accept(tracker);
+        }
+    };
+
+    //messenger.setIncomingWindow(1024);
+
+    messenger.setNetworkCallback(_process);
+    messenger.start();
+
+    messenger.subscribe(address);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+
+} catch(e) {
+    console.log("Caught Exception " + e);
+}
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/examples/messenger/javascript/spout.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/spout.js b/examples/messenger/javascript/spout.js
new file mode 100644
index 0000000..071eb72
--- /dev/null
+++ b/examples/messenger/javascript/spout.js
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("qpid-proton");
+}
+
+try {
+    var address = "amqp://0.0.0.0";
+    var subject = "UK.WEATHER";
+    var msgtext = "Hello World!";
+    var tracker = null;
+    var running = true;
+
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    function _process() {
+//        console.log("                          *** process ***");
+
+        // Process outgoing messages
+        var status = messenger.status(tracker);
+        if (status != proton.Status.PENDING) {
+console.log("status = " + status);
+
+            //messenger.settle(tracker);
+            //tracked--;
+
+            if (running) {
+console.log("stopping");
+                messenger.stop();
+                running = false;
+            } 
+        }
+
+        if (messenger.isStopped()) {
+console.log("exiting");
+            message.free();
+            messenger.free();
+            //exit(0);
+        }
+    };
+
+
+    messenger.setOutgoingWindow(1024);
+
+    messenger.setNetworkCallback(_process);
+    messenger.start();
+
+    message.setAddress(address);
+    message.setSubject(subject);
+    //message.body = msgtext;
+    //message.body = new proton.Data.UUID();
+    //message.body = new proton.Data.Symbol("My Symbol");
+    //message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
+
+    /*message.body = new proton.Data.Binary(4);
+    var buffer = message.body.getBuffer();
+    buffer[0] = 65;
+    buffer[1] = 77;
+    buffer[2] = 81;
+    buffer[3] = 80;*/
+
+
+    //message.body = true;
+    //message.body = "   \"127.0\"  ";
+
+    //message.body = 2147483647; // int
+    //message.body = -2147483649; // long
+    //message.body = 12147483649; // long
+
+
+    message.body = (121474.836490).asFloat(); // float TODO check me
+    //message.body = 12147483649.0.asFloat(); // float TODO check me
+    //message.body = (4294967296).asUnsignedInteger();
+    //message.body = (255).asUnsignedByte();
+
+
+    //message.body = ['Rod', 'Jane', 'Freddy'];
+    //message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
+
+    tracker = messenger.put(message);
+
+} catch(e) {
+    console.log("Caught Exception " + e);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index 966d0ba..e043adb 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -222,9 +222,34 @@ set_target_properties(
   # This build is optimised and minified
   #LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --pre-js
 
-  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_m
 essenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_
 put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get
 _binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_r
 ecv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array'
 , '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '
 _pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
   )
 
+# This command packages up the compiled proton.js into a node.js package called
+# qpid-proton and copies it to the <proton>/node_modules directory. This allows
+# the node.js test and example programs to do proton = require("qpid-proton");
+add_custom_command(
+    TARGET proton.js
+    COMMAND ${CMAKE_COMMAND}
+            -E copy_directory 
+            ${CMAKE_CURRENT_SOURCE_DIR}/qpid-proton 
+            ${PROJECT_SOURCE_DIR}/node_modules/qpid-proton
+    COMMAND ${CMAKE_COMMAND}
+            -E copy
+            ${CMAKE_CURRENT_BINARY_DIR}/proton.js
+            ${PROJECT_SOURCE_DIR}/node_modules/qpid-proton/lib
+   COMMENT "Building qpid-proton package for node.js"
+)
+
+# The cleanall target removes the qpid-proton package from <proton>/node_modules
+add_custom_target(
+    cleanall
+    COMMAND echo "CLEAN NODE MODULES"
+    COMMAND ${CMAKE_COMMAND}
+            -E remove_directory
+            ${PROJECT_SOURCE_DIR}/node_modules/qpid-proton
+)
+
 # If the docs target is specified and the jsdoc3 package for node.js has been
 # installed then build the JavaScript API documentation.
 if (NODE_JSDOC_FOUND)
@@ -236,8 +261,3 @@ if (NODE_JSDOC_FOUND)
 
 endif (NODE_JSDOC_FOUND)
 
-# Some hacks so check what's getting built TODO to get rid of eventually 
-#message(STATUS "qpid-proton-platform: ${qpid-proton-platform}")
-#message(STATUS "qpid-proton-core: ${qpid-proton-core}")
-
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/proton-c/bindings/javascript/README
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/README b/proton-c/bindings/javascript/README
index 67702ff..1998a47 100644
--- a/proton-c/bindings/javascript/README
+++ b/proton-c/bindings/javascript/README
@@ -15,36 +15,35 @@ emscripten itself depends upon. https://github.com/kripken/emscripten/wiki/Emscr
 provides some fairly easy to follow instructions for getting started on several
 platforms the main dependencies are as follows (on Windows the SDK includes these):
 
-* The Emscripten code, from github (git clone git://github.com/kripken/emscripten.git. The documentation suggests
-  master branch but in the short term incoming is probably better as a few updates to emscripten have been added
-  to help get proton working and these may take a little while to get merged back to master.
-* LLVM with Clang. Version 3.2 is the officially supported version, others may not work. There are official clang
-  binaries that include LLVM for some platforms, if yours is not there then you should get the LLVM and Clang
-  sources and build them.
+* The Emscripten code, from github (git clone git://github.com/kripken/emscripten.git.
+  The documentation suggests master branch but in the short term incoming is
+  probably better as a few updates to emscripten have been added to help get
+  proton working and these may take a little while to get merged back to master.
+* LLVM with Clang. Emscripten uses LLVM and Clang, but at the moment the JavaScript
+  back-end for LLVM is off on a branch so you can't use a stock LLVM/Clang.
+  https://github.com/kripken/emscripten/wiki/LLVM-Backend has lots of explanation
+  and some easy to follow instructions for downloading and building fast-comp
 * Node.js (0.8 or above; 0.10.17 or above to run websocket-using servers in node)
 * Python 2.7.3
-* Optionally, if you want to use Closure Compiler to minify your code as much as possible, you will also need Java.
+* Java is required in order to use the Closure Compiler to minify the code.
+  
 
-If you haven't run Emscripten before it's a good idea to have a play with the tutorial
-https://github.com/kripken/emscripten/wiki/Tutorial
+If you haven't run Emscripten before it's a good idea to have a play with the
+tutorial https://github.com/kripken/emscripten/wiki/Tutorial
 
 
-when you are all set up with emscripten and have got the basic tests in the tutorial running
-building Proton should be simple, simply go to the Proton root directory and follow the main
-instructions in the README there, in precis (from the root directory) it's:
+
+
+when you are all set up with emscripten and have got the basic tests in the
+tutorial running building Proton should be simple, simply go to the Proton root
+directory and follow the main instructions in the README there, in precis (from
+the root directory) it's:
 
   mkdir build
   cd build
   cmake ..
   make
 
-
-In order to use WebSockets from Node.js you will need to install the "ws" package, the easiest
-way to do this is to use npm. From <proton-root>/build/proton-c/bindings/javascript (or where
-ever you decide to put the JavaScript binding library created by this build) simply do:
-
-  npm install ws
-
 and you should be all set, to test it's all working do:
 
   node recv-async.js
@@ -59,8 +58,7 @@ in another
 KNOWN ISSUES
 ============
 
-send-async and recv-async are both pretty hacky at the moment and not really asynchronous, this will
-be addressed ASAP.
+send-async and recv-async are both pretty hacky at the moment.
 
 
 SUPPORT

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index 269ee27..43634d4 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -25,7 +25,7 @@
  * <p>
  * This JavaScript wrapper provides a somewhat more idiomatic object oriented
  * interface which abstracts the low-level emscripten based implementation details
- * from client code.
+ * from client code. Any similarities to the Proton Python binding are deliberate.
  * @file
  */
 
@@ -123,7 +123,7 @@ Module['Messenger'] = function(name) { // Messenger Constructor.
      * freed. In C code compiled by emscripten saving and restoring of the stack
      * is automatic, but if we want to us ALLOC_STACK from native JavaScript we
      * need to explicitly save and restore the stack using Runtime.stackSave()
-     * and Runtime.stackRestore() or we will leak memory.
+     * and Runtime.stackRestore() or we will leak emscripten heap memory.
      * See https://github.com/kripken/emscripten/wiki/Interacting-with-code
      * The _pn_messenger constructor copies the char* passed to it.
      */
@@ -415,7 +415,7 @@ _Messenger_['put'] = function(message) {
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
     // low/high pair around to methods that require a tracker.
     var low = _pn_messenger_outgoing_tracker(this._messenger);
-    var high = tempRet0;
+    var high = Runtime.getTempRet0();
     return new Data.Long(low, high);
 };
 
@@ -458,7 +458,7 @@ console.log("settle: not fully tested yet");
     var flags = 0;
     if (tracker == null) {
         var low = _pn_messenger_outgoing_tracker(this._messenger);
-        var high = tempRet0;
+        var high = Runtime.getTempRet0();
         tracker = new Data.Long(low, high);
         flags = Module['Messenger'].PN_CUMULATIVE;
     }
@@ -531,12 +531,10 @@ _Messenger_['get'] = function(message) {
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
     // low/high pair around to methods that require a tracker.
     var low = _pn_messenger_incoming_tracker(this._messenger);
-    var high = tempRet0;
+    var high = Runtime.getTempRet0();
 console.log("get low = " + low);
 console.log("get high = " + high);
 
-console.log("get asm = " + asm);
-console.log("get asm['tempRet0'] = " + asm['tempRet0']);
     return new Data.Long(low, high);
 };
 
@@ -577,7 +575,7 @@ console.log("accept: not fully tested yet");
     var flags = 0;
     if (tracker == null) {
         var low = _pn_messenger_incoming_tracker(this._messenger);
-        var high = tempRet0;
+        var high = Runtime.getTempRet0();
         tracker = new Data.Long(low, high);
         flags = Module['Messenger'].PN_CUMULATIVE;
     }
@@ -602,7 +600,7 @@ console.log("reject: not fully tested yet");
     var flags = 0;
     if (tracker == null) {
         var low = _pn_messenger_incoming_tracker(this._messenger);
-        var high = tempRet0;
+        var high = Runtime.getTempRet0();
         tracker = new Data.Long(low, high);
         flags = Module['Messenger'].PN_CUMULATIVE;
     }
@@ -1237,6 +1235,77 @@ Data['Symbol'].prototype['equals'] = function(rhs) {
     return this.toString() === rhs.toString();
 };
 
+// ---------------------- JavaScript Number Extensions ------------------------ 
+
+Number.prototype['asUnsignedByte'] = function() {
+    return new Data.TypedNumber('UnsignedByte', this);
+};
+
+Number.prototype['asByte'] = function() {
+    return new Data.TypedNumber('Byte', this);
+};
+
+Number.prototype['asUnsignedShort'] = function() {
+    return new Data.TypedNumber('UnsignedShort', this);
+};
+
+Number.prototype['asShort'] = function() {
+    return new Data.TypedNumber('Short', this);
+};
+
+Number.prototype['asUnsignedInteger'] = function() {
+    return new Data.TypedNumber('UnsignedInteger', this);
+};
+
+Number.prototype['asInteger'] = function() {
+    return new Data.TypedNumber('Integer', this);
+};
+
+Number.prototype['asUnsignedLong'] = function() {
+    return new Data.TypedNumber('UnsignedLong', this);
+};
+
+Number.prototype['asLong'] = function() {
+    return new Data.TypedNumber('Long', this);
+};
+
+Number.prototype['asFloat'] = function() {
+    return new Data.TypedNumber('Float', this);
+};
+
+Number.prototype['asDouble'] = function() {
+    return new Data.TypedNumber('Double', this);
+};
+
+Number.prototype['asChar'] = function() {
+    return new Data.TypedNumber('Char', this);
+};
+
+String.prototype['asChar'] = function() {
+    return new Data.TypedNumber('Char', this.charCodeAt(0));
+};
+
+// ------------------------- proton.Data.TypedNumber -------------------------- 
+/**
+ * Create a proton.Data.TypedNumber.
+ * @classdesc
+ * This class is a simple wrapper class that allows a "type" to be recorded for
+ * a number. The idea is that the JavaScript Number class is extended with extra
+ * methods to allow numbers to be "modified" to TypedNumbers, so for example
+ * 1.0.asFloat() would modify 1.0 by returning a TypedNumber with type = Float
+ * and value = 1. The strings used for type correspond to the names of the Data
+ * put* methods e.g. UnsignedByte, Byte, UnsignedShort, Short, UnsignedInteger,
+ * Integer, UnsignedLong, Long, Float, Double, Char so that the correct method
+ * to call can be easily derived from the TypedNumber's type.
+ * @constructor proton.Data.TypedNumber
+ * @param {string} type the type of the Number.
+ * @param {number} value the most significant word.
+ */
+// Use dot notation as it is a "protected" inner class not exported from the closure.
+Data.TypedNumber = function(type, value) { // Data.TypedNumber Constructor.
+    this.type  = type;
+    this.value = value;
+};
 
 // ----------------------------- proton.Data.Long ----------------------------- 
 /**
@@ -1250,6 +1319,7 @@ Data['Symbol'].prototype['equals'] = function(rhs) {
  * @param {number} low the least significant word.
  * @param {number} high the most significant word.
  */
+// Use dot notation as it is a "protected" inner class not exported from the closure.
 Data.Long = function(low, high) { // Data.Long Constructor.
     this.low  = low  | 0;  // force into 32 signed bits.
     this.high = high | 0;  // force into 32 signed bits.
@@ -1805,7 +1875,6 @@ _Data_['putInteger'] = function(i) {
  * @param {number} c a single character.
  */
 _Data_['putChar'] = function(c) {
-console.log("putChar not properly implemented yet");
     this._check(_pn_data_put_char(this._data, c));
 };
 
@@ -1850,6 +1919,7 @@ console.log("putTimestamp not properly implemented yet");
  * @param {number} f a floating point value.
  */
 _Data_['putFloat'] = function(f) {
+console.log("putFloat f = " + f);
     this._check(_pn_data_put_float(this._data, f));
 };
 
@@ -2043,7 +2113,7 @@ _Data_['getBoolean'] = function() {
  * @returns {number} value if the current node is an unsigned byte, returns 0 otherwise.
  */
 _Data_['getUnsignedByte'] = function() {
-    return _pn_data_get_ubyte(this._data);
+    return _pn_data_get_ubyte(this._data) & 0xFF; // & 0xFF converts to unsigned;
 };
 
 /**
@@ -2059,7 +2129,7 @@ _Data_['getByte'] = function() {
  * @return value if the current node is an unsigned short, returns 0 otherwise.
  */
 _Data_['getUnsignedShort'] = function() {
-    return _pn_data_get_ushort(this._data);
+    return _pn_data_get_ushort(this._data) & 0xFFFF; // & 0xFFFF converts to unsigned;
 };
 
 /**
@@ -2077,7 +2147,8 @@ _Data_['getShort'] = function() {
  * @returns {number} value if the current node is an unsigned int, returns 0 otherwise.
  */
 _Data_['getUnsignedInteger'] = function() {
-    return _pn_data_get_uint(this._data);
+    var value = _pn_data_get_uint(this._data);
+    return (value > 0) ? value : 4294967296 + value; // 4294967296 == 2^32
 };
 
 /**
@@ -2092,13 +2163,10 @@ _Data_['getInteger'] = function() {
 /**
  * @method getChar
  * @memberof! proton.Data#
- * @returns {number} value if the current node is a character, returns 0 otherwise.
+ * @returns {string} the character represented by the unicode value of the current node.
  */
-// TODO should this be dealing with strings not numbers?
 _Data_['getChar'] = function() {
-console.log("getChar not properly implemented yet");
-return "character";
-    //return _pn_data_get_char(this._data);
+    return String.fromCharCode(_pn_data_get_char(this._data));
 };
 
 /**
@@ -2107,6 +2175,7 @@ return "character";
  * @returns {number} value if the current node is an unsigned long, returns 0 otherwise.
  */
 _Data_['getUnsignedLong'] = function() {
+console.log("getUnsignedLong");
     return _pn_data_get_ulong(this._data);
 };
 
@@ -2123,7 +2192,7 @@ console.log("getLong");
     // the 64 bit number and Data.Long.toNumber() to convert it back into a
     // JavaScript number.
     var low = _pn_data_get_long(this._data);
-    var high = tempRet0;
+    var high = Runtime.getTempRet0();
     var long = new Data.Long(low, high);
     long = long.toNumber();
 
@@ -2442,8 +2511,12 @@ console.log("obj is quoted String " + quoted);
         this['putBinary'](obj);
     } else if (obj instanceof Data['Symbol']) {
         this['putSymbol'](obj);
+    } else if (obj instanceof Data.TypedNumber) { // Dot notation used for "protected" inner class.
+        // Call the appropriate serialisation method based upon the numerical type.
+        this['put' + obj.type](obj.value);
     } else if (Data.isNumber(obj)) {
         /**
+         * This block encodes standard JavaScript numbers by making some inferences.
          * Encoding JavaScript numbers is surprisingly complex and has several
          * gotchas. The code here tries to do what the author believes is the
          * most intuitive encoding of the native JavaScript Number. It first
@@ -2454,9 +2527,10 @@ console.log("obj is quoted String " + quoted);
          * 32 bit Int value. N.B. JavaScript automagically coerces floating
          * point numbers with a zero Fractional Part into an exact integer so
          * numbers like 1.0, 100.0 etc. will be encoded as int or long here,
-         * which is unlikely to be what is wanted. There's no easy way around this
-         * the two main options are to add a very small fractional number or to
-         * represent the number in a String literal e.g. "1.0f", "1.0d", "1l"
+         * which is unlikely to be what is wanted. There's no easy "transparent"
+         * way around this. The TypedNumber approach above allows applications
+         * to express more explicitly what is require, for example 1.0.asFloat()
+         * (1).asUnsignedByte(), (5).asLong() etc.
          */
         if (obj % 1 === 0) {
 console.log(obj + " is Integer Type " + (obj|0));

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/proton-c/bindings/javascript/drain.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/drain.js b/proton-c/bindings/javascript/drain.js
deleted file mode 100644
index 9d9c726..0000000
--- a/proton-c/bindings/javascript/drain.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("../../../bld/proton-c/bindings/javascript/proton.js");
-}
-
-try {
-    var address = "amqp://~0.0.0.0";
-    var message = new proton.Message();
-    var messenger = new proton.Messenger();
-
-    function _process() {
-//        console.log("                          *** process ***");
-
-        // Process incoming messages
-
-        while (messenger.incoming()) {
-console.log("in while loop\n");
-
-            var tracker = messenger.get(message);
-console.log("tracker = " + tracker);
-
-            console.log("Address: " + message.getAddress());
-            console.log("Subject: " + message.getSubject());
-            console.log("Content: " + message.body);
-
-            messenger.accept(tracker);
-        }
-    };
-
-    //messenger.setIncomingWindow(1024);
-console.log("Break A");
-    messenger.setNetworkCallback(_process);
-    messenger.start();
-console.log("Break B");
-    messenger.subscribe(address);
-console.log("Break C");
-    messenger.recv(); // Receive as many messages as messenger can buffer.
-console.log("Break D");
-} catch(e) {
-    console.log("Caught Exception " + e);
-}
-
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/proton-c/bindings/javascript/qpid-proton/LICENSE
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/qpid-proton/LICENSE b/proton-c/bindings/javascript/qpid-proton/LICENSE
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/proton-c/bindings/javascript/qpid-proton/LICENSE
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/proton-c/bindings/javascript/qpid-proton/README.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/qpid-proton/README.md b/proton-c/bindings/javascript/qpid-proton/README.md
new file mode 100644
index 0000000..db026c7
--- /dev/null
+++ b/proton-c/bindings/javascript/qpid-proton/README.md
@@ -0,0 +1,4 @@
+qpid-proton
+-----------
+
+apache qpid proton messenger AMQP 1.0 library

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/proton-c/bindings/javascript/qpid-proton/package.json
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/qpid-proton/package.json b/proton-c/bindings/javascript/qpid-proton/package.json
new file mode 100644
index 0000000..ffc5ebe
--- /dev/null
+++ b/proton-c/bindings/javascript/qpid-proton/package.json
@@ -0,0 +1,11 @@
+{
+    "name" : "qpid-proton",
+    "version": "0.7.0",
+    "description": "apache qpid proton messenger AMQP 1.0 library",
+    "repository": {
+        "type": "svn",
+        "url": "https://svn.apache.org/repos/asf/qpid/proton/trunk/"
+    },
+    "main" : "./lib/proton.js",
+    "dependencies": {}
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/proton-c/bindings/javascript/spout.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/spout.js b/proton-c/bindings/javascript/spout.js
deleted file mode 100644
index 254b948..0000000
--- a/proton-c/bindings/javascript/spout.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("../../../bld/proton-c/bindings/javascript/proton.js");
-}
-
-try {
-    var address = "amqp://0.0.0.0";
-    var subject = "UK.WEATHER";
-    var msgtext = "Hello World!";
-    var tracker = null;
-    var running = true;
-
-    var message = new proton.Message();
-    var messenger = new proton.Messenger();
-
-    function _process() {
-//        console.log("                          *** process ***");
-
-        // Process outgoing messages
-        var status = messenger.status(tracker);
-        if (status != proton.Status.PENDING) {
-console.log("status = " + status);
-
-            //messenger.settle(tracker);
-            //tracked--;
-
-            if (running) {
-console.log("stopping");
-                messenger.stop();
-                running = false;
-            } 
-        }
-
-        if (messenger.isStopped()) {
-console.log("exiting");
-            message.free();
-            messenger.free();
-            //exit(0);
-        }
-    };
-
-
-    messenger.setOutgoingWindow(1024);
-
-    messenger.setNetworkCallback(_process);
-    messenger.start();
-
-    message.setAddress(address);
-    message.setSubject(subject);
-    //message.body = msgtext;
-    //message.body = new proton.Data.UUID();
-    //message.body = new proton.Data.Symbol("My Symbol");
-    //message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
-
-    message.body = new proton.Data.Binary(4);
-    var buffer = message.body.getBuffer();
-    buffer[0] = 65;
-    buffer[1] = 77;
-    buffer[2] = 81;
-    buffer[3] = 80;
-
-
-    //message.body = true;
-    //message.body = "   \"127.0\"  ";
-
-    //message.body = 2147483647; // int
-    //message.body = -2147483649; // long
-    //message.body = 12147483649; // long
-
-    //message.body = 2147483647.000001; // double
-
-    //message.body = ['Rod', 'Jane', 'Freddy'];
-    //message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
-
-
-    tracker = messenger.put(message);
-
-} catch(e) {
-    console.log("Caught Exception " + e);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/proton-c/src/messenger/messenger.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/messenger.c b/proton-c/src/messenger/messenger.c
index d2cd10c..29b2eeb 100644
--- a/proton-c/src/messenger/messenger.c
+++ b/proton-c/src/messenger/messenger.c
@@ -602,6 +602,10 @@ pn_messenger_t *pn_messenger(const char *name)
        pni_interruptor_finalize);
     pn_list_add(m->pending, m->interruptor);
     m->interrupted = false;
+    // Explicitly initialise pipe file descriptors to invalid values in case pipe
+    // fails, if we don't do this m->ctrl[0] could default to 0 - which is stdin.
+    m->ctrl[0] = -1;
+    m->ctrl[1] = -1;
     pn_pipe(m->io, m->ctrl);
     pni_selectable_set_fd(m->interruptor, m->ctrl[0]);
     pni_selectable_set_context(m->interruptor, m);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/80c99528/tools/cmake/Modules/FindNodePackages.cmake
----------------------------------------------------------------------
diff --git a/tools/cmake/Modules/FindNodePackages.cmake b/tools/cmake/Modules/FindNodePackages.cmake
index 31c5551..bfbb36f 100644
--- a/tools/cmake/Modules/FindNodePackages.cmake
+++ b/tools/cmake/Modules/FindNodePackages.cmake
@@ -18,43 +18,51 @@
 #
 
 # FindNodePackages
-# This module finds and installs (optionally) required node.js packages using npm
+# This module finds and installs (using npm) node.js packages that are used by
+# the JavaScript binding. The binding should still compile if these packages
+# cannot be installed but certain features might not work as described below.
+#
 # * The ws package is the WebSocket library used by emscripten when the target is
-#   node.js, it isn't needed for applications hosted on a browser where native 
-#   WebSockets will be used.
+#   node.js, it isn't needed for applications hosted on a browser (where native 
+#   WebSockets will be used), but without it it won't work with node.js.
 #
 # * The jsdoc package is a JavaScript API document generator analogous to Doxygen
 #   or JavaDoc, it is used by the docs target in the JavaScript binding.
 
 if (NOT NODE_PACKAGES_FOUND)
-    # Install ws node.js WebSocket library https://github.com/einaros/ws
-    message(STATUS "Installing node.js ws package")
-
-    execute_process(
-        COMMAND npm install ws
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-        OUTPUT_VARIABLE var
-    )
-
-    if (var)
-        message(STATUS "Node.js ws package has been installed")
-        set(NODE_WS_FOUND ON)
-    endif (var)
-
-    # Install jsdoc3 API documentation generator for JavaScript https://github.com/jsdoc3/jsdoc
-    message(STATUS "Installing node.js jsdoc package")
-
-    execute_process(
-        COMMAND npm install jsdoc
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
-        OUTPUT_VARIABLE var
-    )
-
-    if (var)
-        message(STATUS "Node.js jsdoc package has been installed")
-        set(NODE_JSDOC_FOUND ON)
-        set(JSDOC_EXE ${PROJECT_SOURCE_DIR}/node_modules/.bin/jsdoc)
-    endif (var)
+    # Check if the specified node.js package is already installed, if not install it.
+    macro(InstallPackage varname name)
+        execute_process(
+            COMMAND npm list --local ${name}
+            OUTPUT_VARIABLE check_package
+        )
+
+        set(${varname} OFF)
+
+        if (check_package MATCHES "${name}@.")
+            message(STATUS "Found node.js package: ${name}")
+            set(${varname} ON)
+        else()
+            message(STATUS "Installing node.js package: ${name}")
+
+            execute_process(
+                COMMAND npm install ${name}
+                WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+                OUTPUT_VARIABLE var
+            )
+
+            if (var)
+                message(STATUS "Installed node.js package: ${name}")
+                set(${varname} ON)
+            endif (var)
+        endif()
+    endmacro()
+
+    # Check if ws WebSocket library https://github.com/einaros/ws is installed
+    InstallPackage("NODE_WS_FOUND" "ws")
+
+    # Check if jsdoc3 API documentation generator https://github.com/jsdoc3/jsdoc is installed
+    InstallPackage("NODE_JSDOC_FOUND" "jsdoc")
 
     set(NODE_PACKAGES_FOUND ON)
 endif (NOT NODE_PACKAGES_FOUND)


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


[42/51] [abbrv] qpid-proton git commit: Sync with proton trunk revision 1627945 and update CMakeLists.txt

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
index 75ba56c..a0a2e95 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
@@ -28,59 +28,47 @@ package org.apache.qpid.proton.engine;
 
 public interface Event
 {
-    public enum Category {
-        CONNECTION,
-        SESSION,
-        LINK,
-        DELIVERY,
-        TRANSPORT;
-    }
 
     public enum Type {
-        CONNECTION_INIT(Category.CONNECTION, 1),
-        CONNECTION_OPEN(Category.CONNECTION, 2),
-        CONNECTION_REMOTE_OPEN(Category.CONNECTION, 3),
-        CONNECTION_CLOSE(Category.CONNECTION, 4),
-        CONNECTION_REMOTE_CLOSE(Category.CONNECTION, 5),
-        CONNECTION_FINAL(Category.CONNECTION, 6),
-
-        SESSION_INIT(Category.SESSION, 1),
-        SESSION_OPEN(Category.SESSION, 2),
-        SESSION_REMOTE_OPEN(Category.SESSION, 3),
-        SESSION_CLOSE(Category.SESSION, 4),
-        SESSION_REMOTE_CLOSE(Category.SESSION, 5),
-        SESSION_FINAL(Category.SESSION, 6),
-
-        LINK_INIT(Category.LINK, 1),
-        LINK_OPEN(Category.LINK, 2),
-        LINK_REMOTE_OPEN(Category.LINK, 3),
-        LINK_CLOSE(Category.LINK, 4),
-        LINK_REMOTE_CLOSE(Category.LINK, 5),
-        LINK_FLOW(Category.LINK, 6),
-        LINK_FINAL(Category.LINK, 7),
-
-        DELIVERY(Category.DELIVERY, 1),
-        TRANSPORT(Category.TRANSPORT, 1);
-
-        private int _opcode;
-        private Category _category;
-
-        private Type(Category c, int o)
-        {
-            this._category = c;
-            this._opcode = o;
-        }
-
-        public Category getCategory()
-        {
-            return this._category;
-        }
-    }
+        CONNECTION_INIT,
+        CONNECTION_BOUND,
+        CONNECTION_UNBOUND,
+        CONNECTION_OPEN,
+        CONNECTION_REMOTE_OPEN,
+        CONNECTION_CLOSE,
+        CONNECTION_REMOTE_CLOSE,
+        CONNECTION_FINAL,
+
+        SESSION_INIT,
+        SESSION_OPEN,
+        SESSION_REMOTE_OPEN,
+        SESSION_CLOSE,
+        SESSION_REMOTE_CLOSE,
+        SESSION_FINAL,
+
+        LINK_INIT,
+        LINK_OPEN,
+        LINK_REMOTE_OPEN,
+        LINK_CLOSE,
+        LINK_REMOTE_CLOSE,
+        LINK_DETACH,
+        LINK_REMOTE_DETACH,
+        LINK_FLOW,
+        LINK_FINAL,
 
-    Category getCategory();
+        DELIVERY,
+
+        TRANSPORT,
+        TRANSPORT_ERROR,
+        TRANSPORT_HEAD_CLOSED,
+        TRANSPORT_TAIL_CLOSED,
+        TRANSPORT_CLOSED
+    }
 
     Type getType();
 
+    Object getContext();
+
     Connection getConnection();
 
     Session getSession();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java
index 04ec3f4..c965a29 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java
@@ -184,4 +184,7 @@ public interface Link extends Endpoint
 
     public int getRemoteCredit();
     public boolean getDrain();
+
+    public void detach();
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java
index ba806bd..e0dc9c2 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java
@@ -22,6 +22,7 @@ package org.apache.qpid.proton.engine;
 
 import java.nio.ByteBuffer;
 
+import org.apache.qpid.proton.amqp.transport.ErrorCondition;
 import org.apache.qpid.proton.engine.impl.TransportImpl;
 
 
@@ -221,4 +222,6 @@ public interface Transport extends Endpoint
 
     int getRemoteChannelMax();
 
+    ErrorCondition getCondition();
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
index 1dcebe4..60d6dfe 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
@@ -56,11 +56,6 @@ class EventImpl implements Event
         context = null;
     }
 
-    public Category getCategory()
-    {
-        return type.getCategory();
-    }
-
     public Type getType()
     {
         return type;
@@ -73,16 +68,15 @@ class EventImpl implements Event
 
     public Connection getConnection()
     {
-        switch (type.getCategory()) {
-        case CONNECTION:
+        if (context instanceof Connection) {
             return (Connection) context;
-        case TRANSPORT:
+        } else if (context instanceof Transport) {
             Transport transport = getTransport();
             if (transport == null) {
                 return null;
             }
             return ((TransportImpl) transport).getConnectionImpl();
-        default:
+        } else {
             Session ssn = getSession();
             if (ssn == null) {
                 return null;
@@ -93,10 +87,9 @@ class EventImpl implements Event
 
     public Session getSession()
     {
-        switch (type.getCategory()) {
-        case SESSION:
+        if (context instanceof Session) {
             return (Session) context;
-        default:
+        } else {
             Link link = getLink();
             if (link == null) {
                 return null;
@@ -107,10 +100,9 @@ class EventImpl implements Event
 
     public Link getLink()
     {
-        switch (type.getCategory()) {
-        case LINK:
+        if (context instanceof Link) {
             return (Link) context;
-        default:
+        } else {
             Delivery dlv = getDelivery();
             if (dlv == null) {
                 return null;
@@ -121,20 +113,18 @@ class EventImpl implements Event
 
     public Delivery getDelivery()
     {
-        switch (type.getCategory()) {
-        case DELIVERY:
+        if (context instanceof Delivery) {
             return (Delivery) context;
-        default:
+        } else {
             return null;
         }
     }
 
     public Transport getTransport()
     {
-        switch (type.getCategory()) {
-        case TRANSPORT:
+        if (context instanceof Transport) {
             return (Transport) context;
-        default:
+        } else {
             return null;
         }
     }
@@ -150,4 +140,5 @@ class EventImpl implements Event
     {
         return "EventImpl{" + "type=" + type + ", context=" + context + '}';
     }
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
index 37433d5..0da2a60 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
@@ -55,6 +55,7 @@ public abstract class LinkImpl extends EndpointImpl implements Link
 
     private LinkNode<LinkImpl> _node;
     private boolean _drain;
+    private boolean _detached;
 
     LinkImpl(SessionImpl session, String name)
     {
@@ -398,4 +399,17 @@ public abstract class LinkImpl extends EndpointImpl implements Link
     {
         getConnectionImpl().put(Event.Type.LINK_CLOSE, this);
     }
+
+    public void detach()
+    {
+        _detached = true;
+        getConnectionImpl().put(Event.Type.LINK_DETACH, this);
+        modified();
+    }
+
+    boolean detached()
+    {
+        return _detached;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
index 57010d2..26ad9ca 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
@@ -103,11 +103,14 @@ public class SessionImpl extends EndpointImpl implements ProtonJSession
         _connection.removeSessionEndpoint(_node);
         _node = null;
 
-        for(SenderImpl sender : _senders.values()) {
+        List<SenderImpl> senders = new ArrayList<SenderImpl>(_senders.values());
+        for(SenderImpl sender : senders) {
             sender.free();
         }
         _senders.clear();
-        for(ReceiverImpl receiver : _receivers.values()) {
+
+        List<ReceiverImpl> receivers = new ArrayList<ReceiverImpl>(_receivers.values());
+        for(ReceiverImpl receiver : receivers) {
             receiver.free();
         }
         _receivers.clear();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
index 62cb10d..2c6c884 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
@@ -121,7 +121,10 @@ public class TransportImpl extends EndpointImpl
 
     private FrameHandler _frameHandler = this;
     private boolean _head_closed = false;
-    private TransportException _tail_error = null;
+    private ErrorCondition _condition = null;
+
+    private boolean postedHeadClosed = false;
+    private boolean postedTailClosed = false;
 
     /**
      * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
@@ -208,10 +211,18 @@ public class TransportImpl extends EndpointImpl
     }
 
     @Override
+    public ErrorCondition getCondition()
+    {
+        return _condition;
+    }
+
+    @Override
     public void bind(Connection conn)
     {
-        _connectionEndpoint = (ConnectionImpl) conn;
         // TODO - check if already bound
+
+        _connectionEndpoint = (ConnectionImpl) conn;
+        put(Event.Type.CONNECTION_BOUND, conn);
         _connectionEndpoint.setTransport(this);
         _connectionEndpoint.incref();
 
@@ -230,6 +241,7 @@ public class TransportImpl extends EndpointImpl
     @Override
     public void unbind()
     {
+        put(Event.Type.CONNECTION_UNBOUND, _connectionEndpoint);
         _connectionEndpoint.modifyEndpoints();
 
         _connectionEndpoint.setTransport(null);
@@ -369,7 +381,7 @@ public class TransportImpl extends EndpointImpl
                     SessionImpl session = link.getSession();
                     TransportSession transportSession = getTransportState(session);
 
-                    if(link.getLocalState() == EndpointState.CLOSED
+                    if(((link.getLocalState() == EndpointState.CLOSED) || link.detached())
                        && transportLink.isLocalHandleSet()
                        && !_isCloseSent)
                     {
@@ -389,8 +401,7 @@ public class TransportImpl extends EndpointImpl
 
                         Detach detach = new Detach();
                         detach.setHandle(localHandle);
-                        // TODO - need an API for detaching rather than closing the link
-                        detach.setClosed(true);
+                        detach.setClosed(!link.detached());
 
                         ErrorCondition localError = link.getCondition();
                         if( localError.getCondition() !=null )
@@ -517,6 +528,11 @@ public class TransportImpl extends EndpointImpl
             transfer.setDeliveryTag(new Binary(delivery.getTag()));
             transfer.setHandle(tpLink.getLocalHandle());
 
+            if(delivery.getLocalState() != null)
+            {
+                transfer.setState(delivery.getLocalState());
+            }
+
             if(delivery.isSettled())
             {
                 transfer.setSettled(Boolean.TRUE);
@@ -742,7 +758,7 @@ public class TransportImpl extends EndpointImpl
 
     private void processOpen()
     {
-        if ((_tail_error != null ||
+        if ((_condition != null ||
              (_connectionEndpoint != null &&
               _connectionEndpoint.getLocalState() != EndpointState.UNINITIALIZED)) &&
             !_isOpenSent) {
@@ -919,7 +935,7 @@ public class TransportImpl extends EndpointImpl
 
     private void processClose()
     {
-        if ((_tail_error != null ||
+        if ((_condition != null ||
              (_connectionEndpoint != null &&
               _connectionEndpoint.getLocalState() == EndpointState.CLOSED)) &&
             !_isCloseSent) {
@@ -930,8 +946,7 @@ public class TransportImpl extends EndpointImpl
                 ErrorCondition localError;
 
                 if (_connectionEndpoint == null) {
-                    localError = new ErrorCondition(ConnectionError.FRAMING_ERROR,
-                                                    _tail_error.toString());
+                    localError = _condition;
                 } else {
                     localError =  _connectionEndpoint.getCondition();
                 }
@@ -1154,7 +1169,11 @@ public class TransportImpl extends EndpointImpl
                 LinkImpl link = transportLink.getLink();
                 transportLink.receivedDetach();
                 transportSession.freeRemoteHandle(transportLink.getRemoteHandle());
-                _connectionEndpoint.put(Event.Type.LINK_REMOTE_CLOSE, link);
+                if (detach.getClosed()) {
+                    _connectionEndpoint.put(Event.Type.LINK_REMOTE_CLOSE, link);
+                } else {
+                    _connectionEndpoint.put(Event.Type.LINK_REMOTE_DETACH, link);
+                }
                 transportLink.clearRemoteHandle();
                 link.setRemoteState(EndpointState.CLOSED);
                 if(detach.getError() != null)
@@ -1231,17 +1250,40 @@ public class TransportImpl extends EndpointImpl
         return _closeReceived;
     }
 
+    void put(Event.Type type, Object context) {
+        if (_connectionEndpoint != null) {
+            _connectionEndpoint.put(type, context);
+        }
+    }
+
+    private void maybePostClosed()
+    {
+        if (postedHeadClosed && postedTailClosed) {
+            put(Event.Type.TRANSPORT_CLOSED, this);
+        }
+    }
+
     @Override
     public void closed(TransportException error)
     {
         if (!_closeReceived || error != null) {
             if (error == null) {
-                _tail_error = new TransportException("connection aborted");
+                _condition = new ErrorCondition(ConnectionError.FRAMING_ERROR,
+                                               "connection aborted");
             } else {
-                _tail_error = error;
+                _condition = new ErrorCondition(ConnectionError.FRAMING_ERROR,
+                                                error.toString());
             }
             _head_closed = true;
         }
+        if (_condition != null) {
+            put(Event.Type.TRANSPORT_ERROR, this);
+        }
+        if (!postedTailClosed) {
+            put(Event.Type.TRANSPORT_TAIL_CLOSED, this);
+            postedTailClosed = true;
+            maybePostClosed();
+        }
     }
 
     @Override
@@ -1346,6 +1388,13 @@ public class TransportImpl extends EndpointImpl
     {
         init();
         _outputProcessor.pop(bytes);
+
+        int p = pending();
+        if (p < 0 && !postedHeadClosed) {
+            put(Event.Type.TRANSPORT_HEAD_CLOSED, this);
+            postedHeadClosed = true;
+            maybePostClosed();
+        }
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
index ff9fbbe..6ae75a7 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
@@ -26,7 +26,7 @@ package org.apache.qpid.proton.messenger.impl;
  *
  */
 
-class Address
+public class Address
 {
 
     private String _address;
@@ -38,13 +38,7 @@ class Address
     private String _port;
     private String _name;
 
-    public Address(String address)
-    {
-        _address = address;
-        parse();
-    }
-
-    private void parse()
+    public void clear()
     {
         _passive = false;
         _scheme = null;
@@ -53,21 +47,30 @@ class Address
         _host = null;
         _port = null;
         _name = null;
+    }
+
+    public Address()
+    {
+        clear();
+    }
 
+    public Address(String address)
+    {
+        clear();
         int start = 0;
-        int schemeEnd = _address.indexOf("://", start);
+        int schemeEnd = address.indexOf("://", start);
         if (schemeEnd >= 0) {
-            _scheme = _address.substring(start, schemeEnd);
+            _scheme = address.substring(start, schemeEnd);
             start = schemeEnd + 3;
         }
 
         String uphp;
-        int slash = _address.indexOf("/", start);
-        if (slash > 0) {
-            uphp = _address.substring(start, slash);
-            _name = _address.substring(slash + 1);
+        int slash = address.indexOf("/", start);
+        if (slash >= 0) {
+            uphp = address.substring(start, slash);
+            _name = address.substring(slash + 1);
         } else {
-            uphp = _address.substring(start);
+            uphp = address.substring(start);
         }
 
         String hp;
@@ -115,7 +118,18 @@ class Address
 
     public String toString()
     {
-        return _address;
+        String  str = new String();
+        if (_scheme != null) str += _scheme + "://";
+        if (_user != null) str += _user;
+        if (_pass != null) str += ":" + _pass;
+        if (_user != null || _pass != null) str += "@";
+        if (_host != null) {
+            if (_host.contains(":")) str += "[" + _host + "]";
+            else str += _host;
+        }
+        if (_port != null) str += ":" + _port;
+        if (_name != null) str += "/" + _name;
+        return str;
     }
 
     public boolean isPassive()
@@ -168,4 +182,33 @@ class Address
         return _name;
     }
 
+    public void setScheme(String scheme)
+    {
+        _scheme= scheme;
+    }
+
+    public void setUser(String user)
+    {
+        _user= user;
+    }
+
+    public void setPass(String pass)
+    {
+        _pass= pass;
+    }
+
+    public void setHost(String host)
+    {
+        _host= host;
+    }
+
+    public void setPort(String port)
+    {
+        _port= port;
+    }
+
+    public void setName(String name)
+    {
+        _name= name;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/resources/cengine.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/cengine.py b/proton-j/src/main/resources/cengine.py
index c47ab58..102ee77 100644
--- a/proton-j/src/main/resources/cengine.py
+++ b/proton-j/src/main/resources/cengine.py
@@ -625,6 +625,10 @@ def pn_link_close(link):
   link.on_close()
   link.impl.close()
 
+def pn_link_detach(link):
+  link.on_close()
+  link.impl.detach()
+
 def pn_link_flow(link, n):
   link.impl.flow(n)
 
@@ -863,6 +867,7 @@ class pn_transport_wrapper:
 
   def __init__(self, impl):
     self.impl = impl
+    self.condition = pn_condition()
 
 def pn_transport():
   return wrap(Proton.transport(), pn_transport_wrapper)
@@ -940,15 +945,15 @@ def pn_transport_close_tail(trans):
 def pn_transport_closed(trans):
   return trans.impl.isClosed()
 
-from org.apache.qpid.proton.engine import Event
+def pn_transport_condition(trans):
+  trans.condition.decode(trans.impl.getCondition())
+  return trans.condition
 
-PN_EVENT_CATEGORY_CONNECTION = Event.Category.CONNECTION
-PN_EVENT_CATEGORY_SESSION = Event.Category.SESSION
-PN_EVENT_CATEGORY_LINK = Event.Category.LINK
-PN_EVENT_CATEGORY_DELIVERY = Event.Category.DELIVERY
-PN_EVENT_CATEGORY_TRANSPORT = Event.Category.TRANSPORT
+from org.apache.qpid.proton.engine import Event
 
 PN_CONNECTION_INIT = Event.Type.CONNECTION_INIT
+PN_CONNECTION_BOUND = Event.Type.CONNECTION_BOUND
+PN_CONNECTION_UNBOUND = Event.Type.CONNECTION_UNBOUND
 PN_CONNECTION_OPEN = Event.Type.CONNECTION_OPEN
 PN_CONNECTION_REMOTE_OPEN = Event.Type.CONNECTION_REMOTE_OPEN
 PN_CONNECTION_CLOSE = Event.Type.CONNECTION_CLOSE
@@ -965,10 +970,16 @@ PN_LINK_OPEN = Event.Type.LINK_OPEN
 PN_LINK_REMOTE_OPEN = Event.Type.LINK_REMOTE_OPEN
 PN_LINK_CLOSE = Event.Type.LINK_CLOSE
 PN_LINK_REMOTE_CLOSE = Event.Type.LINK_REMOTE_CLOSE
+PN_LINK_DETACH = Event.Type.LINK_DETACH
+PN_LINK_REMOTE_DETACH = Event.Type.LINK_REMOTE_DETACH
 PN_LINK_FLOW = Event.Type.LINK_FLOW
 PN_LINK_FINAL = Event.Type.LINK_FINAL
 PN_DELIVERY = Event.Type.DELIVERY
 PN_TRANSPORT = Event.Type.TRANSPORT
+PN_TRANSPORT_ERROR = Event.Type.TRANSPORT_ERROR
+PN_TRANSPORT_HEAD_CLOSED = Event.Type.TRANSPORT_HEAD_CLOSED
+PN_TRANSPORT_TAIL_CLOSED = Event.Type.TRANSPORT_TAIL_CLOSED
+PN_TRANSPORT_CLOSED = Event.Type.TRANSPORT_CLOSED
 
 def pn_collector():
   return Proton.collector()
@@ -1000,8 +1011,33 @@ def pn_event_delivery(event):
 def pn_event_transport(event):
   return wrap(event.getTransport(), pn_transport_wrapper)
 
+from org.apache.qpid.proton.engine.impl import ConnectionImpl, SessionImpl, \
+  SenderImpl, ReceiverImpl, DeliveryImpl, TransportImpl
+
+J2C = {
+  ConnectionImpl: "pn_connection",
+  SessionImpl: "pn_session",
+  SenderImpl: "pn_link",
+  ReceiverImpl: "pn_link",
+  DeliveryImpl: "pn_delivery",
+  TransportImpl: "pn_transport"
+}
+
+wrappers = {
+  "pn_connection": lambda x: wrap(x, pn_connection_wrapper),
+  "pn_session": lambda x: wrap(x, pn_session_wrapper),
+  "pn_link": lambda x: wrap(x, pn_link_wrapper),
+  "pn_delivery": lambda x: wrap(x, pn_delivery_wrapper),
+  "pn_transport": lambda x: wrap(x, pn_transport_wrapper),
+  "pn_void": lambda x: x
+}
+
 def pn_event_class(event):
-  return event.getClass()
+  ctx = event.getContext()
+  return J2C.get(ctx.getClass(), "pn_void")
+
+def pn_event_context(event):
+  return wrappers[pn_event_class(event)](event.getContext())
 
 def pn_event_type(event):
   return event.getType()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/resources/cobject.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/cobject.py b/proton-j/src/main/resources/cobject.py
new file mode 100644
index 0000000..29cc06f
--- /dev/null
+++ b/proton-j/src/main/resources/cobject.py
@@ -0,0 +1,42 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+def pn_class_name(cls):
+  return cls
+
+def pn_void2py(obj):
+  return obj
+
+def pn_py2void(obj):
+    return obj
+
+def pn_cast_pn_connection(obj):
+    return obj
+
+def pn_cast_pn_session(obj):
+    return obj
+
+def pn_cast_pn_link(obj):
+    return obj
+
+def pn_cast_pn_delivery(obj):
+    return obj
+
+def pn_cast_pn_transport(obj):
+    return obj

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/resources/cproton.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/cproton.py b/proton-j/src/main/resources/cproton.py
index b91eb86..3d9a498 100644
--- a/proton-j/src/main/resources/cproton.py
+++ b/proton-j/src/main/resources/cproton.py
@@ -23,6 +23,11 @@ exposed to python via swig. This allows tests defined in python to run
 against both the C and Java protocol implementations.
 """
 
+# @todo(kgiusti) dynamically set these via filters in the pom.xml file
+PN_VERSION_MAJOR = 0
+PN_VERSION_MINOR = 0
+
+from cobject import *
 from cerror import *
 from ccodec import *
 from cengine import *
@@ -31,3 +36,4 @@ from cssl import *
 from cdriver import *
 from cmessenger import *
 from cmessage import *
+from curl import *

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/main/resources/curl.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/curl.py b/proton-j/src/main/resources/curl.py
new file mode 100644
index 0000000..d4d3d37
--- /dev/null
+++ b/proton-j/src/main/resources/curl.py
@@ -0,0 +1,47 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+from org.apache.qpid.proton.messenger.impl import Address
+
+def pn_url():
+    return Address()
+
+def pn_url_parse(urlstr):
+    return Address(urlstr)
+
+def pn_url_free(url): pass
+
+def pn_url_clear(url):
+    url.clear();
+
+def pn_url_str(url): return url.toString()
+
+def pn_url_get_scheme(url): return url.getScheme()
+def pn_url_get_username(url): return url.getUser()
+def pn_url_get_password(url): return url.getPass()
+def pn_url_get_host(url): return url.getHost() or None
+def pn_url_get_port(url): return url.getPort()
+def pn_url_get_path(url): return url.getName()
+
+def pn_url_set_scheme(url, value): url.setScheme(value)
+def pn_url_set_username(url, value): url.setUser(value)
+def pn_url_set_password(url, value): url.setPass(value)
+def pn_url_set_host(url, value): url.setHost(value)
+def pn_url_set_port(url, value): url.setPort(value)
+def pn_url_set_path(url, value): url.setName(value)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/test/java/org/apache/qpid/proton/amqp/BinaryTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/amqp/BinaryTest.java b/proton-j/src/test/java/org/apache/qpid/proton/amqp/BinaryTest.java
new file mode 100644
index 0000000..4ab4766
--- /dev/null
+++ b/proton-j/src/test/java/org/apache/qpid/proton/amqp/BinaryTest.java
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.proton.amqp;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+public class BinaryTest
+{
+
+    @Test
+    public void testNotEqualsWithDifferentTypeObject()
+    {
+        Binary bin = createSteppedValueBinary(10);
+
+        assertFalse("Objects should not be equal with different type", bin.equals("not-a-Binary"));
+    }
+
+    @Test
+    public void testEqualsWithItself()
+    {
+        Binary bin = createSteppedValueBinary(10);
+
+        assertTrue("Object should be equal to itself", bin.equals(bin));
+    }
+
+    @Test
+    public void testEqualsWithDifferentBinaryOfSameLengthAndContent()
+    {
+        int length = 10;
+        Binary bin1 = createSteppedValueBinary(length);
+        Binary bin2 = createSteppedValueBinary(length);
+
+        assertTrue("Objects should be equal", bin1.equals(bin2));
+        assertTrue("Objects should be equal", bin2.equals(bin1));
+    }
+
+    @Test
+    public void testEqualsWithDifferentLengthBinaryOfDifferentBytes()
+    {
+        int length1 = 10;
+        Binary bin1 = createSteppedValueBinary(length1);
+        Binary bin2 = createSteppedValueBinary(length1 + 1);
+
+        assertFalse("Objects should not be equal", bin1.equals(bin2));
+        assertFalse("Objects should not be equal", bin2.equals(bin1));
+    }
+
+    @Test
+    public void testEqualsWithDifferentLengthBinaryOfSameByte()
+    {
+        Binary bin1 = createNewRepeatedValueBinary(10, (byte) 1);
+        Binary bin2 = createNewRepeatedValueBinary(123, (byte) 1);
+
+        assertFalse("Objects should not be equal", bin1.equals(bin2));
+        assertFalse("Objects should not be equal", bin2.equals(bin1));
+    }
+
+    @Test
+    public void testEqualsWithDifferentContentBinary()
+    {
+        int length = 10;
+        Binary bin1 = createNewRepeatedValueBinary(length, (byte) 1);
+
+        Binary bin2 = createNewRepeatedValueBinary(length, (byte) 1);
+        bin2.getArray()[5] = (byte) 0;
+
+        assertFalse("Objects should not be equal", bin1.equals(bin2));
+        assertFalse("Objects should not be equal", bin2.equals(bin1));
+    }
+
+    private Binary createSteppedValueBinary(int length) {
+        byte[] bytes = new byte[length];
+        for (int i = 0; i < length; i++) {
+            bytes[i] = (byte) (length - i);
+        }
+
+        return new Binary(bytes);
+    }
+
+    private Binary createNewRepeatedValueBinary(int length, byte repeatedByte){
+        byte[] bytes = new byte[length];
+        Arrays.fill(bytes, repeatedByte);
+
+        return new Binary(bytes);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java b/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
new file mode 100644
index 0000000..550386a
--- /dev/null
+++ b/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
@@ -0,0 +1,148 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.proton.codec;
+
+import static org.junit.Assert.assertEquals;
+
+import java.lang.Character.UnicodeBlock;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Test;
+import org.apache.qpid.proton.amqp.messaging.AmqpValue;
+
+/**
+ * Test the encoding and decoding of {@link StringType} values.
+ */
+public class StringTypeTest
+{
+    private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
+
+    /**
+     * Loop over all the chars in given {@link UnicodeBlock}s and return a
+     * {@link Set <String>} containing all the possible values as their
+     * {@link String} values.
+     *
+     * @param blocks the {@link UnicodeBlock}s to loop over
+     * @return a {@link Set <String>} containing all the possible values as
+     * {@link String} values
+     */
+    private static Set<String> getAllStringsFromUnicodeBlocks(final UnicodeBlock... blocks)
+    {
+        final Set<UnicodeBlock> blockSet = new HashSet<UnicodeBlock>(Arrays.asList(blocks));
+        final Set<String> strings = new HashSet<String>();
+        for (int codePoint = 0; codePoint <= Character.MAX_CODE_POINT; codePoint++)
+        {
+            if (blockSet.contains(UnicodeBlock.of(codePoint)))
+            {
+                final int charCount = Character.charCount(codePoint);
+                final StringBuilder sb = new StringBuilder(
+                        charCount);
+                if (charCount == 1)
+                {
+                    sb.append(String.valueOf((char) codePoint));
+                }
+                else if (charCount == 2)
+                {
+                    //TODO: use Character.highSurrogate(codePoint) and Character.lowSurrogate(codePoint) when Java 7 is baseline
+                    char highSurrogate = (char) ((codePoint >>> 10) + ('\uD800' - (0x010000 >>> 10)));
+                    char lowSurrogate =  (char) ((codePoint & 0x3ff) + '\uDC00');
+
+                    sb.append(highSurrogate);
+                    sb.append(lowSurrogate);
+                }
+                else
+                {
+                    throw new IllegalArgumentException("Character.charCount of "
+                                                       + charCount + " not supported.");
+                }
+                strings.add(sb.toString());
+            }
+        }
+        return strings;
+    }
+
+
+    /**
+     * Test the encoding and decoding of various complicated Unicode characters
+     * which will end up as "surrogate pairs" when encoded to UTF-8
+     */
+    @Test
+    public void calculateUTF8Length()
+    {
+        for (final String input : generateTestData())
+        {
+            assertEquals("Incorrect string length calculated for string '"+input+"'",input.getBytes(CHARSET_UTF8).length, StringType.calculateUTF8Length(input));
+        }
+    }
+
+    /**
+     * Test the encoding and decoding of various  Unicode characters
+     */
+    @Test
+    public void encodeDecodeStrings()
+    {
+        final DecoderImpl decoder = new DecoderImpl();
+        final EncoderImpl encoder = new EncoderImpl(decoder);
+        AMQPDefinedTypes.registerAllTypes(decoder, encoder);
+        final ByteBuffer bb = ByteBuffer.allocate(16);
+
+        for (final String input : generateTestData())
+        {
+            bb.clear();
+            final AmqpValue inputValue = new AmqpValue(input);
+            encoder.setByteBuffer(bb);
+            encoder.writeObject(inputValue);
+            bb.clear();
+            decoder.setByteBuffer(bb);
+            final AmqpValue outputValue = (AmqpValue) decoder.readObject();
+            assertEquals("Failed to round trip String correctly: ", input, outputValue.getValue());
+        }
+    }
+
+    // build up some test data with a set of suitable Unicode characters
+    private Set<String> generateTestData()
+    {
+        return new HashSet<String>()
+            {
+                private static final long serialVersionUID = 7331717267070233454L;
+
+                {
+                    // non-surrogate pair blocks
+                    addAll(getAllStringsFromUnicodeBlocks(UnicodeBlock.BASIC_LATIN,
+                                                         UnicodeBlock.LATIN_1_SUPPLEMENT,
+                                                         UnicodeBlock.GREEK,
+                                                         UnicodeBlock.LETTERLIKE_SYMBOLS));
+                    // blocks with surrogate pairs
+                    //TODO: restore others when Java 7 is baseline
+                    addAll(getAllStringsFromUnicodeBlocks(/*UnicodeBlock.MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS,*/
+                                                         UnicodeBlock.MUSICAL_SYMBOLS,
+                                                         /*UnicodeBlock.EMOTICONS,*/
+                                                         /*UnicodeBlock.PLAYING_CARDS,*/
+                                                         UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_A,
+                                                         UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B));
+                }
+            };
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java b/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
index c0d2d92..4b233d5 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
@@ -6,24 +6,25 @@ import org.junit.Test;
 
 public class AddressTest {
 
-	private void testParse(String url, String scheme, String user, String pass, String host, String port, String name)
-	{
-		Address address = new Address(url);
-		assertEquals(scheme, address.getScheme());
-		assertEquals(user, address.getUser());
-		assertEquals(pass, address.getPass());
-		assertEquals(host, address.getHost());
-		assertEquals(port, address.getPort());
-	}
+    private void testParse(String url, String scheme, String user, String pass, String host, String port, String name)
+    {
+        Address address = new Address(url);
+        assertEquals(scheme, address.getScheme());
+        assertEquals(user, address.getUser());
+        assertEquals(pass, address.getPass());
+        assertEquals(host, address.getHost());
+        assertEquals(port, address.getPort());
+        assertEquals(url, address.toString());
+    }
 
-	@Test
-	public void addressTests()
-	{
-		testParse("host", null, null, null, "host", null, null);
-		testParse("host:423", null, null, null, "host", "423", null);
-		testParse("user@host", null, "user", null, "host", null, null);
-		testParse("user:1243^&^:pw@host:423", null, "user", "1243^&^:pw", "host", "423", null);
-		testParse("user:1243^&^:pw@host:423/Foo.bar:90087", null, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087");
+    @Test
+    public void addressTests()
+    {
+        testParse("host", null, null, null, "host", null, null);
+        testParse("host:423", null, null, null, "host", "423", null);
+        testParse("user@host", null, "user", null, "host", null, null);
+        testParse("user:1243^&^:pw@host:423", null, "user", "1243^&^:pw", "host", "423", null);
+        testParse("user:1243^&^:pw@host:423/Foo.bar:90087", null, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087");
         testParse("user:1243^&^:pw@host:423/Foo.bar:90087@somewhere", null, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087@somewhere");
         testParse("[::1]", null, null, null, "::1", null, null);
         testParse("[::1]:amqp", null, null, null, "::1", "amqp", null);
@@ -38,14 +39,13 @@ public class AddressTest {
         testParse("amqp://user@[1234:52:0:1260:f2de:f1ff:fe59:8f87]:amqp", "amqp", "user", null, "1234:52:0:1260:f2de:f1ff:fe59:8f87", "amqp", null);
         testParse("amqp://user:1243^&^:pw@[::1]:amqp", "amqp", "user", "1243^&^:pw", "::1", "amqp", null);
         testParse("amqp://user:1243^&^:pw@[::1]:amqp/Foo.bar:90087", "amqp", "user", "1243^&^:pw", "::1", "amqp", "Foo.bar:90087");
-		testParse("amqp://host", "amqp", null, null, "host", null, null);
-		testParse("amqp://user@host", "amqp", "user", null, "host", null, null);
-		testParse("amqp://user@host/path:%", "amqp", "user", null, "host", null, "path:%");
-		testParse("amqp://user@host:5674/path:%", "amqp", "user", null, "host", "5674", "path:%");
-		testParse("amqp://user@host/path:%", "amqp", "user", null, "host", null, "path:%");
-		testParse("amqp://bigbird@host/queue@host", "amqp", "bigbird", null, "host", null, "queue@host");
-		testParse("amqp://host/queue@host", "amqp", null, null, "host", null, "queue@host");
-		testParse("amqp://host:9765/queue@host", "amqp", null, null, "host", "9765", "queue@host");
-	}
-
+        testParse("amqp://host", "amqp", null, null, "host", null, null);
+        testParse("amqp://user@host", "amqp", "user", null, "host", null, null);
+        testParse("amqp://user@host/path:%", "amqp", "user", null, "host", null, "path:%");
+        testParse("amqp://user@host:5674/path:%", "amqp", "user", null, "host", "5674", "path:%");
+        testParse("amqp://user@host/path:%", "amqp", "user", null, "host", null, "path:%");
+        testParse("amqp://bigbird@host/queue@host", "amqp", "bigbird", null, "host", null, "queue@host");
+        testParse("amqp://host/queue@host", "amqp", null, null, "host", null, "queue@host");
+        testParse("amqp://host:9765/queue@host", "amqp", null, null, "host", "9765", "queue@host");
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/test/java/org/apache/qpid/proton/systemtests/EngineTestBase.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/EngineTestBase.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/EngineTestBase.java
new file mode 100644
index 0000000..7f1822c
--- /dev/null
+++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/EngineTestBase.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.proton.systemtests;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.util.logging.Logger;
+
+import org.apache.qpid.proton.amqp.messaging.Target;
+import org.apache.qpid.proton.engine.Endpoint;
+import org.apache.qpid.proton.engine.EndpointState;
+
+public abstract class EngineTestBase
+{
+    private static final Logger LOGGER = Logger.getLogger(EngineTestBase.class.getName());
+
+    private final TestLoggingHelper _testLoggingHelper = new TestLoggingHelper(LOGGER);
+    private final ProtonContainer _client = new ProtonContainer("clientContainer");
+    private final ProtonContainer _server = new ProtonContainer("serverContainer");
+
+    protected TestLoggingHelper getTestLoggingHelper()
+    {
+        return _testLoggingHelper;
+    }
+
+    protected ProtonContainer getClient()
+    {
+        return _client;
+    }
+
+    protected ProtonContainer getServer()
+    {
+        return _server;
+    }
+
+    protected void assertClientHasNothingToOutput()
+    {
+        assertEquals(0, getClient().transport.getOutputBuffer().remaining());
+        getClient().transport.outputConsumed();
+    }
+
+    protected void pumpServerToClient()
+    {
+        ByteBuffer serverBuffer = getServer().transport.getOutputBuffer();
+
+        getTestLoggingHelper().prettyPrint("          <<<" + TestLoggingHelper.SERVER_PREFIX + " ", serverBuffer);
+        assertTrue("Server expected to produce some output", serverBuffer.hasRemaining());
+
+        ByteBuffer clientBuffer = getClient().transport.getInputBuffer();
+
+        clientBuffer.put(serverBuffer);
+
+        assertEquals("Client expected to consume all server's output", 0, serverBuffer.remaining());
+
+        getClient().transport.processInput().checkIsOk();
+        getServer().transport.outputConsumed();
+    }
+
+    protected void pumpClientToServer()
+    {
+        ByteBuffer clientBuffer = getClient().transport.getOutputBuffer();
+
+        getTestLoggingHelper().prettyPrint(TestLoggingHelper.CLIENT_PREFIX + ">>> ", clientBuffer);
+        assertTrue("Client expected to produce some output", clientBuffer.hasRemaining());
+
+        ByteBuffer serverBuffer = getServer().transport.getInputBuffer();
+
+        serverBuffer.put(clientBuffer);
+
+        assertEquals("Server expected to consume all client's output", 0, clientBuffer.remaining());
+
+        getClient().transport.outputConsumed();
+        getServer().transport.processInput().checkIsOk();
+    }
+
+    protected void doOutputInputCycle() throws Exception
+    {
+        pumpClientToServer();
+
+        pumpServerToClient();
+    }
+
+    protected void assertEndpointState(Endpoint endpoint, EndpointState localState, EndpointState remoteState)
+    {
+        assertEquals(localState, endpoint.getLocalState());
+        assertEquals(remoteState, endpoint.getRemoteState());
+    }
+
+    protected void assertTerminusEquals(org.apache.qpid.proton.amqp.transport.Target expectedTarget, org.apache.qpid.proton.amqp.transport.Target actualTarget)
+    {
+        assertEquals(
+                ((Target)expectedTarget).getAddress(),
+                ((Target)actualTarget).getAddress());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/test/java/org/apache/qpid/proton/systemtests/FreeTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/FreeTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/FreeTest.java
new file mode 100644
index 0000000..7687206
--- /dev/null
+++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/FreeTest.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.proton.systemtests;
+
+import static java.util.EnumSet.of;
+import static org.apache.qpid.proton.engine.EndpointState.ACTIVE;
+import static org.apache.qpid.proton.engine.EndpointState.UNINITIALIZED;
+import static org.apache.qpid.proton.systemtests.TestLoggingHelper.bold;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+
+import java.util.logging.Logger;
+
+import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.messaging.Source;
+import org.apache.qpid.proton.amqp.messaging.Target;
+import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
+import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.engine.Session;
+import org.junit.Test;
+
+public class FreeTest extends EngineTestBase
+{
+    private static final Logger LOGGER = Logger.getLogger(FreeTest.class.getName());
+
+    @Test
+    public void testFreeConnectionWithMultipleSessionsAndSendersAndReceiversDoesNotThrowCME() throws Exception
+    {
+        LOGGER.fine(bold("======== About to create transports"));
+
+        getClient().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getClient().transport, TestLoggingHelper.CLIENT_PREFIX);
+
+        getServer().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getServer().transport, "            " + TestLoggingHelper.SERVER_PREFIX);
+
+        getClient().connection = Proton.connection();
+        getClient().transport.bind(getClient().connection);
+
+        getServer().connection = Proton.connection();
+        getServer().transport.bind(getServer().connection);
+
+
+
+        LOGGER.fine(bold("======== About to open connections"));
+        getClient().connection.open();
+        getServer().connection.open();
+
+        doOutputInputCycle();
+
+
+
+        LOGGER.fine(bold("======== About to open sessions"));
+        getClient().session = getClient().connection.session();
+        getClient().session.open();
+
+        Session clientSession2 = getClient().connection.session();
+        clientSession2.open();
+
+        pumpClientToServer();
+
+        getServer().session = getServer().connection.sessionHead(of(UNINITIALIZED), of(ACTIVE));
+        assertEndpointState(getServer().session, UNINITIALIZED, ACTIVE);
+
+        getServer().session.open();
+        assertEndpointState(getServer().session, ACTIVE, ACTIVE);
+
+        Session serverSession2 = getServer().connection.sessionHead(of(UNINITIALIZED), of(ACTIVE));
+        assertNotNull("Engine did not return expected second server session", serverSession2);
+        assertNotSame("Engine did not return expected second server session", serverSession2, getServer().session);
+        serverSession2.open();
+
+        pumpServerToClient();
+        assertEndpointState(getClient().session, ACTIVE, ACTIVE);
+        assertEndpointState(clientSession2, ACTIVE, ACTIVE);
+
+
+
+        LOGGER.fine(bold("======== About to create client senders"));
+
+        getClient().source = new Source();
+        getClient().source.setAddress(null);
+
+        getClient().target = new Target();
+        getClient().target.setAddress("myQueue");
+
+        getClient().sender = getClient().session.sender("sender1");
+        getClient().sender.setTarget(getClient().target);
+        getClient().sender.setSource(getClient().source);
+
+        getClient().sender.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+        getClient().sender.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+
+        assertEndpointState(getClient().sender, UNINITIALIZED, UNINITIALIZED);
+
+        getClient().sender.open();
+        assertEndpointState(getClient().sender, ACTIVE, UNINITIALIZED);
+
+
+        Sender clientSender2 = getClient().session.sender("sender2");
+        clientSender2.setTarget(getClient().target);
+        clientSender2.setSource(getClient().source);
+
+        clientSender2.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+        clientSender2.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+
+        assertEndpointState(clientSender2, UNINITIALIZED, UNINITIALIZED);
+
+        clientSender2.open();
+        assertEndpointState(clientSender2, ACTIVE, UNINITIALIZED);
+
+        pumpClientToServer();
+
+
+        LOGGER.fine(bold("======== About to set up server receivers"));
+
+        getServer().receiver = (Receiver) getServer().connection.linkHead(of(UNINITIALIZED), of(ACTIVE));
+        // Accept the settlement modes suggested by the client
+        getServer().receiver.setSenderSettleMode(getServer().receiver.getRemoteSenderSettleMode());
+        getServer().receiver.setReceiverSettleMode(getServer().receiver.getRemoteReceiverSettleMode());
+
+        org.apache.qpid.proton.amqp.transport.Target serverRemoteTarget = getServer().receiver.getRemoteTarget();
+        assertTerminusEquals(getClient().target, serverRemoteTarget);
+
+        getServer().receiver.setTarget(serverRemoteTarget);
+
+        assertEndpointState(getServer().receiver, UNINITIALIZED, ACTIVE);
+        getServer().receiver.open();
+
+        assertEndpointState(getServer().receiver, ACTIVE, ACTIVE);
+
+        Receiver serverReceiver2 = (Receiver) getServer().connection.linkHead(of(UNINITIALIZED), of(ACTIVE));
+        serverReceiver2.open();
+        assertEndpointState(serverReceiver2, ACTIVE, ACTIVE);
+
+        pumpServerToClient();
+        assertEndpointState(getClient().sender, ACTIVE, ACTIVE);
+        assertEndpointState(clientSender2, ACTIVE, ACTIVE);
+
+
+
+        LOGGER.fine(bold("======== About to create client receivers"));
+
+        Source src = new Source();
+        src.setAddress("myQueue");
+
+        Target tgt1 = new Target();
+        tgt1.setAddress("receiver1");
+
+        getClient().receiver = getClient().session.receiver("receiver1");
+        getClient().receiver.setSource(src);
+        getClient().receiver.setTarget(tgt1);
+
+        getClient().receiver.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+        getClient().receiver.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+
+        assertEndpointState(getClient().receiver, UNINITIALIZED, UNINITIALIZED);
+
+        getClient().receiver.open();
+        assertEndpointState(getClient().receiver, ACTIVE, UNINITIALIZED);
+
+
+        Target tgt2 = new Target();
+        tgt1.setAddress("receiver2");
+
+        Receiver clientReceiver2 = getClient().session.receiver("receiver2");
+        clientReceiver2.setSource(src);
+        clientReceiver2.setTarget(tgt2);
+
+        clientReceiver2.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+        clientReceiver2.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+
+        assertEndpointState(clientReceiver2, UNINITIALIZED, UNINITIALIZED);
+
+        clientReceiver2.open();
+        assertEndpointState(clientReceiver2, ACTIVE, UNINITIALIZED);
+
+        pumpClientToServer();
+
+
+
+        LOGGER.fine(bold("======== About to set up server senders"));
+
+        getServer().sender = (Sender) getServer().connection.linkHead(of(UNINITIALIZED), of(ACTIVE));
+        // Accept the settlement modes suggested by the client
+        getServer().sender.setSenderSettleMode(getServer().sender.getRemoteSenderSettleMode());
+        getServer().sender.setReceiverSettleMode(getServer().sender.getRemoteReceiverSettleMode());
+
+        org.apache.qpid.proton.amqp.transport.Target serverRemoteTarget2 = getServer().sender.getRemoteTarget();
+        assertTerminusEquals(tgt1, serverRemoteTarget2);
+
+        getServer().sender.setTarget(serverRemoteTarget2);
+
+        assertEndpointState(getServer().sender, UNINITIALIZED, ACTIVE);
+        getServer().sender.open();
+        assertEndpointState(getServer().sender, ACTIVE, ACTIVE);
+
+        Sender serverSender2 = (Sender) getServer().connection.linkHead(of(UNINITIALIZED), of(ACTIVE));
+
+        serverRemoteTarget2 = serverSender2.getRemoteTarget();
+        assertTerminusEquals(tgt2, serverRemoteTarget2);
+        serverSender2.setTarget(serverRemoteTarget2);
+        serverSender2.open();
+        assertEndpointState(serverSender2, ACTIVE, ACTIVE);
+
+        pumpServerToClient();
+        assertEndpointState(getClient().receiver, ACTIVE, ACTIVE);
+        assertEndpointState(clientReceiver2, ACTIVE, ACTIVE);
+
+
+
+        LOGGER.fine(bold("======== About to close and free client's connection"));
+
+        getClient().connection.close();
+        getClient().connection.free();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java
index 9c5dbb3..a24bbdd 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/ProtonEngineExampleTest.java
@@ -29,7 +29,6 @@ import static org.apache.qpid.proton.systemtests.TestLoggingHelper.bold;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 
-import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.logging.Logger;
 
@@ -42,8 +41,6 @@ import org.apache.qpid.proton.amqp.messaging.Target;
 import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
 import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
 import org.apache.qpid.proton.engine.Delivery;
-import org.apache.qpid.proton.engine.Endpoint;
-import org.apache.qpid.proton.engine.EndpointState;
 import org.apache.qpid.proton.engine.Receiver;
 import org.apache.qpid.proton.message.Message;
 import org.junit.Test;
@@ -64,84 +61,79 @@ import org.junit.Test;
  *
  * Does not illustrate use of the Messenger API.
  */
-public class ProtonEngineExampleTest
+public class ProtonEngineExampleTest extends EngineTestBase
 {
     private static final Logger LOGGER = Logger.getLogger(ProtonEngineExampleTest.class.getName());
 
     private static final int BUFFER_SIZE = 4096;
 
-    private TestLoggingHelper _testLoggingHelper = new TestLoggingHelper(LOGGER);
-
-    private final ProtonContainer _client = new ProtonContainer("clientContainer");
-    private final ProtonContainer _server = new ProtonContainer("serverContainer");
-
-    private final String _targetAddress = _server.containerId + "-link1-target";
+    private final String _targetAddress = getServer().containerId + "-link1-target";
 
     @Test
     public void test() throws Exception
     {
         LOGGER.fine(bold("======== About to create transports"));
 
-        _client.transport = Proton.transport();
-        ProtocolTracerEnabler.setProtocolTracer(_client.transport, TestLoggingHelper.CLIENT_PREFIX);
+        getClient().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getClient().transport, TestLoggingHelper.CLIENT_PREFIX);
 
-        _server.transport = Proton.transport();
-        ProtocolTracerEnabler.setProtocolTracer(_server.transport, "            " + TestLoggingHelper.SERVER_PREFIX);
+        getServer().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getServer().transport, "            " + TestLoggingHelper.SERVER_PREFIX);
 
         doOutputInputCycle();
 
-        _client.connection = Proton.connection();
-        _client.transport.bind(_client.connection);
+        getClient().connection = Proton.connection();
+        getClient().transport.bind(getClient().connection);
 
-        _server.connection = Proton.connection();
-        _server.transport.bind(_server.connection);
+        getServer().connection = Proton.connection();
+        getServer().transport.bind(getServer().connection);
 
 
 
         LOGGER.fine(bold("======== About to open connections"));
-        _client.connection.open();
-        _server.connection.open();
+        getClient().connection.open();
+        getServer().connection.open();
 
         doOutputInputCycle();
 
 
 
         LOGGER.fine(bold("======== About to open sessions"));
-        _client.session = _client.connection.session();
-        _client.session.open();
+        getClient().session = getClient().connection.session();
+        getClient().session.open();
 
         pumpClientToServer();
 
-        _server.session = _server.connection.sessionHead(of(UNINITIALIZED), of(ACTIVE));
-        assertEndpointState(_server.session, UNINITIALIZED, ACTIVE);
+        getServer().session = getServer().connection.sessionHead(of(UNINITIALIZED), of(ACTIVE));
+        assertEndpointState(getServer().session, UNINITIALIZED, ACTIVE);
 
-        _server.session.open();
-        assertEndpointState(_server.session, ACTIVE, ACTIVE);
+        getServer().session.open();
+        assertEndpointState(getServer().session, ACTIVE, ACTIVE);
 
         pumpServerToClient();
-        assertEndpointState(_client.session, ACTIVE, ACTIVE);
+        assertEndpointState(getClient().session, ACTIVE, ACTIVE);
 
 
 
         LOGGER.fine(bold("======== About to create sender"));
 
-        _client.source = new Source();
-        _client.source.setAddress(null);
+        getClient().source = new Source();
+        getClient().source.setAddress(null);
 
-        _client.target = new Target();
-        _client.target.setAddress(_targetAddress);
+        getClient().target = new Target();
+        getClient().target.setAddress(_targetAddress);
 
-        _client.sender = _client.session.sender("link1");
-        _client.sender.setTarget(_client.target);
-        _client.sender.setSource(_client.source);
+        getClient().sender = getClient().session.sender("link1");
+        getClient().sender.setTarget(getClient().target);
+        getClient().sender.setSource(getClient().source);
         // Exactly once delivery semantics
-        _client.sender.setSenderSettleMode(SenderSettleMode.UNSETTLED);
-        _client.sender.setReceiverSettleMode(ReceiverSettleMode.SECOND);
+        getClient().sender.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+        getClient().sender.setReceiverSettleMode(ReceiverSettleMode.SECOND);
 
-        assertEndpointState(_client.sender, UNINITIALIZED, UNINITIALIZED);
+        assertEndpointState(getClient().sender, UNINITIALIZED, UNINITIALIZED);
 
-        _client.sender.open();
-        assertEndpointState(_client.sender, ACTIVE, UNINITIALIZED);
+        getClient().sender.open();
+        assertEndpointState(getClient().sender, ACTIVE, UNINITIALIZED);
 
         pumpClientToServer();
 
@@ -152,46 +144,46 @@ public class ProtonEngineExampleTest
         // A real application would be interested in more states than simply ACTIVE, as there
         // exists the possibility that the link could have moved to another state already e.g. CLOSED.
         // (See pipelining).
-        _server.receiver = (Receiver) _server.connection.linkHead(of(UNINITIALIZED), of(ACTIVE));
+        getServer().receiver = (Receiver) getServer().connection.linkHead(of(UNINITIALIZED), of(ACTIVE));
         // Accept the settlement modes suggested by the client
-        _server.receiver.setSenderSettleMode(_server.receiver.getRemoteSenderSettleMode());
-        _server.receiver.setReceiverSettleMode(_server.receiver.getRemoteReceiverSettleMode());
+        getServer().receiver.setSenderSettleMode(getServer().receiver.getRemoteSenderSettleMode());
+        getServer().receiver.setReceiverSettleMode(getServer().receiver.getRemoteReceiverSettleMode());
 
-        org.apache.qpid.proton.amqp.transport.Target serverRemoteTarget = _server.receiver.getRemoteTarget();
-        assertTerminusEquals(_client.target, serverRemoteTarget);
+        org.apache.qpid.proton.amqp.transport.Target serverRemoteTarget = getServer().receiver.getRemoteTarget();
+        assertTerminusEquals(getClient().target, serverRemoteTarget);
 
-        _server.receiver.setTarget(applicationDeriveTarget(serverRemoteTarget));
+        getServer().receiver.setTarget(applicationDeriveTarget(serverRemoteTarget));
 
-        assertEndpointState(_server.receiver, UNINITIALIZED, ACTIVE);
-        _server.receiver.open();
+        assertEndpointState(getServer().receiver, UNINITIALIZED, ACTIVE);
+        getServer().receiver.open();
 
-        assertEndpointState(_server.receiver, ACTIVE, ACTIVE);
+        assertEndpointState(getServer().receiver, ACTIVE, ACTIVE);
 
         pumpServerToClient();
-        assertEndpointState(_client.sender, ACTIVE, ACTIVE);
+        assertEndpointState(getClient().sender, ACTIVE, ACTIVE);
 
-        _server.receiver.flow(1);
+        getServer().receiver.flow(1);
         pumpServerToClient();
 
 
         LOGGER.fine(bold("======== About to create a message and send it to the server"));
 
-        _client.message = Proton.message();
+        getClient().message = Proton.message();
         Section messageBody = new AmqpValue("Hello");
-        _client.message.setBody(messageBody);
-        _client.messageData = new byte[BUFFER_SIZE];
-        int lengthOfEncodedMessage = _client.message.encode(_client.messageData, 0, BUFFER_SIZE);
-        _testLoggingHelper.prettyPrint(TestLoggingHelper.MESSAGE_PREFIX, Arrays.copyOf(_client.messageData, lengthOfEncodedMessage));
+        getClient().message.setBody(messageBody);
+        getClient().messageData = new byte[BUFFER_SIZE];
+        int lengthOfEncodedMessage = getClient().message.encode(getClient().messageData, 0, BUFFER_SIZE);
+        getTestLoggingHelper().prettyPrint(TestLoggingHelper.MESSAGE_PREFIX, Arrays.copyOf(getClient().messageData, lengthOfEncodedMessage));
 
         byte[] deliveryTag = "delivery1".getBytes();
-        _client.delivery = _client.sender.delivery(deliveryTag);
-        int numberOfBytesAcceptedBySender = _client.sender.send(_client.messageData, 0, lengthOfEncodedMessage);
+        getClient().delivery = getClient().sender.delivery(deliveryTag);
+        int numberOfBytesAcceptedBySender = getClient().sender.send(getClient().messageData, 0, lengthOfEncodedMessage);
         assertEquals("For simplicity, assume the sender can accept all the data",
                      lengthOfEncodedMessage, numberOfBytesAcceptedBySender);
 
-        assertNull(_client.delivery.getLocalState());
+        assertNull(getClient().delivery.getLocalState());
 
-        boolean senderAdvanced = _client.sender.advance();
+        boolean senderAdvanced = getClient().sender.advance();
         assertTrue("sender has not advanced", senderAdvanced);
 
         pumpClientToServer();
@@ -199,106 +191,106 @@ public class ProtonEngineExampleTest
 
         LOGGER.fine(bold("======== About to process the message on the server"));
 
-        _server.delivery = _server.connection.getWorkHead();
+        getServer().delivery = getServer().connection.getWorkHead();
         assertEquals("The received delivery should be on our receiver",
-                _server.receiver, _server.delivery.getLink());
-        assertNull(_server.delivery.getLocalState());
-        assertNull(_server.delivery.getRemoteState());
+                getServer().receiver, getServer().delivery.getLink());
+        assertNull(getServer().delivery.getLocalState());
+        assertNull(getServer().delivery.getRemoteState());
 
-        assertFalse(_server.delivery.isPartial());
-        assertTrue(_server.delivery.isReadable());
+        assertFalse(getServer().delivery.isPartial());
+        assertTrue(getServer().delivery.isReadable());
 
-        _server.messageData = new byte[BUFFER_SIZE];
-        int numberOfBytesProducedByReceiver = _server.receiver.recv(_server.messageData, 0, BUFFER_SIZE);
+        getServer().messageData = new byte[BUFFER_SIZE];
+        int numberOfBytesProducedByReceiver = getServer().receiver.recv(getServer().messageData, 0, BUFFER_SIZE);
         assertEquals(numberOfBytesAcceptedBySender, numberOfBytesProducedByReceiver);
 
-        _server.message = Proton.message();
-        _server.message.decode(_server.messageData, 0, numberOfBytesProducedByReceiver);
+        getServer().message = Proton.message();
+        getServer().message.decode(getServer().messageData, 0, numberOfBytesProducedByReceiver);
 
-        boolean messageProcessed = applicationProcessMessage(_server.message);
+        boolean messageProcessed = applicationProcessMessage(getServer().message);
         assertTrue(messageProcessed);
 
-        _server.delivery.disposition(Accepted.getInstance());
-        assertEquals(Accepted.getInstance(), _server.delivery.getLocalState());
+        getServer().delivery.disposition(Accepted.getInstance());
+        assertEquals(Accepted.getInstance(), getServer().delivery.getLocalState());
 
         pumpServerToClient();
-        assertEquals(Accepted.getInstance(), _client.delivery.getRemoteState());
+        assertEquals(Accepted.getInstance(), getClient().delivery.getRemoteState());
 
 
         LOGGER.fine(bold("======== About to accept and settle the message on the client"));
 
-        Delivery clientDelivery = _client.connection.getWorkHead();
-        assertEquals(_client.delivery, clientDelivery);
+        Delivery clientDelivery = getClient().connection.getWorkHead();
+        assertEquals(getClient().delivery, clientDelivery);
         assertTrue(clientDelivery.isUpdated());
-        assertEquals(_client.sender, clientDelivery.getLink());
+        assertEquals(getClient().sender, clientDelivery.getLink());
         clientDelivery.disposition(clientDelivery.getRemoteState());
-        assertEquals(Accepted.getInstance(), _client.delivery.getLocalState());
+        assertEquals(Accepted.getInstance(), getClient().delivery.getLocalState());
 
         clientDelivery.settle();
-        assertNull("Now we've settled, the delivery should no longer be in the work list", _client.connection.getWorkHead());
+        assertNull("Now we've settled, the delivery should no longer be in the work list", getClient().connection.getWorkHead());
 
         pumpClientToServer();
 
 
         LOGGER.fine(bold("======== About to settle the message on the server"));
 
-        assertEquals(Accepted.getInstance(), _server.delivery.getRemoteState());
-        Delivery serverDelivery = _server.connection.getWorkHead();
-        assertEquals(_server.delivery, serverDelivery);
+        assertEquals(Accepted.getInstance(), getServer().delivery.getRemoteState());
+        Delivery serverDelivery = getServer().connection.getWorkHead();
+        assertEquals(getServer().delivery, serverDelivery);
         assertTrue(serverDelivery.isUpdated());
         assertTrue("Client should have already settled", serverDelivery.remotelySettled());
         serverDelivery.settle();
         assertTrue(serverDelivery.isSettled());
-        assertNull("Now we've settled, the delivery should no longer be in the work list", _server.connection.getWorkHead());
+        assertNull("Now we've settled, the delivery should no longer be in the work list", getServer().connection.getWorkHead());
 
         // Increment the receiver's credit so its ready for another message.
         // When using proton-c, this call is required in order to generate a Flow frame
         // (proton-j sends one even without it to eagerly restore the session incoming window).
-        _server.receiver.flow(1);
+        getServer().receiver.flow(1);
         pumpServerToClient();
 
 
         LOGGER.fine(bold("======== About to close client's sender"));
 
-        _client.sender.close();
+        getClient().sender.close();
 
         pumpClientToServer();
 
 
         LOGGER.fine(bold("======== Server about to process client's link closure"));
 
-        assertSame(_server.receiver, _server.connection.linkHead(of(ACTIVE), of(CLOSED)));
-        _server.receiver.close();
+        assertSame(getServer().receiver, getServer().connection.linkHead(of(ACTIVE), of(CLOSED)));
+        getServer().receiver.close();
 
         pumpServerToClient();
 
 
         LOGGER.fine(bold("======== About to close client's session"));
 
-        _client.session.close();
+        getClient().session.close();
 
         pumpClientToServer();
 
 
         LOGGER.fine(bold("======== Server about to process client's session closure"));
 
-        assertSame(_server.session, _server.connection.sessionHead(of(ACTIVE), of(CLOSED)));
-        _server.session.close();
+        assertSame(getServer().session, getServer().connection.sessionHead(of(ACTIVE), of(CLOSED)));
+        getServer().session.close();
 
         pumpServerToClient();
 
 
         LOGGER.fine(bold("======== About to close client's connection"));
 
-        _client.connection.close();
+        getClient().connection.close();
 
         pumpClientToServer();
 
 
         LOGGER.fine(bold("======== Server about to process client's connection closure"));
 
-        assertEquals(CLOSED, _server.connection.getRemoteState());
-        _server.connection.close();
+        assertEquals(CLOSED, getServer().connection.getRemoteState());
+        getServer().connection.close();
 
         pumpServerToClient();
 
@@ -331,66 +323,4 @@ public class ProtonEngineExampleTest
         Object messageBody = ((AmqpValue)message.getBody()).getValue();
         return "Hello".equals(messageBody);
     }
-
-    private void assertTerminusEquals(
-            org.apache.qpid.proton.amqp.transport.Target expectedTarget,
-            org.apache.qpid.proton.amqp.transport.Target actualTarget)
-    {
-        assertEquals(
-                ((Target)expectedTarget).getAddress(),
-                ((Target)actualTarget).getAddress());
-    }
-
-    private void assertEndpointState(Endpoint endpoint, EndpointState localState, EndpointState remoteState)
-    {
-        assertEquals(localState, endpoint.getLocalState());
-        assertEquals(remoteState, endpoint.getRemoteState());
-    }
-
-    private void doOutputInputCycle() throws Exception
-    {
-        pumpClientToServer();
-
-        pumpServerToClient();
-    }
-
-    private void pumpClientToServer()
-    {
-        ByteBuffer clientBuffer = _client.transport.getOutputBuffer();
-
-        _testLoggingHelper.prettyPrint(TestLoggingHelper.CLIENT_PREFIX + ">>> ", clientBuffer);
-        assertTrue("Client expected to produce some output", clientBuffer.hasRemaining());
-
-        ByteBuffer serverBuffer = _server.transport.getInputBuffer();
-
-        serverBuffer.put(clientBuffer);
-
-        assertEquals("Server expected to consume all client's output", 0, clientBuffer.remaining());
-
-        _client.transport.outputConsumed();
-        _server.transport.processInput().checkIsOk();
-    }
-
-    private void pumpServerToClient()
-    {
-        ByteBuffer serverBuffer = _server.transport.getOutputBuffer();
-
-        _testLoggingHelper.prettyPrint("          <<<" + TestLoggingHelper.SERVER_PREFIX + " ", serverBuffer);
-        assertTrue("Server expected to produce some output", serverBuffer.hasRemaining());
-
-        ByteBuffer clientBuffer = _client.transport.getInputBuffer();
-
-        clientBuffer.put(serverBuffer);
-
-        assertEquals("Client expected to consume all server's output", 0, serverBuffer.remaining());
-
-        _client.transport.processInput().checkIsOk();
-        _server.transport.outputConsumed();
-    }
-
-    private void assertClientHasNothingToOutput()
-    {
-        assertEquals(0, _client.transport.getOutputBuffer().remaining());
-        _client.transport.outputConsumed();
-    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/tests/python/proton_tests/__init__.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/__init__.py b/tests/python/proton_tests/__init__.py
index 1853da6..1cecf38 100644
--- a/tests/python/proton_tests/__init__.py
+++ b/tests/python/proton_tests/__init__.py
@@ -26,4 +26,4 @@ import proton_tests.transport
 import proton_tests.ssl
 import proton_tests.interop
 import proton_tests.soak
-
+import proton_tests.url

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/tests/python/proton_tests/engine.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/engine.py b/tests/python/proton_tests/engine.py
index 44157e7..c821107 100644
--- a/tests/python/proton_tests/engine.py
+++ b/tests/python/proton_tests/engine.py
@@ -2101,6 +2101,11 @@ class CollectorTest(Test):
 
     assert False, "actual events %s did not match any of the expected sequences: %s" % (events, sequences)
 
+  def expect_until(self, *types):
+    events = self.drain()
+    etypes = tuple([e.type for e in events[-len(types):]])
+    assert etypes == types, "actual events %s did not end in expect sequence: %s" % (events, types)
+
 class EventTest(CollectorTest):
 
   def teardown(self):
@@ -2150,8 +2155,8 @@ class EventTest(CollectorTest):
     self.pump()
     c1.free()
     c1._transport.unbind()
-    self.expect(Event.SESSION_FINAL, Event.LINK_FINAL, Event.SESSION_FINAL,
-                Event.CONNECTION_FINAL)
+    self.expect(Event.CONNECTION_UNBOUND, Event.SESSION_FINAL, Event.LINK_FINAL,
+                Event.SESSION_FINAL, Event.CONNECTION_FINAL)
 
   def testConnectionINIT_FINAL(self):
     c = Connection()
@@ -2215,8 +2220,8 @@ class EventTest(CollectorTest):
     self.expect(Event.LINK_REMOTE_OPEN, Event.DELIVERY)
     rcv.session.connection._transport.unbind()
     rcv.session.connection.free()
-    self.expect(Event.TRANSPORT, Event.LINK_FINAL, Event.SESSION_FINAL,
-                Event.CONNECTION_FINAL)
+    self.expect(Event.CONNECTION_UNBOUND, Event.TRANSPORT, Event.LINK_FINAL,
+                Event.SESSION_FINAL, Event.CONNECTION_FINAL)
 
   def testDeliveryEventsDisp(self):
     snd, rcv = self.testFlowEvents()
@@ -2233,7 +2238,85 @@ class EventTest(CollectorTest):
     rdlv.update(Delivery.ACCEPTED)
     self.pump()
     event = self.expect(Event.DELIVERY)
-    assert event.delivery == dlv
+    assert event.context == dlv
+
+  def testConnectionBOUND_UNBOUND(self):
+    c = Connection()
+    c.collect(self.collector)
+    self.expect(Event.CONNECTION_INIT)
+    t = Transport()
+    t.bind(c)
+    self.expect(Event.CONNECTION_BOUND)
+    t.unbind()
+    self.expect(Event.CONNECTION_UNBOUND, Event.TRANSPORT)
+
+  def testTransportERROR_CLOSE(self):
+    c = Connection()
+    c.collect(self.collector)
+    self.expect(Event.CONNECTION_INIT)
+    t = Transport()
+    t.bind(c)
+    self.expect(Event.CONNECTION_BOUND)
+    assert t.condition is None
+    t.push("asdf")
+    self.expect(Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED)
+    assert t.condition is not None
+    assert t.condition.name == "amqp:connection:framing-error"
+    assert "AMQP header mismatch" in t.condition.description
+    p = t.pending()
+    assert p > 0
+    t.pop(p)
+    self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+  def testTransportCLOSED(self):
+    c = Connection()
+    c.collect(self.collector)
+    self.expect(Event.CONNECTION_INIT)
+    t = Transport()
+    t.bind(c)
+    c.open()
+
+    self.expect(Event.CONNECTION_BOUND, Event.CONNECTION_OPEN, Event.TRANSPORT)
+
+    c2 = Connection()
+    t2 = Transport()
+    t2.bind(c2)
+    c2.open()
+    c2.close()
+
+    pump(t, t2)
+
+    self.expect(Event.CONNECTION_REMOTE_OPEN, Event.CONNECTION_REMOTE_CLOSE,
+                Event.TRANSPORT_TAIL_CLOSED)
+
+    c.close()
+
+    pump(t, t2)
+
+    self.expect(Event.CONNECTION_CLOSE, Event.TRANSPORT,
+                Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+  def testLinkDetach(self):
+    c1 = Connection()
+    c1.collect(self.collector)
+    t1 = Transport()
+    t1.bind(c1)
+    c1.open()
+    s1 = c1.session()
+    s1.open()
+    l1 = s1.sender("asdf")
+    l1.open()
+    l1.detach()
+    self.expect_until(Event.LINK_DETACH, Event.TRANSPORT)
+
+    c2 = Connection()
+    c2.collect(self.collector)
+    t2 = Transport()
+    t2.bind(c2)
+
+    pump(t1, t2)
+
+    self.expect_until(Event.LINK_REMOTE_DETACH)
 
 class PeerTest(CollectorTest):
 
@@ -2255,7 +2338,8 @@ class TeardownLeakTest(PeerTest):
 
   def doLeak(self, local, remote):
     self.connection.open()
-    self.expect(Event.CONNECTION_INIT, Event.CONNECTION_OPEN, Event.TRANSPORT)
+    self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+                Event.CONNECTION_OPEN, Event.TRANSPORT)
 
     ssn = self.connection.session()
     ssn.open()
@@ -2294,19 +2378,23 @@ class TeardownLeakTest(PeerTest):
     self.pump()
 
     if remote:
-      self.expect_oneof((Event.LINK_REMOTE_CLOSE, Event.SESSION_REMOTE_CLOSE,
-                         Event.CONNECTION_REMOTE_CLOSE),
-                        (Event.LINK_REMOTE_CLOSE, Event.LINK_FINAL,
-                         Event.SESSION_REMOTE_CLOSE,
-                         Event.CONNECTION_REMOTE_CLOSE))
+      self.expect_oneof((Event.TRANSPORT_HEAD_CLOSED, Event.LINK_REMOTE_CLOSE,
+                         Event.SESSION_REMOTE_CLOSE, Event.CONNECTION_REMOTE_CLOSE,
+                         Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_CLOSED),
+                        (Event.TRANSPORT_HEAD_CLOSED, Event.LINK_REMOTE_CLOSE,
+                         Event.LINK_FINAL, Event.SESSION_REMOTE_CLOSE,
+                         Event.CONNECTION_REMOTE_CLOSE, Event.TRANSPORT_TAIL_CLOSED,
+                         Event.TRANSPORT_CLOSED))
     else:
-      self.expect(Event.SESSION_REMOTE_CLOSE, Event.CONNECTION_REMOTE_CLOSE)
+      self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.SESSION_REMOTE_CLOSE,
+                  Event.CONNECTION_REMOTE_CLOSE, Event.TRANSPORT_TAIL_CLOSED,
+                  Event.TRANSPORT_CLOSED)
 
     self.connection.free()
     self.transport.unbind()
 
-    self.expect_oneof((Event.LINK_FINAL, Event.SESSION_FINAL, Event.CONNECTION_FINAL),
-                      (Event.SESSION_FINAL, Event.CONNECTION_FINAL))
+    self.expect_oneof((Event.LINK_FINAL, Event.CONNECTION_UNBOUND, Event.SESSION_FINAL, Event.CONNECTION_FINAL),
+                      (Event.CONNECTION_UNBOUND, Event.LINK_FINAL, Event.SESSION_FINAL, Event.CONNECTION_FINAL))
 
   def testLocalRemoteLeak(self):
     self.doLeak(True, True)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/92b8098c/tests/python/proton_tests/scratch.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/scratch.py b/tests/python/proton_tests/scratch.py
new file mode 100644
index 0000000..7e8ae5b
--- /dev/null
+++ b/tests/python/proton_tests/scratch.py
@@ -0,0 +1,44 @@
+  def xxx_test_reopen_on_same_session(self):
+    ssn1 = self.snd.session
+    ssn2 = self.rcv.session
+
+    self.snd.open()
+    self.rcv.open()
+    self.pump()
+
+    assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+    assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+    self.snd.close()
+    self.rcv.close()
+    self.pump()
+
+    assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+    assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+    print self.snd._link
+    self.snd = ssn1.sender("test-link")
+    print self.snd._link
+    self.rcv = ssn2.receiver("test-link")
+    self.snd.open()
+    self.rcv.open()
+    self.pump()
+
+    assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+    assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+class SessionPipelineTest(PeerTest):
+
+  def xxx_test(self):
+    self.connection.open()
+    self.peer.open()
+    self.pump()
+    ssn = self.connection.session()
+    ssn.open()
+    self.pump()
+    peer_ssn = self.peer.session_head(0)
+    ssn.close()
+    self.pump()
+    peer_ssn.close()
+    self.peer.close()
+    self.pump()


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


[33/51] [abbrv] qpid-proton git commit: Refactor JavaScript binding from a single ludicrously huge binding.js into a set of sub-modules that should hopefully make maintenance much simpler

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
deleted file mode 100644
index 05e08a8..0000000
--- a/proton-c/bindings/javascript/binding.js
+++ /dev/null
@@ -1,4129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/**
- * This file provides a JavaScript wrapper around the Proton Messenger API.
- * It will be used to wrap the emscripten compiled proton-c code and be minified by
- * the Closure compiler, so all comments will be stripped from the actual library.
- * <p>
- * This JavaScript wrapper provides a somewhat more idiomatic object oriented
- * interface which abstracts the low-level emscripten based implementation details
- * from client code. Any similarities to the Proton Python binding are deliberate.
- * @file
- */
-
-/**
- * The Module Object is exported by emscripten for all execution platforms, we
- * use it as a namespace to allow us to selectively export only what we wish to
- * be publicly visible from this package/module. We will use the associative
- * array form for declaring exported properties to prevent the Closure compiler
- * from minifying e.g. <pre>Module['Messenger'] = ...</pre>
- * Exported Objects can be used in client code using a more convenient namespace, e.g.:
- * <pre>
- * proton = require('qpid-proton');
- * var messenger = new proton.Messenger();
- * var message = new proton.Message();
- * </pre>
- * @namespace proton
- */
-
-var Module = {
-    // Prevent emscripten runtime exiting, we will be enabling network callbacks.
-    'noExitRuntime' : true,
-};
-
-/*****************************************************************************/
-/*                                                                           */
-/*                                   Status                                  */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * Export Status Enum, avoiding minification.
- * @enum
- * @alias Status
- * @memberof proton
- */
-Module['Status'] = {
-    /** PN_STATUS_UNKNOWN */  'UNKNOWN':  0, // The tracker is unknown.
-    /** PN_STATUS_PENDING */  'PENDING':  1, // The message is in flight.
-                                             // For outgoing messages, use messenger.isBuffered()
-                                             // to see if it has been sent or not.
-    /** PN_STATUS_ACCEPTED */ 'ACCEPTED': 2, // The message was accepted.
-    /** PN_STATUS_REJECTED */ 'REJECTED': 3, // The message was rejected.
-    /** PN_STATUS_RELEASED */ 'RELEASED': 4, // The message was released.
-    /** PN_STATUS_MODIFIED */ 'MODIFIED': 5, // The message was modified.
-    /** PN_STATUS_ABORTED */  'ABORTED':  6, // The message was aborted.
-    /** PN_STATUS_SETTLED */  'SETTLED':  7  // The remote party has settled the message.
-};
-
-
-/*****************************************************************************/
-/*                                                                           */
-/*                                   Error                                   */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * Export Error Enum, avoiding minification.
- * @enum
- * @alias Error
- * @memberof proton
- */
-Module['Error'] = {
-    /** PN_EOS */        'EOS':        -1,
-    /** PN_ERR */        'ERR':        -2,
-    /** PN_OVERFLOW */   'OVERFLOW':   -3,
-    /** PN_UNDERFLOW */  'UNDERFLOW':  -4,
-    /** PN_STATE_ERR */  'STATE_ERR':  -5,
-    /** PN_ARG_ERR */    'ARG_ERR':    -6,
-    /** PN_TIMEOUT */    'TIMEOUT':    -7,
-    /** PN_INTR */       'INTR':       -8,
-    /** PN_INPROGRESS */ 'INPROGRESS': -9
-};
-
-
-/*****************************************************************************/
-/*                                                                           */
-/*                               MessengerError                              */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * Constructs a proton.MessengerError instance.
- * @classdesc This class is a subclass of Error.
- * @constructor proton.MessengerError
- * @param {string} message the error message.
- */
-Module['MessengerError'] = function(message) { // MessengerError constructor.
-    this.name = "MessengerError";
-    this.message = (message || "");
-};
-
-Module['MessengerError'].prototype = new Error();
-Module['MessengerError'].prototype.constructor = Module['MessengerError'];
-
-Module['MessengerError'].prototype.toString = function() {
-    return this.name + ': ' + this.message
-};
-
-
-/*****************************************************************************/
-/*                                                                           */
-/*                                MessageError                               */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * Constructs a proton.MessageError instance.
- * @classdesc This class is a subclass of Error.
- * @constructor proton.MessageError
- * @param {string} message the error message.
- */
-Module['MessageError'] = function(message) { // MessageError constructor.
-    this.name = "MessageError";
-    this.message = (message || "");
-};
-
-Module['MessageError'].prototype = new Error();
-Module['MessageError'].prototype.constructor = Module['MessageError'];
-
-Module['MessageError'].prototype.toString = function() {
-    return this.name + ': ' + this.message
-};
-
-
-/*****************************************************************************/
-/*                                                                           */
-/*                                  DataError                                */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * Constructs a proton.DataError instance.
- * @classdesc This class is a subclass of Error.
- * @constructor proton.DataError
- * @param {string} message the error message.
- */
-Module['DataError'] = function(message) { // DataError constructor.
-    this.name = "DataError";
-    this.message = (message || "");
-};
-
-Module['DataError'].prototype = new Error();
-Module['DataError'].prototype.constructor = Module['DataError'];
-
-Module['DataError'].prototype.toString = function() {
-    return this.name + ': ' + this.message
-};
-
-
-/*****************************************************************************/
-/*                                                                           */
-/*                                 Messenger                                 */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * Constructs a proton.Messenger instance giving it an (optional) name. If name
- * is supplied that will be used as the name of the Messenger, otherwise a UUID
- * will be used. The Messenger is initialised to non-blocking mode as it makes
- * little sense to have blocking behaviour in a JavaScript implementation.
- * @classdesc This class is
- * @constructor proton.Messenger
- * @param {string} name the name of this Messenger instance.
- */
-Module['Messenger'] = function(name) { // Messenger Constructor.
-    /**
-     * The emscripten idiom below is used in a number of places in the JavaScript
-     * bindings to map JavaScript Strings to C style strings. ALLOC_STACK will
-     * increase the stack and place the item there. When the stack is next restored
-     * (by calling Runtime.stackRestore()), that memory will be automatically
-     * freed. In C code compiled by emscripten saving and restoring of the stack
-     * is automatic, but if we want to us ALLOC_STACK from native JavaScript we
-     * need to explicitly save and restore the stack using Runtime.stackSave()
-     * and Runtime.stackRestore() or we will leak emscripten heap memory.
-     * See https://github.com/kripken/emscripten/wiki/Interacting-with-code
-     * The _pn_messenger constructor copies the char* passed to it.
-     */
-    var sp = Runtime.stackSave();
-    this._messenger = _pn_messenger(name ? allocate(intArrayFromString(name), 'i8', ALLOC_STACK) : 0);
-    Runtime.stackRestore(sp);
-
-    /**
-     * Initiate Messenger non-blocking mode. For JavaScript we make this the
-     * default behaviour and don't export this method because JavaScript is
-     * fundamentally an asynchronous non-blocking execution environment.
-     */
-    _pn_messenger_set_blocking(this._messenger, false);
-
-    // Subscriptions that haven't yet completed, used for managing subscribe events.
-    this._pendingSubscriptions = [];
-
-    // Used in the Event registration mechanism (in the 'on' and 'emit' methods).
-    this._callbacks = {};
-
-    // This call ensures that the emscripten network callback functions are initialised.
-    Module.EventDispatch.registerMessenger(this);
-
-
-    // TODO improve error handling mechanism.
-    /*
-     * The emscripten websocket error event could get triggered by any Messenger
-     * and it's hard to determine which one without knowing which file descriptors
-     * are associated with which instance. As a workaround we set the _checkErrors
-     * flag when we call put or subscribe and reset it when work succeeds.
-     */
-    this._checkErrors = false;
-
-    /**
-     * TODO update to handle multiple Messenger instances
-     * Handle the emscripten websocket error and use it to trigger a MessengerError
-     * Note that the emscripten websocket error passes an array containing the
-     * file descriptor, the errno and the message, we just use the message here.
-     */
-    var that = this;
-    Module['websocket']['on']('error', function(error) {
-
-console.log("Module['websocket']['on'] caller is " + arguments.callee.caller.toString());
-
-console.log("that._checkErrors = " + that._checkErrors);
-console.log("error = " + error);
-        if (that._checkErrors) {
-            that._emit('error', new Module['MessengerError'](error[2]));
-        }
-    });
-};
-
-Module['Messenger'].PN_CUMULATIVE = 0x1; // Protected Class attribute.
-
-// Expose prototype as a variable to make method declarations less verbose.
-var _Messenger_ = Module['Messenger'].prototype;
-
-// ************************* Protected methods ********************************
-
-// We use the dot notation rather than associative array form for protected
-// methods so they are visible to this "package", but the Closure compiler will
-// minify and obfuscate names, effectively making a defacto "protected" method.
-
-/**
- * This helper method checks the supplied error code, converts it into an
- * exception and throws the exception. This method will try to use the message
- * populated in pn_messenger_error(), if present, but if not it will fall
- * back to using the basic error code rendering from pn_code().
- * @param code the error code to check.
- */
-_Messenger_._check = function(code) {
-    if (code < 0) {
-        if (code === Module['Error']['INPROGRESS']) {
-            return code;
-        }
-
-        var errno = this['getErrno']();
-        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
-
-        if (this._callbacks['error']) {
-            this._emit('error', new Module['MessengerError'](message));
-        } else {
-            throw new Module['MessengerError'](message);
-        }
-    } else {
-        return code;
-    }
-};
-
-/**
- * Invokes the callbacks registered for a specified event.
- * @method _emit
- * @memberof! proton.Messenger#
- * @param event the event we want to emit.
- * @param param the parameter we'd like to pass to the event callback.
- */
-_Messenger_._emit = function(event, param) {
-    var callbacks = this._callbacks[event];
-    if (callbacks) {
-        for (var i = 0; i < callbacks.length; i++) {
-            var callback = callbacks[i];
-            if ('function' === typeof callback) {
-                callback.call(this, param);
-            }
-        }
-    }
-};
-
-/**
- * Checks any pending subscriptions and when a source address becomes available
- * emit a subscription event passing the Subscription that triggered the event.
- * Note that this doesn't seem to work for listen/bind style subscriptions,
- * that is to say subscriptions of the form amqp://~0.0.0.0 don't know why?
- */
-_Messenger_._checkSubscriptions = function() {
-    // Check for completed subscriptions, and emit subscribe event.
-    var subscriptions = this._pendingSubscriptions;
-    if (subscriptions.length) {
-        var pending = []; // Array of any subscriptions that remain pending.
-        for (var j = 0; j < subscriptions.length; j++) {
-            subscription = subscriptions[j];
-            if (subscription['getAddress']()) {
-                this._emit('subscription', subscription);
-            } else {
-                pending.push(subscription);
-            }
-        }
-        this._pendingSubscriptions = pending;
-    }
-};
-
-
-// *************************** Public methods *****************************
-
-/**
- * N.B. The following methods are not exported by the JavaScript Messenger
- * binding for reasons described below.
- *
- * For these methods it is expected that security would be implemented via
- * a secure WebSocket. TODO what happens if we decide to implement TCP sockets
- * via Node.js net library. If we do that we may want to compile OpenSSL
- * using emscripten and include these methods.
- * pn_messenger_set_certificate()
- * pn_messenger_get_certificate()
- * pn_messenger_set_private_key()
- * pn_messenger_get_private_key()
- * pn_messenger_set_password()
- * pn_messenger_get_password()
- * pn_messenger_set_trusted_certificates()
- * pn_messenger_get_trusted_certificates()
- *
- * For these methods the implementation is fairly meaningless because JavaScript
- * is a fundamentally asynchronous non-blocking environment.
- * pn_messenger_set_timeout()
- * pn_messenger_set_blocking()
- * pn_messenger_interrupt()
- * pn_messenger_send() // Not sure if this is useful in JavaScript.
- */
-
-/**
- * Registers a listener callback for a specified event.
- * @method on
- * @memberof! proton.Messenger#
- * @param event the event we want to listen for.
- * @param callback the callback function to be registered for the specified event.
- */
-_Messenger_['on'] = function(event, callback) {
-    if ('function' === typeof callback) {
-        if (!this._callbacks[event]) {
-            this._callbacks[event] = [];
-        }
-
-        this._callbacks[event].push(callback);
-    }
-};
-
-/**
- * Removes a listener callback for a specified event.
- * @method removeListener
- * @memberof! proton.Messenger#
- * @param event the event we want to detach from.
- * @param callback the callback function to be removed for the specified event.
- *        if no callback is specified all callbacks are removed for the event.
- */
-_Messenger_['removeListener'] = function(event, callback) {
-    if (callback) {
-        var callbacks = this._callbacks[event];
-        if ('function' === typeof callback && callbacks) {
-            // Search for the specified callback.
-            for (var i = 0; i < callbacks.length; i++) {
-                if (callback === callbacks[i]) {
-                    // If we find the specified callback delete it and return.
-                    callbacks.splice(i, 1);
-                    return;
-                }
-            }
-        }
-    } else {
-        // If we call remove with no callback we remove all callbacks.
-        delete this._callbacks[event];
-    }
-};
-
-/**
- * Retrieves the name of a Messenger.
- * @method getName
- * @memberof! proton.Messenger#
- * @returns {string} the name of the messenger.
- */
-_Messenger_['getName'] = function() {
-    return Pointer_stringify(_pn_messenger_name(this._messenger));
-};
-
-/**
- * Retrieves the timeout for a Messenger.
- * @method getTimeout
- * @memberof! proton.Messenger#
- * @returns {number} zero because JavaScript is fundamentally non-blocking.
- */
-_Messenger_['getTimeout'] = function() {
-    return 0;
-};
-
-/**
- * Accessor for messenger blocking mode.
- * @method isBlocking
- * @memberof! proton.Messenger#
- * @returns {boolean} false because JavaScript is fundamentally non-blocking.
- */
-_Messenger_['isBlocking'] = function() {
-    return false;
-};
-
-/**
- * Free the Messenger. This will close all connections that are managed
- * by the Messenger. Call the stop method before destroying the Messenger.
- * <p>
- * N.B. This method has to be called explicitly in JavaScript as we can't
- * intercept finalisers, so we need to remember to free before removing refs.
- * @method free
- * @memberof! proton.Messenger#
- */
-_Messenger_['free'] = function() {
-    // This call ensures that the emscripten network callback functions are removed.
-    Module.EventDispatch.unregisterMessenger(this);
-    _pn_messenger_free(this._messenger);
-};
-
-/**
- * @method getErrno
- * @memberof! proton.Messenger#
- * @returns {number} the most recent error message code.
- */
-_Messenger_['getErrno'] = function() {
-    return _pn_messenger_errno(this._messenger);
-};
-
-/**
- * @method getError
- * @memberof! proton.Messenger#
- * @returns {string} the most recent error message as a String.
- */
-_Messenger_['getError'] = function() {
-    return Pointer_stringify(_pn_error_text(_pn_messenger_error(this._messenger)));
-};
-
-/**
- * Returns the size of the outgoing window that was set with setOutgoingWindow.
- * The default is 0.
- * @method getOutgoingWindow
- * @memberof! proton.Messenger#
- * @returns {number} the outgoing window size.
- */
-_Messenger_['getOutgoingWindow'] = function() {
-    return _pn_messenger_get_outgoing_window(this._messenger);
-};
-
-/**
- * Sets the outgoing tracking window for the Messenger. The Messenger will
- * track the remote status of this many outgoing deliveries after calling
- * send. Defaults to zero.
- * <p>
- * A Message enters this window when you call put() with the Message.
- * If your outgoing window size is n, and you call put() n+1 times, status
- * information will no longer be available for the first Message.
- * @method setOutgoingWindow
- * @memberof! proton.Messenger#
- * @param {number} window the size of the tracking window in messages.
- */
-_Messenger_['setOutgoingWindow'] = function(window) {
-    this._check(_pn_messenger_set_outgoing_window(this._messenger, window));
-};
-
-/**
- * Returns the size of the incoming window that was set with setIncomingWindow.
- * The default is 0.
- * @method getIncomingWindow
- * @memberof! proton.Messenger#
- * @returns {number} the incoming window size.
- */
-_Messenger_['getIncomingWindow'] = function() {
-    return _pn_messenger_get_incoming_window(this._messenger);
-};
-
-/**
- * Sets the incoming tracking window for the Messenger. The Messenger will
- * track the remote status of this many incoming deliveries after calling
- * send. Defaults to zero.
- * <p>
- * Messages enter this window only when you take them into your application
- * using get(). If your incoming window size is n, and you get() n+1 messages
- * without explicitly accepting or rejecting the oldest message, then the
- * Message that passes beyond the edge of the incoming window will be assigned
- * the default disposition of its link.
- * @method setIncomingWindow
- * @memberof! proton.Messenger#
- * @param {number} window the size of the tracking window in messages.
- */
-_Messenger_['setIncomingWindow'] = function(window) {
-    this._check(_pn_messenger_set_incoming_window(this._messenger, window));
-};
-
-/**
- * Currently a no-op placeholder. For future compatibility, do not send or
- * recv messages before starting the Messenger.
- * @method start
- * @memberof! proton.Messenger#
- */
-_Messenger_['start'] = function() {
-    this._check(_pn_messenger_start(this._messenger));
-};
-
-/**
- * Transitions the Messenger to an inactive state. An inactive Messenger
- * will not send or receive messages from its internal queues. A Messenger
- * should be stopped before being discarded to ensure a clean shutdown
- * handshake occurs on any internally managed connections.
- * <p>
- * The Messenger may require some time to stop if it is busy, and in that
- * case will return {@link proton.Error.INPROGRESS}. In that case, call isStopped
- * to see if it has fully stopped.
- * @method stop
- * @memberof! proton.Messenger#
- * @returns {@link proton.Error.INPROGRESS} if still busy.
- */
-_Messenger_['stop'] = function() {
-    return this._check(_pn_messenger_stop(this._messenger));
-};
-
-/**
- * Returns true iff a Messenger is in the stopped state.
- * @method isStopped
- * @memberof! proton.Messenger#
- * @returns {boolean} true iff a Messenger is in the stopped state.
- */
-_Messenger_['isStopped'] = function() {
-    return (_pn_messenger_stopped(this._messenger) > 0);
-};
-
-/**
- * Subscribes the Messenger to messages originating from the
- * specified source. The source is an address as specified in the
- * Messenger introduction with the following addition. If the
- * domain portion of the address begins with the '~' character, the
- * Messenger will interpret the domain as host/port, bind to it,
- * and listen for incoming messages. For example "~0.0.0.0",
- * "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
- * local interface and listen for incoming messages with the last
- * variant only permitting incoming SSL connections.
- * @method subscribe
- * @memberof! proton.Messenger#
- * @param {string} source the source address we're subscribing to.
- * @returns {Subscription} a subscription.
- */
-_Messenger_['subscribe'] = function(source) {
-    if (!source) {
-        this._check(Module['Error']['ARG_ERR']);
-    }
-    var sp = Runtime.stackSave();
-    this._checkErrors = true; // TODO improve error handling mechanism.
-    var subscription = _pn_messenger_subscribe(this._messenger,
-                                               allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
-    Runtime.stackRestore(sp);
-
-    if (!subscription) {
-        this._check(Module['Error']['ERR']);
-    }
-
-    subscription = new Subscription(subscription)
-    this._pendingSubscriptions.push(subscription);
-    return subscription;
-};
-
-/**
- * Places the content contained in the message onto the outgoing queue
- * of the Messenger. This method will never block, however it will send any
- * unblocked Messages in the outgoing queue immediately and leave any blocked
- * Messages remaining in the outgoing queue. The outgoing property may be
- * used to check the depth of the outgoing queue.
- * <p>
- * When the content in a given Message object is copied to the outgoing
- * message queue, you may then modify or discard the Message object
- * without having any impact on the content in the outgoing queue.
- * <p>
- * This method returns an outgoing tracker for the Message.  The tracker
- * can be used to determine the delivery status of the Message.
- * @method put
- * @memberof! proton.Messenger#
- * @param {proton.Message} message a Message to send.
- * @param {boolean} flush if this is set true or is undefined then messages are
- *        flushed (this is the default). If explicitly set to false then messages
- *        may not be sent immediately and might require an explicit call to work().
- *        This may be used to "batch up" messages and *may* be more efficient.
- * @returns {proton.Data.Long} a tracker.
- */
-_Messenger_['put'] = function(message, flush) {
-    flush = flush === false ? false : true;
-    message._preEncode();
-    this._checkErrors = true; // TODO improve error handling mechanism.
-    this._check(_pn_messenger_put(this._messenger, message._message));
-
-    // If flush is set invoke pn_messenger_work.
-    if (flush) {
-        _pn_messenger_work(this._messenger, 0);
-    }
-
-    // Getting the tracker is a little tricky as it is a 64 bit number. The way
-    // emscripten handles this is to return the low 32 bits directly and pass
-    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
-    // low/high pair around to methods that require a tracker.
-    var low = _pn_messenger_outgoing_tracker(this._messenger);
-    var high = Runtime.getTempRet0();
-    return new Data.Long(low, high);
-};
-
-/**
- * Gets the last known remote state of the delivery associated with the given tracker.
- * @method status
- * @memberof! proton.Messenger#
- * @param {proton.Data.Long} tracker the tracker whose status is to be retrieved.
- * @returns {proton.Status} one of None, PENDING, REJECTED, or ACCEPTED.
- */
-_Messenger_['status'] = function(tracker) {
-    if (tracker == null) {
-        var low = _pn_messenger_outgoing_tracker(this._messenger);
-        var high = Runtime.getTempRet0();
-        tracker = new Data.Long(low, high);
-    }
-
-    return _pn_messenger_status(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits());
-};
-
-/**
- * Checks if the delivery associated with the given tracker is still waiting to be sent.
- * @method isBuffered
- * @memberof! proton.Messenger#
- * @param {proton.Data.Long} tracker the tracker identifying the delivery.
- * @returns {boolean} true if delivery is still buffered.
- */
-_Messenger_['isBuffered'] = function(tracker) {
-    if (tracker == null) {
-        var low = _pn_messenger_outgoing_tracker(this._messenger);
-        var high = Runtime.getTempRet0();
-        tracker = new Data.Long(low, high);
-    }
-
-    return (_pn_messenger_buffered(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits()) > 0);
-};
-
-/**
- * Frees a Messenger from tracking the status associated with a given tracker.
- * If you don't supply a tracker, all outgoing messages up to the most recent
- * will be settled.
- * @method settle
- * @memberof! proton.Messenger#
- * @param {proton.Data.Long} tracker the tracker identifying the delivery.
- */
-_Messenger_['settle'] = function(tracker) {
-    // Getting the tracker is a little tricky as it is a 64 bit number. The way
-    // emscripten handles this is to return the low 32 bits directly and pass
-    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
-    // low/high pair around to methods that require a tracker.
-    var flags = 0;
-    if (tracker == null) {
-        var low = _pn_messenger_outgoing_tracker(this._messenger);
-        var high = Runtime.getTempRet0();
-        tracker = new Data.Long(low, high);
-        flags = Module['Messenger'].PN_CUMULATIVE;
-    }
-
-    this._check(_pn_messenger_settle(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
-};
-
-/**
- * Sends or receives any outstanding messages queued for a Messenger.
- * For JavaScript the only timeout that makes sense is 0 (do not block).
- * This method may also do I/O work other than sending and receiving messages.
- * For example, closing connections after messenger.stop() has been called.
- * @method work
- * @memberof! proton.Messenger#
- * @returns {boolean} true if there is work still to do, false otherwise.
- */
-_Messenger_['work'] = function() {
-    var err = _pn_messenger_work(this._messenger, 0);
-    if (err === Module['Error']['TIMEOUT']) {
-console.log("work = false");
-        return false;
-    } else {
-        this._checkErrors = false; // TODO improve error handling mechanism.
-        this._check(err);
-console.log("work = true");
-        return true;
-    }
-};
-
-/**
- * Receives up to limit messages into the incoming queue.  If no value for limit
- * is supplied, this call will receive as many messages as it can buffer internally.
- * @method recv
- * @memberof! proton.Messenger#
- * @param {number} limit the maximum number of messages to receive or -1 to to receive
- *        as many messages as it can buffer internally.
- */
-_Messenger_['recv'] = function(limit) {
-    this._check(_pn_messenger_recv(this._messenger, (limit ? limit : -1)));
-};
-
-/**
- * Returns the capacity of the incoming message queue of messenger. Note this
- * count does not include those messages already available on the incoming queue.
- * @method receiving
- * @memberof! proton.Messenger#
- * @returns {number} the message queue capacity.
- */
-_Messenger_['receiving'] = function() {
-    return _pn_messenger_receiving(this._messenger);
-};
-
-/**
- * Moves the message from the head of the incoming message queue into the
- * supplied message object. Any content in the message will be overwritten.
- * <p>
- * A tracker for the incoming Message is returned. The tracker can later be
- * used to communicate your acceptance or rejection of the Message.
- * @method get
- * @memberof! proton.Messenger#
- * @param {proton.Message} message the destination message object. If no Message
- *        object is supplied, the Message popped from the head of the queue is discarded.
- * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
- *        objects as strings. This can be useful as the data in Binary objects
- *        will be overwritten with subsequent calls to get, so they must be
- *        explicitly copied. Needless to say it is only safe to set this flag if
- *        you know that the data you are dealing with is actually a string, for
- *        example C/C++ applications often seem to encode strings as AMQP binary,
- *        a common cause of interoperability problems.
- * @returns {proton.Data.Long} a tracker for the incoming Message.
- */
-_Messenger_['get'] = function(message, decodeBinaryAsString) {
-    var impl = null;
-    if (message) {
-        impl = message._message;
-    }
-
-    this._check(_pn_messenger_get(this._messenger, impl));
-
-    if (message) {
-        message._postDecode(decodeBinaryAsString);
-    }
-
-    // Getting the tracker is a little tricky as it is a 64 bit number. The way
-    // emscripten handles this is to return the low 32 bits directly and pass
-    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
-    // low/high pair around to methods that require a tracker.
-    var low = _pn_messenger_incoming_tracker(this._messenger);
-    var high = Runtime.getTempRet0();
-
-    return new Data.Long(low, high);
-};
-
-/**
- * Returns the Subscription of the Message returned by the most recent call
- * to get, or null if pn_messenger_get has not yet been called.
- * @method incomingSubscription
- * @memberof! proton.Messenger#
- * @returns {Subscription} a Subscription or null if get has never been called
- *          for this Messenger.
- */
-_Messenger_['incomingSubscription'] = function() {
-    var subscription = _pn_messenger_incoming_subscription(this._messenger);
-    if (subscription) {
-        return new Subscription(subscription);
-    } else {
-        return null;
-    }
-};
-
-/**
- * Signal the sender that you have acted on the Message pointed to by the tracker.
- * If no tracker is supplied, then all messages that have been returned by the
- * get method are accepted, except those that have already been auto-settled
- * by passing beyond your incoming window size.
- * @method accept
- * @memberof! proton.Messenger#
- * @param {proton.Data.Long} tracker the tracker identifying the delivery.
- */
-_Messenger_['accept'] = function(tracker) {
-    // Getting the tracker is a little tricky as it is a 64 bit number. The way
-    // emscripten handles this is to return the low 32 bits directly and pass
-    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
-    // low/high pair around to methods that require a tracker.
-    var flags = 0;
-    if (tracker == null) {
-        var low = _pn_messenger_incoming_tracker(this._messenger);
-        var high = Runtime.getTempRet0();
-        tracker = new Data.Long(low, high);
-        flags = Module['Messenger'].PN_CUMULATIVE;
-    }
-
-    this._check(_pn_messenger_accept(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
-};
-
-/**
- * Rejects the Message indicated by the tracker.  If no tracker is supplied,
- * all messages that have been returned by the get method are rejected, except
- * those already auto-settled by passing beyond your outgoing window size.
- * @method reject
- * @memberof! proton.Messenger#
- * @param {proton.Data.Long} tracker the tracker identifying the delivery.
- */
-_Messenger_['reject'] = function(tracker) {
-    // Getting the tracker is a little tricky as it is a 64 bit number. The way
-    // emscripten handles this is to return the low 32 bits directly and pass
-    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
-    // low/high pair around to methods that require a tracker.
-    var flags = 0;
-    if (tracker == null) {
-        var low = _pn_messenger_incoming_tracker(this._messenger);
-        var high = Runtime.getTempRet0();
-        tracker = new Data.Long(low, high);
-        flags = Module['Messenger'].PN_CUMULATIVE;
-    }
-
-    this._check(_pn_messenger_reject(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
-};
-
-/**
- * Returns the number of messages in the outgoing message queue of a messenger.
- * @method outgoing
- * @memberof! proton.Messenger#
- * @returns {number} the outgoing queue depth.
- */
-_Messenger_['outgoing'] = function() {
-    return _pn_messenger_outgoing(this._messenger);
-};
-
-/**
- * Returns the number of messages in the incoming message queue of a messenger.
- * @method incoming
- * @memberof! proton.Messenger#
- * @returns {number} the incoming queue depth.
- */
-_Messenger_['incoming'] = function() {
-    return _pn_messenger_incoming(this._messenger);
-};
-
-/**
- * Adds a routing rule to a Messenger's internal routing table.
- * <p>
- * The route method may be used to influence how a messenger will internally treat
- * a given address or class of addresses. Every call to the route method will
- * result in messenger appending a routing rule to its internal routing table.
- * <p>
- * Whenever a message is presented to a messenger for delivery, it will match the
- * address of this message against the set of routing rules in order. The first
- * rule to match will be triggered, and instead of routing based on the address
- * presented in the message, the messenger will route based on the address supplied
- * in the rule.
- * <p>
- * The pattern matching syntax supports two types of matches, a '' will match any
- * character except a '/', and a '*' will match any character including a '/'.
- * <p>
- * A routing address is specified as a normal AMQP address, however it may
- * additionally use substitution variables from the pattern match that triggered
- * the rule.
- * <p>
- * Any message sent to "foo" will be routed to "amqp://foo.com":
- * <pre>
- * route("foo", "amqp://foo.com");
- * </pre>
- * Any message sent to "foobar" will be routed to "amqp://foo.com/bar":
- * <pre>
- * route("foobar", "amqp://foo.com/bar");
- * </pre>
- * Any message sent to bar/<path> will be routed to the corresponding path within
- * the amqp://bar.com domain:
- * <pre>
- * route("bar/*", "amqp://bar.com/$1");
- * </pre>
- * Supply credentials for foo.com:
- * <pre>
- * route("amqp://foo.com/*", "amqp://user:password@foo.com/$1");
- * </pre>
- * Supply credentials for all domains:
- * <pre>
- * route("amqp://*", "amqp://user:password@$1");
- * </pre>
- * Route all addresses through a single proxy while preserving the original destination:
- * <pre>
- * route("amqp://%/*", "amqp://user:password@proxy/$1/$2");
- * </pre>
- * Route any address through a single broker:
- * <pre>
- * route("*", "amqp://user:password@broker/$1");
- * </pre>
- * @method route
- * @memberof! proton.Messenger#
- * @param {string} pattern a glob pattern to select messages.
- * @param {string} address an address indicating outgoing address rewrite.
- */
-_Messenger_['route'] = function(pattern, address) {
-    var sp = Runtime.stackSave();
-    this._check(_pn_messenger_route(this._messenger,
-                                    allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
-                                    allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
-    Runtime.stackRestore(sp);
-};
-
-/**
- * Rewrite message addresses prior to transmission.
- * <p>
- * Similar to route(), except that the destination of the Message is determined
- * before the message address is rewritten.
- * <p>
- * The outgoing address is only rewritten after routing has been finalized. If
- * a message has an outgoing address of "amqp://0.0.0.0:5678", and a rewriting
- * rule that changes its outgoing address to "foo", it will still arrive at the
- * peer that is listening on "amqp://0.0.0.0:5678", but when it arrives there,
- * the receiver will see its outgoing address as "foo".
- * <p>
- * The default rewrite rule removes username and password from addresses
- * before they are transmitted.
- * @method rewrite
- * @memberof! proton.Messenger#
- * @param {string} pattern a glob pattern to select messages.
- * @param {string} address an address indicating outgoing address rewrite.
- */
-_Messenger_['rewrite'] = function(pattern, address) {
-    var sp = Runtime.stackSave();
-    this._check(_pn_messenger_rewrite(this._messenger,
-                                      allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
-                                      allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
-    Runtime.stackRestore(sp);
-};
-
-
-/*****************************************************************************/
-/*                                                                           */
-/*                               EventDispatch                               */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * EventDispatch is a Singleton class that allows callbacks to be registered which
- * will get triggered by the emscripten WebSocket network callbacks. Clients of
- * Messenger will register callbacks by calling:
- * <pre>
- * messenger.on('work', &lt;callback function&gt;);
- * </pre>
- * EventDispatch supports callback registration from multiple Messenger instances.
- * The client callbacks will actually be called when a given messenger has work
- * available or a WebSocket close has been occurred (in which case all registered
- * callbacks will be called).
- * <p>
- * The approach implemented here allows the registered callbacks to follow a
- * similar pattern to _process_incoming and _process_outgoing in async.py
- * @memberof proton
- */
-Module.EventDispatch = new function() { // Note the use of new to create a Singleton.
-    var _firstCall = true; // Flag used to check the first time registerMessenger is called.
-    var _messengers = {};
-
-    /**
-     * Provides functionality roughly equivalent to the following C code:
-     * while (1) {
-     *     pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
-     *     process();
-     * }
-     * The blocking call isn't viable in JavaScript as it is entirely asynchronous
-     * and we wouldn't want to replace the while(1) with a timed loop either!!
-     * This method gets triggered asynchronously by the emscripten socket events and
-     * we then perform an equivalent loop for each messenger, triggering every
-     * registered callback whilst there is work remaining. If triggered by close
-     * we bypass the _pn_messenger_work test as it will never succeed after closing.
-     */
-    var _pump = function(fd, closing) {
-        for (var i in _messengers) {
-            if (_messengers.hasOwnProperty(i)) {
-                var messenger = _messengers[i];
-
-                if (closing) {
-                    messenger._emit('work');
-                } else {
-                    while (_pn_messenger_work(messenger._messenger, 0) >= 0) {
-                        messenger._checkSubscriptions();
-                        messenger._checkErrors = false; // TODO improve error handling mechanism.
-                        messenger._emit('work');
-                    }
-                }
-            }
-        }
-    };
-
-    /**
-     * Listener for the emscripten socket close event. Delegates to _pump()
-     * passing a flag to indicate that the socket is closing.
-     */
-    var _close = function(fd) {
-        _pump(fd, true);
-    };
-
-    /**
-     * Register the specified Messenger as being interested in network events.
-     */
-    this.registerMessenger = function(messenger) {
-        if (_firstCall) {
-            /**
-             * Initialises the emscripten network callback functions. This needs
-             * to be done the first time we call registerMessenger rather than
-             * when we create the Singleton because emscripten's socket filesystem
-             * has to be mounted before can listen for any of these events.
-             */
-            Module['websocket']['on']('open', _pump);
-            Module['websocket']['on']('connection', _pump);
-            Module['websocket']['on']('message', _pump);
-            Module['websocket']['on']('close', _close);
-            _firstCall = false;
-        }
-
-        var name = messenger.getName();
-        _messengers[name] = messenger; 
-    };
-
-    /**
-     * Unregister the specified Messenger from interest in network events.
-     */
-    this.unregisterMessenger = function(messenger) {
-        var name = messenger.getName();
-        delete _messengers[name];
-    };
-};
-
-
-/*****************************************************************************/
-/*                                                                           */
-/*                               Subscription                                */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * Constructs a Subscription instance.
- * @classdesc This class is a wrapper for Messenger's subscriptions.
- * Subscriptions should never be *directly* instantiated by client code only via
- * Messenger.subscribe() or Messenger.incomingSubscription(), so we declare the
- * constructor in the scope of the package and don't export it via Module.
- * @constructor Subscription                                                              
- */
-var Subscription = function(subscription) { // Subscription Constructor.
-    this._subscription = subscription;
-};
-
-/**
- * TODO Not sure exactly what pn_subscription_get_context does.
- * @method getContext
- * @memberof! Subscription#
- * @returns the Subscription's Context.
- */
-Subscription.prototype['getContext'] = function() {
-    return _pn_subscription_get_context(this._subscription);
-};
-
-/**
- * TODO Not sure exactly what pn_subscription_set_context does.
- * @method setContext
- * @memberof! Subscription#
- * @param context the Subscription's new Context.
- */
-Subscription.prototype['setContext'] = function(context) {
-    _pn_subscription_set_context(this._subscription, context);
-};
-
-/**
- * @method getAddress
- * @memberof! Subscription#
- * @returns the Subscription's Address.
- */
-Subscription.prototype['getAddress'] = function() {
-    return Pointer_stringify(_pn_subscription_address(this._subscription));
-};
-
-
-/*****************************************************************************/
-/*                                                                           */
-/*                                  Message                                  */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * Constructs a proton.Message instance.
- * @classdesc This class is a mutable holder of message content that may be used
- * to generate and encode or decode and access AMQP formatted message data.
- * @constructor proton.Message
- * @property {object} instructions delivery instructions for the message.
- * @property {object} annotations infrastructure defined message annotations.
- * @property {object} properties application defined message properties.
- * @property {object} body message body as a native JavaScript Object.
- * @property {object} data message body as a proton.Data Object.
- */
-Module['Message'] = function() { // Message Constructor.
-    this._message = _pn_message();
-    this._id = new Data(_pn_message_id(this._message));
-    this._correlationId = new Data(_pn_message_correlation_id(this._message));
-
-    // ************************* Public properties ****************************
-
-    this['instructions'] = null;
-    this['annotations'] = null;
-
-    // Intitialise with an empty Object so we can set properties in a natural way.
-    // message.properties.prop1 = "foo";
-    // message.properties.prop2 = "bar";
-    this['properties'] = {};
-
-    this['body'] = null;
-    this['data'] = null;
-};
-
-// Expose constructor as package scope variable to make internal calls less verbose.
-var Message = Module['Message'];
-
-// Expose prototype as a variable to make method declarations less verbose.
-var _Message_ = Message.prototype;
-
-// ************************** Class properties ********************************
-
-Message['DEFAULT_PRIORITY'] = 4; /** Default priority for messages.*/
-
-// ************************* Protected methods ********************************
-
-// We use the dot notation rather than associative array form for protected
-// methods so they are visible to this "package", but the Closure compiler will
-// minify and obfuscate names, effectively making a defacto "protected" method.
-
-/**
- * This helper method checks the supplied error code, converts it into an
- * exception and throws the exception. This method will try to use the message
- * populated in pn_message_error(), if present, but if not it will fall
- * back to using the basic error code rendering from pn_code().
- * @param code the error code to check.
- */
-_Message_._check = function(code) {
-    if (code < 0) {
-        var errno = this['getErrno']();
-        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
-
-        throw new Module['MessageError'](message);
-    } else {
-        return code;
-    }
-};
-
-/**
- * Encode the Message prior to sending on the wire.
- */
-_Message_._preEncode = function() {
-    // A Message Object may be reused so we create new Data instances and clear
-    // the state for them each time put() gets called.
-    var inst = new Data(_pn_message_instructions(this._message));
-    var ann = new Data(_pn_message_annotations(this._message));
-    var props = new Data(_pn_message_properties(this._message));
-    var body = new Data(_pn_message_body(this._message));
-
-    inst.clear();
-    if (this['instructions']) {
-        inst['putObject'](this['instructions']);
-    }
-
-    ann.clear();
-    if (this['annotations']) {
-        ann['putObject'](this['annotations']);
-    }
-
-    props.clear();
-    if (this['properties']) {
-        props['putObject'](this['properties']);
-    }
-
-    body.clear();
-    if (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']);
-        }
-    }
-};
-
-/**
- * Decode the Message after receiving off the wire.
- * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
- *        objects as strings. This can be useful as the data in Binary objects
- *        will be overwritten with subsequent calls to get, so they must be
- *        explicitly copied. Needless to say it is only safe to set this flag if
- *        you know that the data you are dealing with is actually a string, for
- *        example C/C++ applications often seem to encode strings as AMQP binary,
- *        a common cause of interoperability problems.
- */
-_Message_._postDecode = function(decodeBinaryAsString) {
-    var inst = new Data(_pn_message_instructions(this._message));
-    var ann = new Data(_pn_message_annotations(this._message));
-    var props = new Data(_pn_message_properties(this._message));
-    var body = new Data(_pn_message_body(this._message), decodeBinaryAsString);
-
-    if (inst.next()) {
-        this['instructions'] = inst['getObject']();
-    } else {
-        this['instructions'] = {};
-    }
-
-    if (ann.next()) {
-        this['annotations'] = ann['getObject']();
-    } else {
-        this['annotations'] = {};
-    }
-
-    if (props.next()) {
-        this['properties'] = props['getObject']();
-    } else {
-        this['properties'] = {};
-    }
-
-    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;
-    }
-};
-
-// *************************** Public methods *********************************
-
-/**
- * Free the Message.
- * <p>
- * N.B. This method has to be called explicitly in JavaScript as we can't
- * intercept finalisers, so we need to remember to free before removing refs.
- * @method free
- * @memberof! proton.Message#
- */
-_Message_['free'] = function() {
-    _pn_message_free(this._message);
-};
-
-/**
- * @method getErrno
- * @memberof! proton.Message#
- * @returns {number the most recent error message code.
- */
-_Message_['getErrno'] = function() {
-    return _pn_message_errno(this._message);
-};
-
-/**
- * @method getError
- * @memberof! proton.Message#
- * @returns {string} the most recent error message as a String.
- */
-_Message_['getError'] = function() {
-    return Pointer_stringify(_pn_error_text(_pn_message_error(this._message)));
-};
-
-/**
- * Clears the contents of the Message. All fields will be reset to their default values.
- * @method clear
- * @memberof! proton.Message#
- */
-_Message_['clear'] = function() {
-    _pn_message_clear(this._message);
-    this['instructions'] = null;
-    this['annotations'] = null;
-    this['properties'] = {};
-    this['body'] = null;
-    this['data'] = null;
-};
-
-/**
- * Get the inferred flag for a message.
- * <p>
- * The inferred flag for a message indicates how the message content
- * is encoded into AMQP sections. If inferred is true then binary and
- * list values in the body of the message will be encoded as AMQP DATA
- * and AMQP SEQUENCE sections, respectively. If inferred is false,
- * then all values in the body of the message will be encoded as AMQP
- * VALUE sections regardless of their type. Use
- * {@link proton.Message.setInferred} to set the value.
- * @method isInferred
- * @memberof! proton.Message#
- * @returns {boolean} true iff the inferred flag for the message is set.
- */
-_Message_['isInferred'] = function() {
-    return (_pn_message_is_inferred(this._message) > 0);
-};
-
-/**
- * Set the inferred flag for a message. See {@link proton.Message.isInferred} 
- * for a description of what the inferred flag is.
- * @method setInferred
- * @memberof! proton.Message#
- * @param {boolean} inferred the new value of the inferred flag.
- */
-_Message_['setInferred'] = function(inferred) {
-    this._check(_pn_message_set_inferred(this._message, inferred));
-};
-
-/**
- * Get the durable flag for a message.
- * <p>
- * The durable flag indicates that any parties taking responsibility
- * for the message must durably store the content. Use
- * {@link proton.Message.setDurable} to set the value.
- * @method isDurable
- * @memberof! proton.Message#
- * @returns {boolean} true iff the durable flag for the message is set.
- */
-_Message_['isDurable'] = function() {
-    return (_pn_message_is_durable(this._message) > 0);
-};
-
-/**
- * Set the durable flag for a message. See {@link proton.Message.isDurable} 
- * for a description of what the durable flag is.
- * @method setDurable
- * @memberof! proton.Message#
- * @param {boolean} durable the new value of the durable flag.
- */
-_Message_['setDurable'] = function(durable) {
-    this._check(_pn_message_set_durable(this._message, durable));
-};
-
-/**
- * Get the priority for a message.
- * <p>
- * The priority of a message impacts ordering guarantees. Within a
- * given ordered context, higher priority messages may jump ahead of
- * lower priority messages. Priority range is 0..255
- * @method getPriority
- * @memberof! proton.Message#
- * @returns {number} the priority of the Message.
- */
-_Message_['getPriority'] = function() {
-    return _pn_message_get_priority(this._message) & 0xFF; // & 0xFF converts to unsigned.
-};
-
-/**
- * Set the priority of the Message. See {@link proton.Message.getPriority}
- * for details on message priority.
- * @method setPriority
- * @memberof! proton.Message#
- * @param {number} priority the address we want to send the Message to.
- */
-_Message_['setPriority'] = function(priority) {
-    this._check(_pn_message_set_priority(this._message, priority));
-};
-
-/**
- * Get the ttl for a message.
- * <p>
- * The ttl for a message determines how long a message is considered
- * live. When a message is held for retransmit, the ttl is
- * decremented. Once the ttl reaches zero, the message is considered
- * dead. Once a message is considered dead it may be dropped. Use
- * {@link proton.Message.setTTL} to set the ttl for a message.
- * @method getTTL
- * @memberof! proton.Message#
- * @returns {number} the ttl in milliseconds.
- */
-_Message_['getTTL'] = function() {
-    return _pn_message_get_ttl(this._message);
-};
-
-/**
- * Set the ttl for a message. See {@link proton.Message.getTTL}
- * for a detailed description of message ttl.
- * @method setTTL
- * @memberof! proton.Message#
- * @param {number} ttl the new value for the message ttl in milliseconds.
- */
-_Message_['setTTL'] = function(ttl) {
-    this._check(_pn_message_set_ttl(this._message, ttl));
-};
-
-/**
- * Get the first acquirer flag for a message.
- * <p>
- * When set to true, the first acquirer flag for a message indicates
- * that the recipient of the message is the first recipient to acquire
- * the message, i.e. there have been no failed delivery attempts to
- * other acquirers. Note that this does not mean the message has not
- * been delivered to, but not acquired, by other recipients.
- * @method isFirstAcquirer
- * @memberof! proton.Message#
- * @returns {boolean} true iff the first acquirer flag for the message is set.
- */
-_Message_['isFirstAcquirer'] = function() {
-    return (_pn_message_is_first_acquirer(this._message) > 0);
-};
-
-/**
- * Set the first acquirer flag for a message. See {@link proton.Message.isFirstAcquirer} 
- * for details on the first acquirer flag.
- * @method setFirstAcquirer
- * @memberof! proton.Message#
- * @param {boolean} first the new value of the first acquirer flag.
- */
-_Message_['setFirstAcquirer'] = function(first) {
-    this._check(_pn_message_set_first_acquirer(this._message, first));
-};
-
-/**
- * Get the delivery count for a message.
- * <p>
- * The delivery count field tracks how many attempts have been made to
- * deliver a message. Use {@link proton.Message.setDeliveryCount} to set
- * the delivery count for a message.
- * @method getDeliveryCount
- * @memberof! proton.Message#
- * @returns {number} the delivery count for the message.
- */
-_Message_['getDeliveryCount'] = function() {
-    return _pn_message_get_delivery_count(this._message);
-};
-
-/**
- * Set the delivery count for a message. See {@link proton.Message.getDeliveryCount}
- * for details on what the delivery count means.
- * @method setDeliveryCount
- * @memberof! proton.Message#
- * @param {number} count the new delivery count.
- */
-_Message_['setDeliveryCount'] = function(count) {
-    this._check(_pn_message_set_delivery_count(this._message, count));
-};
-
-/**
- * Get the id for a message.
- * <p>
- * The message id provides a globally unique identifier for a message.
- * A message id can be an a string, an unsigned long, a uuid or a binary value.
- * @method getID
- * @memberof! proton.Message#
- * @returns {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} the message id.
- */
-_Message_['getID'] = function() {
-    return this._id['getObject']();
-};
-
-/**
- * Set the id for a message. See {@link proton.Message.getID}
- * for more details on the meaning of the message id. Note that only string,
- * unsigned long, uuid, or binary values are permitted.
- * @method setID
- * @memberof! proton.Message#
- * @param {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} id the
- *        new value of the message id.
- */
-_Message_['setID'] = function(id) {
-    this._id['rewind']();
-    if (Data.isNumber(id)) {
-        this._id['putULONG'](id);
-    } else {
-        this._id['putObject'](id);
-    }
-};
-
-/**
- * Get the user id of the message creator.
- * <p>
- * The underlying raw data of the returned {@link proton.Data.Binary} will be
- * valid until any one of the following operations occur:
- * <pre>
- *  - {@link proton.Message.free}
- *  - {@link proton.Message.clear}
- *  - {@link proton.Message.setUserID}
- * </pre>
- * @method getUserID
- * @memberof! proton.Message#
- * @returns {proton.Data.Binary} the message's user id.
- */
-_Message_['getUserID'] = function() {
-    var sp = Runtime.stackSave();
-    // The implementation here is a bit "quirky" due to some low-level details
-    // of the interaction between emscripten and LLVM and the use of pn_bytes.
-    // The JavaScript code below is basically a binding to:
-    //
-    // pn_bytes_t bytes = pn_message_get_user_id(message);
-
-    // Here's the quirky bit, pn_message_get_user_id actually returns pn_bytes_t 
-    // *by value* but the low-level code handles this *by pointer* so we first
-    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
-    // and then we pass the pointer to that storage as the first parameter to the
-    // compiled pn_message_get_user_id.
-    var bytes = allocate(8, 'i8', ALLOC_STACK);
-    _pn_message_get_user_id(bytes, this._message);
-
-    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
-    // getValue() call to retrieve the size and then the start pointer.
-    var size  = getValue(bytes, 'i32');
-    var start = getValue(bytes + 4, '*');
-
-    // Create a proton.Data.Binary from the pn_bytes_t information.
-    var binary = new Data['Binary'](size, start);
-
-    // Tidy up the memory that we allocated on emscripten's stack.
-    Runtime.stackRestore(sp);
-
-    return binary;
-};
-
-/**
- * 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}, 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
- * @memberof! proton.Message#
- * @param {(string|proton.Data.Uuid)} id the new user id for the message.
- */
-_Message_['setUserID'] = function(id) {
-    // If the id parameter is a proton.Data.Binary use it otherwise create a Binary
-    // using the string form of the parameter that was passed.
-    id = (id instanceof Data['Binary']) ? id : new Data['Binary']('' + id);
-
-    var sp = Runtime.stackSave();
-    // The implementation here is a bit "quirky" due to some low-level details
-    // of the interaction between emscripten and LLVM and the use of pn_bytes.
-    // The JavaScript code below is basically a binding to:
-    //
-    // pn_message_set_user_id(message, pn_bytes(id.size, id.start));
-
-    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
-    // the low-level code handles this *by pointer* so we first need to allocate
-    // 8 bytes storage for {size, start} on the emscripten stack and then we
-    // pass the pointer to that storage as the first parameter to the pn_bytes.
-    var bytes = allocate(8, 'i8', ALLOC_STACK);
-    _pn_bytes(bytes, id.size, id.start);
-
-    // The compiled pn_message_set_user_id takes the pn_bytes_t by reference not value.
-    this._check(_pn_message_set_user_id(this._message, bytes));
-
-    // After calling _pn_message_set_user_id the underlying Message object "owns" the
-    // binary data, so we can call free on the proton.Data.Binary instance to
-    // release any storage it has acquired back to the emscripten heap.
-    id['free']();
-    Runtime.stackRestore(sp);
-};
-
-/**
- * Get the address for a message.
- * @method getAddress
- * @memberof! proton.Message#
- * @returns {string} the address of the Message.
- */
-_Message_['getAddress'] = function() {
-    return Pointer_stringify(_pn_message_get_address(this._message));
-};
-
-/**
- * Set the address of the Message.
- * @method setAddress
- * @memberof! proton.Message#
- * @param {string} address the address we want to send the Message to.
- */
-_Message_['setAddress'] = function(address) {
-    var sp = Runtime.stackSave();
-    this._check(_pn_message_set_address(this._message, allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
-    Runtime.stackRestore(sp);
-};
-
-/**
- * Get the subject for a message.
- * @method getSubject
- * @memberof! proton.Message#
- * @returns {string} the subject of the Message.
- */
-_Message_['getSubject'] = function() {
-    return Pointer_stringify(_pn_message_get_subject(this._message));
-};
-
-/**
- * Set the subject of the Message.
- * @method setSubject
- * @memberof! proton.Message#
- * @param {string} subject the subject we want to set for the Message.
- */
-_Message_['setSubject'] = function(subject) {
-    var sp = Runtime.stackSave();
-    this._check(_pn_message_set_subject(this._message, allocate(intArrayFromString(subject), 'i8', ALLOC_STACK)));
-    Runtime.stackRestore(sp);
-};
-
-/**
- * Get the reply to for a message.
- * @method getReplyTo
- * @memberof! proton.Message#
- * @returns {string} the reply to of the Message.
- */
-_Message_['getReplyTo'] = function() {
-    return Pointer_stringify(_pn_message_get_reply_to(this._message));
-};
-
-/**
- * Set the reply to for a message.
- * @method setReplyTo
- * @memberof! proton.Message#
- * @param {string} reply the reply to we want to set for the Message.
- */
-_Message_['setReplyTo'] = function(reply) {
-    var sp = Runtime.stackSave();
-    this._check(_pn_message_set_reply_to(this._message, allocate(intArrayFromString(reply), 'i8', ALLOC_STACK)));
-    Runtime.stackRestore(sp);
-};
-
-/**
- * Get the correlation id for a message.
- * <p>
- * A correlation id can be an a string, an unsigned long, a uuid or a binary value.
- * @method getCorrelationID
- * @memberof! proton.Message#
- * @returns {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} the message id.
- */
-_Message_['getCorrelationID'] = function() {
-    return this._correlationId['getObject']();
-};
-
-/**
- * Set the correlation id for a message. See {@link proton.Message.getCorrelationID}
- * for more details on the meaning of the correlation id. Note that only string,
- * unsigned long, uuid, or binary values are permitted.
- * @method setCorrelationID
- * @memberof! proton.Message#
- * @param {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} id the
- *        new value of the correlation id.
- */
-_Message_['setCorrelationID'] = function(id) {
-    this._correlationId['rewind']();
-    if (Data.isNumber(id)) {
-        this._correlationId['putULONG'](id);
-    } else {
-        this._correlationId['putObject'](id);
-    }
-};
-
-/**
- * Get the content type for a message.
- * @method getContentType
- * @memberof! proton.Message#
- * @returns {string} the content type of the Message.
- */
-_Message_['getContentType'] = function() {
-    return Pointer_stringify(_pn_message_get_content_type(this._message));
-};
-
-/**
- * Set the content type for a message.
- * @method setContentType
- * @memberof! proton.Message#
- * @param {string} type the content type we want to set for the Message.
- */
-_Message_['setContentType'] = function(type) {
-    var sp = Runtime.stackSave();
-    this._check(_pn_message_set_content_type(this._message, allocate(intArrayFromString(type), 'i8', ALLOC_STACK)));
-    Runtime.stackRestore(sp);
-};
-
-/**
- * Get the content encoding for a message.
- * @method getContentEncoding
- * @memberof! proton.Message#
- * @returns {string} the content encoding of the Message.
- */
-_Message_['getContentEncoding'] = function() {
-    return Pointer_stringify(_pn_message_get_content_encoding(this._message));
-};
-
-/**
- * Set the content encoding for a message.
- * @method setContentEncoding
- * @memberof! proton.Message#
- * @param {string} encoding the content encoding we want to set for the Message.
- */
-_Message_['setContentEncoding'] = function(encoding) {
-    var sp = Runtime.stackSave();
-    this._check(_pn_message_set_content_encoding(this._message, allocate(intArrayFromString(encoding), 'i8', ALLOC_STACK)));
-    Runtime.stackRestore(sp);
-};
-
-/**
- * Get the expiry time for a message.
- * A zero value for the expiry time indicates that the message will
- * never expire. This is the default value.
- * @method getExpiryTime
- * @memberof! proton.Message#
- * @returns {Date} the expiry time for the message.
- */
-_Message_['getExpiryTime'] = function() {
-    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
-    // emscripten handles this is to return the low 32 bits directly and pass
-    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
-    // the 64 bit number and Data.Long.toNumber() to convert it back into a
-    // JavaScript number.
-    var low =  _pn_message_get_expiry_time(this._message);
-    var high = Runtime.getTempRet0();
-    var long = new Data.Long(low, high);
-    long = long.toNumber();
-    return new Date(long);
-};
-
-/**
- * Set the expiry time for a message.
- * @method setExpiryTime
- * @memberof! proton.Message#
- * @param {(number|Date)} time the new expiry time for the message.
- */
-_Message_['setExpiryTime'] = function(time) {
-    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
-    var timestamp = Data.Long.fromNumber(time.valueOf());
-    this._check(_pn_message_set_expiry_time(this._message, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
-};
-
-/**
- * Get the creation time for a message.
- * A zero value for the creation time indicates that the creation time
- * has not been set. This is the default value.
- * @method getCreationTime
- * @memberof! proton.Message#
- * @returns {Date} the creation time for the message.
- */
-_Message_['getCreationTime'] = function() {
-    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
-    // emscripten handles this is to return the low 32 bits directly and pass
-    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
-    // the 64 bit number and Data.Long.toNumber() to convert it back into a
-    // JavaScript number.
-    var low =  _pn_message_get_creation_time(this._message);
-    var high = Runtime.getTempRet0();
-    var long = new Data.Long(low, high);
-    long = long.toNumber();
-    return new Date(long);
-};
-
-/**
- * Set the creation time for a message.
- * @method setCreationTime
- * @memberof! proton.Message#
- * @param {(number|Date)} time the new creation time for the message.
- */
-_Message_['setCreationTime'] = function(time) {
-    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
-    var timestamp = Data.Long.fromNumber(time.valueOf());
-    this._check(_pn_message_set_creation_time(this._message, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
-};
-
-/**
- * Get the group id for a message.
- * @method getGroupID
- * @memberof! proton.Message#
- * @returns {string} the group id of the Message.
- */
-_Message_['getGroupID'] = function() {
-    return Pointer_stringify(_pn_message_get_group_id(this._message));
-};
-
-/**
- * Set the group id for a message.
- * @method setGroupID
- * @memberof! proton.Message#
- * @param {string} id the group id we want to set for the Message.
- */
-_Message_['setGroupID'] = function(id) {
-    var sp = Runtime.stackSave();
-    this._check(_pn_message_set_group_id(this._message, allocate(intArrayFromString(id), 'i8', ALLOC_STACK)));
-    Runtime.stackRestore(sp);
-};
-
-/**
- * Get the group sequence for a message.
- * <p>
- * The group sequence of a message identifies the relative ordering of
- * messages within a group. The default value for the group sequence
- * of a message is zero.
- * @method getGroupSequence
- * @memberof! proton.Message#
- * @returns {number} the group sequence for the message.
- */
-_Message_['getGroupSequence'] = function() {
-    return _pn_message_get_group_sequence(this._message);
-};
-
-/**
- * Set the group sequence for a message. See {@link proton.Message.getGroupSequence}
- * for details on what the group sequence means.
- * @method setGroupSequence
- * @memberof! proton.Message#
- * @param {number} n the new group sequence for the message.
- */
-_Message_['setGroupSequence'] = function(n) {
-    this._check(_pn_message_set_group_sequence(this._message, n));
-};
-
-/**
- * Get the reply to group id for a message.
- * @method getReplyToGroupID
- * @memberof! proton.Message#
- * @returns {string} the reply to group id of the Message.
- */
-_Message_['getReplyToGroupID'] = function() {
-    return Pointer_stringify(_pn_message_get_reply_to_group_id(this._message));
-};
-
-/**
- * Set the reply to group id for a message.
- * @method setReplyToGroupID
- * @memberof! proton.Message#
- * @param {string} id the reply to group id we want to set for the Message.
- */
-_Message_['setReplyToGroupID'] = function(id) {
-    var sp = Runtime.stackSave();
-    this._check(_pn_message_set_reply_to_group_id(this._message, allocate(intArrayFromString(id), 'i8', ALLOC_STACK)));
-    Runtime.stackRestore(sp);
-};
-
-/**
- * The following methods are marked as deprecated and are not implemented.
- * pn_message_get_format()
- * pn_message_set_format()
- * pn_message_load()
- * pn_message_load_data()
- * pn_message_load_text()
- * pn_message_load_amqp()
- * pn_message_load_json()
- * pn_message_save()
- * pn_message_save_data()
- * pn_message_save_text()
- * pn_message_save_amqp()
- * pn_message_save_json()
- * pn_message_data()
- */
-
-/**
- * Return a Binary representation of the message encoded in AMQP format. N.B. the
- * returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
- * responsible for freeing it or passing it to a method that consumes a Binary
- * such as {@link proton.Message.decode}.
- * @method encode
- * @memberof! proton.Data#
- * @returns {proton.Data.Binary} a representation of the message encoded in AMQP format.
- */
-_Message_['encode'] = function() {
-    this._preEncode();
-    var size = 1024;
-    while (true) {
-        setValue(size, size, 'i32'); // Set pass by reference variable.
-        var bytes = _malloc(size);   // Allocate storage from emscripten heap.
-        var err = _pn_message_encode(this._message, bytes, size);
-        var size = getValue(size, 'i32'); // Dereference the real size value;
-
-        if (err === Module['Error']['OVERFLOW']) {
-            _free(bytes);
-            size *= 2;
-        } else if (err >= 0) {
-            return new Data['Binary'](size, bytes);
-        } else {
-            _free(bytes);
-            this._check(err);
-            return;
-        }
-    }
-};
-
-/**
- * Decodes and loads the message content from supplied Binary AMQP data  N.B. 
- * this method "consumes" data from a {@link proton.Data.Binary} in other words
- * it takes responsibility for the underlying data and frees the raw data from
- * the Binary.
- * @method decode
- * @memberof! proton.Data#
- * @param {proton.Data.Binary} encoded the AMQP encoded binary message.
- */
-_Message_['decode'] = function(encoded) {
-    var err = _pn_message_decode(this._message, encoded.start, encoded.size);
-    encoded['free'](); // Free the original Binary.
-    if (err >= 0) {
-        this._postDecode();
-    }
-    this._check(err);
-};
-
-
-/*****************************************************************************/
-/*                                                                           */
-/*                                    Data                                   */
-/*                                                                           */
-/*****************************************************************************/
-
-/**
- * Constructs a proton.Data instance.
- * @classdesc
- * The Data class provides an interface for decoding, extracting, creating, and
- * encoding arbitrary AMQP data. A Data object contains a tree of AMQP values.
- * Leaf nodes in this tree correspond to scalars in the AMQP type system such as
- * ints<INT> or strings<STRING>. Non-leaf nodes in this tree correspond to compound
- * values in the AMQP type system such as lists<LIST>, maps<MAP>, arrays<ARRAY>,
- * or described values<DESCRIBED>. The root node of the tree is the Data object
- * itself and can have an arbitrary number of children.
- * <p>
- * A Data object maintains the notion of the current sibling node and a current
- * parent node. Siblings are ordered within their parent. Values are accessed
- * and/or added by using the next, prev, enter, and exit methods to navigate to
- * the desired location in the tree and using the supplied variety of put* and
- * get* methods to access or add a value of the desired type.
- * <p>
- * The put* methods will always add a value after the current node in the tree.
- * If the current node has a next sibling the put* method will overwrite the value
- * on this node. If there is no current node or the current node has no next
- * sibling then one will be added. The put* methods always set the added/modified
- * node to the current node. The get* methods read the value of the current node
- * and do not change which node is current.
- * @constructor proton.Data
- * @param {number} data an optional pointer to a pn_data_t instance. If supplied
- *        the underlying data is "owned" by another object (for example a Message)
- *        and that object is assumed to be responsible for freeing the data if
- *        necessary. If no data is supplied then the Data is stand-alone and the
- *        client application is responsible for freeing the underlying data via
- *        a call to free().
- * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
- *        objects as strings. This can be useful as the data in Binary objects
- *        will be overwritten with subsequent calls to get, so they must be
- *        explicitly copied. Needless to say it is only safe to set this flag if
- *        you know that the data you are dealing with is actually a string, for
- *        example C/C++ applications often seem to encode strings as AMQP binary,
- *        a common cause of interoperability problems.
- */
-Module['Data'] = function(data, decodeBinaryAsString) { // Data Constructor.
-    if (!data) {
-        this._data = _pn_data(16); // Default capacity is 16
-        this['free'] = function() {
-            _pn_data_free(this._data);
-            // Set free to a null function to prevent possibility of a "double free".
-            this['free'] = function() {};
-        };
-    } else {
-        this._data = data;
-        this['free'] = function() {};
-    }
-    this._decodeBinaryAsString = decodeBinaryAsString;
-};
-
-// Expose constructor as package scope variable to make internal calls less verbose.
-var Data = Module['Data'];
-
-// Expose prototype as a variable to make method declarations less verbose.
-var _Data_ = Data.prototype;
-
-// ************************** Class properties ********************************
-
-Data['NULL']       = 1;
-Data['BOOL']       = 2;
-Data['UBYTE']      = 3;
-Data['BYTE']       = 4;
-Data['USHORT']     = 5;
-Data['SHORT']      = 6;
-Data['UINT']       = 7;
-Data['INT']        = 8;
-Data['CHAR']       = 9;
-Data['ULONG']      = 10;
-Data['LONG']       = 11;
-Data['TIMESTAMP']  = 12;
-Data['FLOAT']      = 13;
-Data['DOUBLE']     = 14;
-Data['DECIMAL32']  = 15;
-Data['DECIMAL64']  = 16;
-Data['DECIMAL128'] = 17;
-Data['UUID']       = 18;
-Data['BINARY']     = 19;
-Data['STRING']     = 20;
-Data['SYMBOL']     = 21;
-Data['DESCRIBED']  = 22;
-Data['ARRAY']      = 23;
-Data['LIST']       = 24;
-Data['MAP']        = 25;
-
-/**
- * Look-up table mapping proton-c types to the accessor method used to
- * deserialise the type. N.B. this is a simple Array and not a map because the
- * types that we get back from pn_data_type are integers from the pn_type_t enum.
- * @property {Array<String>} TypeNames
- * @memberof! proton.Data
- */
-Data['TypeNames'] = [
-    'NULL',       // 0
-    'NULL',       // PN_NULL       = 1
-    'BOOL',       // PN_BOOL       = 2
-    'UBYTE',      // PN_UBYTE      = 3
-    'BYTE',       // PN_BYTE       = 4
-    'USHORT',     // PN_USHORT     = 5
-    'SHORT',      // PN_SHORT      = 6
-    'UINT',       // PN_UINT       = 7
-    'INT',        // PN_INT        = 8
-    'CHAR',       // PN_CHAR       = 9
-    'ULONG',      // PN_ULONG      = 10
-    'LONG',       // PN_LONG       = 11
-    'TIMESTAMP',  // PN_TIMESTAMP  = 12
-    'FLOAT',      // PN_FLOAT      = 13
-    'DOUBLE',     // PN_DOUBLE     = 14
-    'DECIMAL32',  // PN_DECIMAL32  = 15
-    'DECIMAL64',  // PN_DECIMAL64  = 16
-    'DECIMAL128', // PN_DECIMAL128 = 17
-    'UUID',       // PN_UUID       = 18
-    'BINARY',     // PN_BINARY     = 19
-    'STRING',     // PN_STRING     = 20
-    'SYMBOL',     // PN_SYMBOL     = 21
-    'DESCRIBED',  // PN_DESCRIBED  = 22
-    'ARRAY',      // PN_ARRAY      = 23
-    'LIST',       // PN_LIST       = 24
-    'MAP'         // PN_MAP        = 25
-];
-
-// *************************** Class methods **********************************
-
-/**
- * Test if a given Object is a JavaScript Array.
- * @method isArray
- * @memberof! proton.Data
- * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a JavaScript Array.
- */
-Data.isArray = Array.isArray || function(o) {
-    return Object.prototype.toString.call(o) === '[object Array]';
-};
-
-/**
- * Test if a given Object is a JavaScript Number.
- * @method isNumber
- * @memberof! proton.Data
- * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a JavaScript Number.
- */
-Data.isNumber = function(o) {
-    return typeof o === 'number' || 
-          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object Number]');
-};
-
-/**
- * Test if a given Object is a JavaScript String.
- * @method isString
- * @memberof! proton.Data
- * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a JavaScript String.
- */
-Data.isString = function(o) {
-    return typeof o === 'string' ||
-          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object String]');
-};
-
-/**
- * Test if a given Object is a JavaScript Boolean.
- * @method isBoolean
- * @memberof! proton.Data
- * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a JavaScript Boolean.
- */
-Data.isBoolean = function(o) {
-    return typeof o === 'boolean' ||
-          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object Boolean]');
-};
-
-// **************************** Inner Classes *********************************
-
-// --------------------------- proton.Data.Uuid -------------------------------
-/**
- * Create a proton.Data.Uuid which is a type 4 UUID.
- * @classdesc
- * This class represents a type 4 UUID, wich may use crypto libraries to generate
- * the UUID if supported by the platform (e.g. node.js or a modern browser)
- * @constructor proton.Data.Uuid
- * @param u a UUID. If null a type 4 UUID is generated wich may use crypto if
- *        supported by the platform. If u is an emscripten "pointer" we copy the
- *        data from that. If u is a JavaScript Array we use it as-is. If u is a
- *        String then we try to parse that as a UUID.
- * @property {Array} uuid is the compact array form of the UUID.
- */
-Data['Uuid'] = function(u) { // Data.Uuid Constructor.
-    // Helper to copy from emscriptem allocated storage into JavaScript Array.
-    function _p2a(p) {
-        var uuid = new Array(16);
-        for (var i = 0; i < 16; i++) {
-            uuid[i] = getValue(p + i, 'i8') & 0xFF; // & 0xFF converts to unsigned.
-        }
-        return uuid;
-    };
-
-    if (!u) { // Generate UUID using emscriptem's uuid_generate implementation.
-        var sp = Runtime.stackSave();
-        var p = allocate(16, 'i8', ALLOC_STACK); // Create temporary pointer storage.
-        _uuid_generate(p);      // Generate UUID into allocated pointer.
-        this['uuid'] = _p2a(p); // Copy from allocated storage into JavaScript Array.
-        Runtime.stackRestore(sp);
-    } else if (Data.isNumber(u)) { // Use pointer that has been passed in.
-        this['uuid'] = _p2a(u);    // Copy from allocated storage into JavaScript Array.
-    } else if (Data.isArray(u)) { // Use array that has been passed in.
-        this['uuid'] = u; // Just use the JavaScript Array.
-    } else if (Data.isString(u)) { // Parse String form UUID.
-        if (u.length === 36) {
-            var i = 0;
-            var uuid = new Array(16);
-            u.toLowerCase().replace(/[0-9a-f]{2}/g, function(byte) {
-                if (i < 16) {
-                    uuid[i++] = parseInt(byte, 16);
-                }
-            });
-            this['uuid'] = uuid;
-        }
-    }
-    this.string = null;
-};
-
-/**
- * Returns the string representation of the proton.Data.Uuid.
- * @method toString
- * @memberof! proton.Data.Uuid#
- * @returns {string} the String
- *          /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
- *          form of a {@link proton.Data.Uuid}.
- */
-Data['Uuid'].prototype.toString = Data['Uuid'].prototype.valueOf = function() {
-    if (!this.string) { // Check if we've cached the string version.
-        var i = 0;
-        var uu = this['uuid'];
-        var uuid = 'xxxx-xx-xx-xx-xxxxxx'.replace(/[x]/g, function(c) {
-            var r = uu[i].toString(16);
-            r = (r.length === 1) ? '0' + r : r; // Zero pad single digit hex values
-            i++;
-            return r;
-        });
-        this.string = uuid;
-    }
-    return this.string;
-};
-
-/**
- * Compare two instances of proton.Data.Uuid for equality.
- * @method equals
- * @memberof! proton.Data.Uuid#
- * @param {proton.Data.Uuid} rhs the instance we wish to compare this instance with.
- * @returns {boolean} true iff the two compared instances are equal.
- */
-Data['Uuid'].prototype['equals'] = function(rhs) {
-    return this.toString() === rhs.toString();
-};
-
-// ---------------------------- proton.Data.Symbol ---------------------------- 
-/**
- * Create a proton.Data.Symbol.
- * @classdesc
- * This class represents an AMQP Symbol. This class is necessary primarily as a
- * way to enable us to distinguish between a native String and a Symbol in the
- * JavaScript type system.
- * @constructor proton.Data.Symbol
- * @param {string} s a symbol.
- */
-Data['Symbol'] = function(s) { // Data.Symbol Constructor.
-    this.value = s;
-};
-
-/**
- * @method toString
- * @memberof! proton.Data.Symbol#
- * @returns {string} the String form of a {@link proton.Data.Symbol}.
- */
-Data['Symbol'].prototype.toString = Data['Symbol'].prototype.valueOf = function() {
-    return this.value;
-};
-
-/**
- * Compare two instances of proton.Data.Symbol for equality.
- * @method equals
- * @memberof! proton.Data.Symbol#
- * @param {proton.Data.Symbol} rhs the instance we wish to compare this instance with.
- * @returns {boolean} true iff the two compared instances are equal.
- */
-Data['Symbol'].prototype['equals'] = function(rhs) {
-    return this.toString() === rhs.toString();
-};
-
-// ---------------------------- proton.Data.Described ---------------------------- 
-/**
- * Create a proton.Data.Described.
- * @classdesc
- * This class represents an AMQP Described.
- * @constructor proton.Data.Described
- * @param {object} value the value of the described type.
- * @param {string} descriptor an optional string describing the type.
- * @property {object} value the actual value of the described type.
- * @property {string} descriptor a string describing the type.
- */
-Data['Described'] = function(value, descriptor) { // Data.Described Constructor.
-    this['value'] = value;
-    this['descriptor'] = descriptor;
-};
-
-/**
- * @method toString
- * @memberof! proton.Data.Described#
- * @returns {string} the String form of a {@link proton.Data.Described}.
- */
-Data['Described'].prototype.toString = function() {
-    return 'Described(' + this['value'] + ', ' + this['descriptor'] + ')';
-};
-
-/**
- * @method valueOf
- * @memberof! proton.Data.Described#
- * @returns {object} the value of the {@link proton.Data.Described}.
- */
-Data['Described'].prototype.valueOf = function() {
-    return this['value'];
-};
-
-/**
- * Compare two instances of proton.Data.Described for equality.
- * @method equals
- * @memberof! proton.Data.Described#
- * @param {proton.Data.Described} rhs the instance we wish to compare this instance with.
- * @returns {boolean} true iff the two compared instances are equal.
- */
-Data['Described'].prototype['equals'] = function(rhs) {
-    if (rhs instanceof Data['Described']) {
-        return ((this['descriptor'] === rhs['descriptor']) && (this['value'] === rhs['value']));
-    } else {
-        return false;
-    }
-};
-
-// ---------------------------- proton.Data.Array ---------------------------- 
-/**
- * TODO make this behave more like a native JavaScript Array: http://www.bennadel.com/blog/2292-extending-javascript-arrays-while-keeping-native-bracket-notation-functionality.htm
- * Create a proton.Data.Array.
- * @classdesc
- * This class represents an AMQP Array.
- * @constructor proton.Data.Array
- * @param {{string|number)} type the type of the Number either as a string or number.
- *        Stored internally as a string corresponding to one of the TypeNames.     

<TRUNCATED>

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


[22/51] [abbrv] qpid-proton git commit: Update with merge of latest proton codebase and checked against latest emscripten incoming branch

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/python/setup.py.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setup.py.in b/proton-c/bindings/python/setup.py.in
new file mode 100644
index 0000000..94f3dfc
--- /dev/null
+++ b/proton-c/bindings/python/setup.py.in
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+from distutils.core import setup, Extension
+import logging
+import os
+import sys
+
+_c_module = '@SWIG_MODULE_cproton_REAL_NAME@'
+_src_file = '@PN_SWIG_PYTHON_C_WRAPPER@'
+_version =  '@PN_VERSION@'
+_release = 0
+
+if "--proton-install-prefix" in sys.argv:
+    # special option used only if the python headers and library have been
+    # installed to a non-standard directory.  This can be done during 'make
+    # install' from the proton build tree by using the cmake option
+    # -DCMAKE_INSTALL_PREFIX.  The location of the headers and library must be
+    # specified so we can build the binding's C extension.
+    i = sys.argv.index("--proton-install-prefix") + 1
+    if i >= len(sys.argv):
+        raise ValueError("--proton-install-prefix requires a path parameter.")
+    _prefix = sys.argv[i]
+    # remove the proton arguments to they don't conflict with setup.py's other
+    # command arguments:
+    del sys.argv[i]
+    sys.argv.remove("--proton-install-prefix")
+    _destdir = os.environ.get("DESTDIR", "")
+    if _destdir and os.path.isabs(_prefix):
+        # DESTDIR may be used on unix systems to put the entire install tree
+        # under a particular directory.  However, if _prefix is an absolute
+        # path, os.path.join will discard DESTDIR, so strip off the leading
+        # separator
+        _prefix = _prefix.lstrip(os.path.sep)
+
+    _inc_dir = os.path.join(_destdir,
+                            _prefix,
+                            '@INCLUDE_INSTALL_DIR@')
+    _lib_dir = os.path.join(_destdir,
+                            _prefix,
+                            '@LIB_INSTALL_DIR@')
+
+    swig_ext = Extension(_c_module, [_src_file],
+                         libraries=['qpid-proton'],
+                         include_dirs=[_inc_dir],
+                         library_dirs=[_lib_dir])
+else:
+    swig_ext = Extension(_c_module, [_src_file],
+                         libraries=['qpid-proton'])
+
+_help_description = """Before you can build or install these bindings, you must
+first install version @PN_VERSION@ of the Proton development library
+(libqpid-proton) and its C header files. These files must be available in order
+to build this packages' C-based extension.
+
+Packages for the Proton development library may be provided by your system's
+distribution. For example, the qpid-proton-c-devel RPM is available for
+Centos/RHEL via EPEL.  A libqpid-proton2-dev deb file is available for Ubuntu
+via the Apache Qpid PPA (ppa:qpid/released).
+
+If your distribution does not make these packages available, you can download
+the Proton sources directly from the Apache Qpid project:
+
+ http://qpid.apache.org
+
+This package is compatible with the @PN_VERSION@ release of the Proton
+development library.
+
+If you need additional help, see http://qpid.apache.org/discussion.html
+"""
+
+_long_description = """This package contains the Python bindings for the Apache
+QPID Proton library.\n%s""" % _help_description
+
+try:
+    setup(name="python-qpid-proton",
+          version="%s-%d" % (_version, _release),
+          author="Apache Qpid",
+          author_email="dev@qpid.apache.org",
+          py_modules=["proton", "cproton"],
+          url="http://qpid.apache.org/",
+          description="Python bindings for the Proton library",
+          long_description=_long_description,
+          license="Apache Software License",
+          classifiers=["License :: OSI Approved :: Apache Software License",
+                       "Intended Audience :: Developers",
+                       "Programming Language :: Python"],
+          ext_modules=[swig_ext])
+except:
+    logging.error("setup failed!\n%s", _help_description)
+    raise

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/ruby/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/CMakeLists.txt b/proton-c/bindings/ruby/CMakeLists.txt
index 9336abf..e77e4de 100644
--- a/proton-c/bindings/ruby/CMakeLists.txt
+++ b/proton-c/bindings/ruby/CMakeLists.txt
@@ -20,7 +20,9 @@
 if (NOT DEFAULT_RUBY_TESTING)
   message(FATAL_ERROR "Ruby bindings cannot be tested while missing dependencies")
 endif (NOT DEFAULT_RUBY_TESTING)
-
+list(APPEND SWIG_MODULE_cproton-ruby_EXTRA_DEPS
+    ${CMAKE_SOURCE_DIR}/proton-c/include/proton/cproton.i
+)
 include_directories (${RUBY_INCLUDE_PATH})
 swig_add_module(cproton-ruby ruby ruby.i)
 swig_link_libraries(cproton-ruby ${BINDING_DEPS} ${RUBY_LIBRARY})

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/ruby/lib/qpid_proton.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton.rb b/proton-c/bindings/ruby/lib/qpid_proton.rb
index cf044f6..e28c684 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton.rb
@@ -20,6 +20,7 @@
 require "cproton"
 require "date"
 
+require "qpid_proton/version"
 require "qpid_proton/described"
 require "qpid_proton/mapping"
 require "qpid_proton/array"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/ruby/lib/qpid_proton/version.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/version.rb b/proton-c/bindings/ruby/lib/qpid_proton/version.rb
new file mode 100644
index 0000000..cd30bf0
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/qpid_proton/version.rb
@@ -0,0 +1,29 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+module Qpid
+
+  module Proton
+
+    PN_VERSION_MAJOR = Cproton::PN_VERSION_MAJOR
+    PN_VERSION_MINOR = Cproton::PN_VERSION_MINOR
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/ruby/qpid_proton.gemspec
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/qpid_proton.gemspec b/proton-c/bindings/ruby/qpid_proton.gemspec
index d193563..f61d14c 100644
--- a/proton-c/bindings/ruby/qpid_proton.gemspec
+++ b/proton-c/bindings/ruby/qpid_proton.gemspec
@@ -8,6 +8,7 @@ system "swig -ruby -I../../include -o ext/cproton/cproton.c ruby.i"
 Gem::Specification.new do |s|
   s.name        = "qpid_proton"
   s.version     = "0.3"
+  s.licenses    = ['Apache-2.0']
   s.platform    = Gem::Platform::RUBY
   s.authors     = ["Darryl L. Pierce"]
   s.email       = ["proton@qpid.apache.org"]

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/ruby/ruby.i
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/ruby.i b/proton-c/bindings/ruby/ruby.i
index fd11786..502fa92 100644
--- a/proton-c/bindings/ruby/ruby.i
+++ b/proton-c/bindings/ruby/ruby.i
@@ -344,5 +344,4 @@ bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE)
 bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE);
 %ignore pn_ssl_get_protocol_name;
 
-
 %include "proton/cproton.i"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/docs/man/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/docs/man/CMakeLists.txt b/proton-c/docs/man/CMakeLists.txt
index d907a67..bd33e90 100644
--- a/proton-c/docs/man/CMakeLists.txt
+++ b/proton-c/docs/man/CMakeLists.txt
@@ -17,6 +17,6 @@
 # under the License.
 #
 
-INSTALL (FILES proton.1
+INSTALL (FILES proton.1 proton-dump.1
          DESTINATION ${MAN_INSTALL_DIR}/man1)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/docs/man/proton-dump.1
----------------------------------------------------------------------
diff --git a/proton-c/docs/man/proton-dump.1 b/proton-c/docs/man/proton-dump.1
new file mode 100644
index 0000000..0920d62
--- /dev/null
+++ b/proton-c/docs/man/proton-dump.1
@@ -0,0 +1,19 @@
+.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.44.1.
+.TH USAGE: "1" "August 2014" "Usage: proton-dump [FILE1] [FILEn] ..." "User Commands"
+.SH NAME
+proton-dump - display the contents of an AMQP dump file containing frame data
+.SH SYNOPSIS
+.B proton-dump
+[\fIFILE1\fR] [\fIFILEn\fR] ...
+.SH DESCRIPTION
+Displays the content of an AMQP dump file containing frame data.
+.TP
+[FILEn]
+Dump file to be displayed.
+.PP
+Displays the content of an AMQP dump file containing frame data.
+.TP
+[FILEn]
+Dump file to be displayed.
+.SH "SEE ALSO"
+proton(1)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/buffer.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/buffer.h b/proton-c/include/proton/buffer.h
index a3cf843..26d4bb3 100644
--- a/proton-c/include/proton/buffer.h
+++ b/proton-c/include/proton/buffer.h
@@ -29,6 +29,11 @@
 extern "C" {
 #endif
 
+typedef struct {
+    size_t size;
+    char *start;
+} pn_buffer_memory_t;
+
 typedef struct pn_buffer_t pn_buffer_t;
 
 PN_EXTERN pn_buffer_t *pn_buffer(size_t capacity);
@@ -44,6 +49,7 @@ PN_EXTERN int pn_buffer_trim(pn_buffer_t *buf, size_t left, size_t right);
 PN_EXTERN void pn_buffer_clear(pn_buffer_t *buf);
 PN_EXTERN int pn_buffer_defrag(pn_buffer_t *buf);
 PN_EXTERN pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf);
+PN_EXTERN pn_buffer_memory_t pn_buffer_memory(pn_buffer_t *buf);
 PN_EXTERN int pn_buffer_print(pn_buffer_t *buf);
 
 #ifdef __cplusplus

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/cproton.i
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/cproton.i b/proton-c/include/proton/cproton.i
index cef8b1f..1a9ad7f 100644
--- a/proton-c/include/proton/cproton.i
+++ b/proton-c/include/proton/cproton.i
@@ -30,6 +30,26 @@ typedef long long int int64_t;
 /* Parse these interface header files to generate APIs for script languages */
 
 %include "proton/import_export.h"
+
+%ignore _PROTON_VERSION_H;
+%include "proton/version.h"
+
+/* We cannot safely just wrap pn_bytes_t but each language binding must have a typemap for it - presumably to a string type */
+%ignore pn_bytes_t;
+
+/* There is no need to wrap pn_class_t aa it is an internal implementation detail and cannot be used outside the library */
+%ignore pn_class_t;
+
+/* Ignore C APIs related to pn_atom_t - they can all be achieved with pn_data_t */
+%ignore pn_atom_t;
+%ignore pn_atom_t_u; /* Seem to need this even though its nested in pn_atom_t */
+%ignore pn_data_get_atom;
+%ignore pn_data_put_atom;
+
+%ignore pn_delivery_tag_t;
+%ignore pn_decimal128_t;
+%ignore pn_uuid_t;
+
 %include "proton/types.h"
 %ignore pn_string_vformat;
 %ignore pn_string_vaddf;
@@ -60,7 +80,7 @@ typedef long long int int64_t;
 
 %aggregate_check(int, check_sasl_outcome,
                  PN_SASL_NONE, PN_SASL_OK, PN_SASL_AUTH,
-                 PN_SASL_SYS, PN_SASL_PERM, PN_SASL_TEMP);
+                 PN_SASL_SYS, PN_SASL_PERM, PN_SASL_TEMP, PN_SASL_SKIPPED);
 
 %aggregate_check(int, check_sasl_state,
                  PN_SASL_CONF, PN_SASL_IDLE, PN_SASL_STEP,
@@ -982,6 +1002,12 @@ typedef long long int int64_t;
   sasl != NULL;
 }
 
+%contract pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow)
+{
+ require:
+  sasl != NULL;
+}
+
 %contract pn_sasl_plain(pn_sasl_t *sasl, const char *username, const char *password)
 {
  require:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index fdb2803..c57c77d 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -81,8 +81,12 @@ typedef struct pn_event_t pn_event_t;
  */
 typedef enum {
     PN_EVENT_CATEGORY_NONE   = 0,
-    PN_EVENT_CATEGORY_PROTOCOL = 0x00010000,
-    PN_EVENT_CATEGORY_COUNT = 2
+    PN_EVENT_CATEGORY_CONNECTION = 0x00010000,
+    PN_EVENT_CATEGORY_SESSION = 0x00020000,
+    PN_EVENT_CATEGORY_LINK = 0x00030000,
+    PN_EVENT_CATEGORY_DELIVERY = 0x00040000,
+    PN_EVENT_CATEGORY_TRANSPORT = 0x00050000,
+    PN_EVENT_CATEGORY_COUNT = 6
 } pn_event_category_t;
 
 /**
@@ -94,45 +98,137 @@ typedef enum {
    * ever be generated.
    */
   PN_EVENT_NONE = 0,
+
+  /**
+   * The connection has been created. This is the first event that
+   * will ever be issued for a connection. Events of this type point
+   * to the relevant connection.
+   */
+  PN_CONNECTION_INIT = PN_EVENT_CATEGORY_CONNECTION + 1,
+
+  /**
+   * The local connection endpoint has been closed. Events of this
+   * type point to the relevant connection.
+   */
+  PN_CONNECTION_OPEN = PN_EVENT_CATEGORY_CONNECTION + 2,
+
+  /**
+   * The remote endpoint has opened the connection. Events of this
+   * type point to the relevant connection.
+   */
+  PN_CONNECTION_REMOTE_OPEN = PN_EVENT_CATEGORY_CONNECTION + 3,
+
+  /**
+   * The local connection endpoint has been closed. Events of this
+   * type point to the relevant connection.
+   */
+  PN_CONNECTION_CLOSE = PN_EVENT_CATEGORY_CONNECTION + 4,
+
+  /**
+   *  The remote endpoint has closed the connection. Events of this
+   *  type point to the relevant connection.
+   */
+  PN_CONNECTION_REMOTE_CLOSE = PN_EVENT_CATEGORY_CONNECTION + 5,
+
+  /**
+   * The connection has been freed and any outstanding processing has
+   * been completed. This is the final event that will ever be issued
+   * for a connection.
+   */
+  PN_CONNECTION_FINAL = PN_EVENT_CATEGORY_CONNECTION + 6,
+
+  /**
+   * The session has been created. This is the first event that will
+   * ever be issued for a session.
+   */
+  PN_SESSION_INIT = PN_EVENT_CATEGORY_SESSION + 1,
+
   /**
-   * The endpoint state flags for a connection have changed. Events of
-   * this type point to the relevant connection as well as its
-   * associated transport.
+   * The local session endpoint has been opened. Events of this type
+   * point ot the relevant session.
    */
-  PN_CONNECTION_REMOTE_STATE = PN_EVENT_CATEGORY_PROTOCOL+1,
-  PN_CONNECTION_LOCAL_STATE = PN_EVENT_CATEGORY_PROTOCOL+2,
+  PN_SESSION_OPEN = PN_EVENT_CATEGORY_SESSION + 2,
+
   /**
-   * The endpoint state flags for a session have changed. Events of
-   * this type point to the relevant session as well as its associated
-   * connection and transport.
+   * The remote endpoint has opened the session. Events of this type
+   * point to the relevant session.
    */
-  PN_SESSION_REMOTE_STATE = PN_EVENT_CATEGORY_PROTOCOL+3,
-  PN_SESSION_LOCAL_STATE = PN_EVENT_CATEGORY_PROTOCOL+4,
+  PN_SESSION_REMOTE_OPEN = PN_EVENT_CATEGORY_SESSION + 3,
+
   /**
-   * The endpoint state flags for a link have changed. Events of this
-   * type point to the relevant link as well as its associated
-   * session, connection, and transport.
+   * The local session endpoint has been closed. Events of this type
+   * point ot the relevant session.
    */
-  PN_LINK_REMOTE_STATE = PN_EVENT_CATEGORY_PROTOCOL+5,
-  PN_LINK_LOCAL_STATE = PN_EVENT_CATEGORY_PROTOCOL+6,
+  PN_SESSION_CLOSE = PN_EVENT_CATEGORY_SESSION + 4,
+
+  /**
+   * The remote endpoint has closed the session. Events of this type
+   * point to the relevant session.
+   */
+  PN_SESSION_REMOTE_CLOSE = PN_EVENT_CATEGORY_SESSION + 5,
+
+  /**
+   * The session has been freed and any outstanding processing has
+   * been completed. This is the final event that will ever be issued
+   * for a session.
+   */
+  PN_SESSION_FINAL = PN_EVENT_CATEGORY_SESSION + 6,
+
+  /**
+   * The link has been created. This is the first event that will ever
+   * be issued for a link.
+   */
+  PN_LINK_INIT = PN_EVENT_CATEGORY_LINK + 1,
+
+  /**
+   * The local link endpoint has been opened. Events of this type
+   * point ot the relevant link.
+   */
+  PN_LINK_OPEN = PN_EVENT_CATEGORY_LINK + 2,
+
+  /**
+   * The remote endpoint has opened the link. Events of this type
+   * point to the relevant link.
+   */
+  PN_LINK_REMOTE_OPEN = PN_EVENT_CATEGORY_LINK + 3,
+
+  /**
+   * The local link endpoint has been closed. Events of this type
+   * point ot the relevant link.
+   */
+  PN_LINK_CLOSE = PN_EVENT_CATEGORY_LINK + 4,
+
+  /**
+   * The remote endpoint has closed the link. Events of this type
+   * point to the relevant link.
+   */
+  PN_LINK_REMOTE_CLOSE = PN_EVENT_CATEGORY_LINK + 5,
+
   /**
    * The flow control state for a link has changed. Events of this
-   * type point to the relevant link along with its associated
-   * session, connection, and transport.
+   * type point to the relevant link.
    */
-  PN_LINK_FLOW = PN_EVENT_CATEGORY_PROTOCOL+7,
+  PN_LINK_FLOW = PN_EVENT_CATEGORY_LINK + 6,
+
+  /**
+   * The link has been freed and any outstanding processing has been
+   * completed. This is the final event that will ever be issued for a
+   * link. Events of this type point to the relevant link.
+   */
+  PN_LINK_FINAL = PN_EVENT_CATEGORY_LINK + 7,
+
   /**
    * A delivery has been created or updated. Events of this type point
-   * to the relevant delivery as well as its associated link, session,
-   * connection, and transport.
+   * to the relevant delivery.
    */
-  PN_DELIVERY = PN_EVENT_CATEGORY_PROTOCOL+8,
+  PN_DELIVERY = PN_EVENT_CATEGORY_DELIVERY + 1,
+
   /**
    * The transport has new data to read and/or write. Events of this
-   * type point to the relevant transport as well as its associated
-   * connection.
+   * type point to the relevant transport.
    */
-  PN_TRANSPORT = PN_EVENT_CATEGORY_PROTOCOL+9
+  PN_TRANSPORT = PN_EVENT_CATEGORY_TRANSPORT + 1
+
 } pn_event_type_t;
 
 /**
@@ -198,6 +294,11 @@ PN_EXTERN pn_event_type_t pn_event_type(pn_event_t *event);
 PN_EXTERN pn_event_category_t pn_event_category(pn_event_t *event);
 
 /**
+ * Get the context associated with an event.
+ */
+PN_EXTERN void *pn_event_context(pn_event_t *event);
+
+/**
  * Get the connection associated with an event.
  *
  * @param[in] event an event object

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/io.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/io.h b/proton-c/include/proton/io.h
index fffc09a..2d56736 100644
--- a/proton-c/include/proton/io.h
+++ b/proton-c/include/proton/io.h
@@ -44,6 +44,7 @@ typedef int pn_socket_t;
 #endif
 
 typedef struct pn_io_t pn_io_t;
+typedef struct pn_selector_t pn_selector_t;
 
 PN_EXTERN pn_io_t *pn_io(void);
 PN_EXTERN void pn_io_free(pn_io_t *io);
@@ -58,6 +59,7 @@ PN_EXTERN int pn_pipe(pn_io_t *io, pn_socket_t *dest);
 PN_EXTERN ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size);
 PN_EXTERN ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size);
 PN_EXTERN bool pn_wouldblock(pn_io_t *io);
+PN_EXTERN pn_selector_t *pn_io_selector(pn_io_t *io);
 
 #ifdef __cplusplus
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/object.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/object.h b/proton-c/include/proton/object.h
index dc4983a..9f6e63c 100644
--- a/proton-c/include/proton/object.h
+++ b/proton-c/include/proton/object.h
@@ -43,6 +43,7 @@ typedef void *(*pn_iterator_next_t)(void *state);
 typedef struct pn_iterator_t pn_iterator_t;
 
 typedef struct {
+  const char *name;
   void (*initialize)(void *);
   void (*finalize)(void *);
   uintptr_t (*hashcode)(void *);
@@ -51,6 +52,7 @@ typedef struct {
 } pn_class_t;
 
 #define PN_CLASS(PREFIX) {                      \
+    #PREFIX,                                    \
     PREFIX ## _initialize,                      \
     PREFIX ## _finalize,                        \
     PREFIX ## _hashcode,                        \
@@ -58,14 +60,17 @@ typedef struct {
     PREFIX ## _inspect                          \
 }
 
-PN_EXTERN void *pn_new(size_t size, pn_class_t *clazz);
-PN_EXTERN void pn_initialize(void *object, pn_class_t *clazz);
+PN_EXTERN void *pn_new(size_t size, const pn_class_t* clazz);
+PN_EXTERN void *pn_new2(size_t size, const pn_class_t* clazz, void *from);
+PN_EXTERN void pn_initialize(void *object, const pn_class_t *clazz);
 PN_EXTERN void *pn_incref(void *object);
+PN_EXTERN void *pn_incref2(void *object, void *from);
 PN_EXTERN void pn_decref(void *object);
+PN_EXTERN void pn_decref2(void *object, void *from);
 PN_EXTERN int pn_refcount(void *object);
 PN_EXTERN void pn_finalize(void *object);
 PN_EXTERN void pn_free(void *object);
-PN_EXTERN pn_class_t *pn_class(void *object);
+PN_EXTERN const pn_class_t *pn_class(void* object);
 PN_EXTERN uintptr_t pn_hashcode(void *object);
 PN_EXTERN intptr_t pn_compare(void *a, void *b);
 PN_EXTERN bool pn_equals(void *a, void *b);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/sasl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/sasl.h b/proton-c/include/proton/sasl.h
index 0cd9141..1f132e6 100644
--- a/proton-c/include/proton/sasl.h
+++ b/proton-c/include/proton/sasl.h
@@ -54,7 +54,8 @@ typedef enum {
   PN_SASL_AUTH=1,   /** failed due to bad credentials */
   PN_SASL_SYS=2,    /** failed due to a system error */
   PN_SASL_PERM=3,   /** failed due to unrecoverable error */
-  PN_SASL_TEMP=4    /** failed due to transient error */
+  PN_SASL_TEMP=4,   /** failed due to transient error */
+  PN_SASL_SKIPPED=5 /** the peer didn't perform the sasl exchange */
 } pn_sasl_outcome_t;
 
 /** The state of the SASL negotiation process */
@@ -113,6 +114,18 @@ PN_EXTERN void pn_sasl_client(pn_sasl_t *sasl);
  */
 PN_EXTERN void pn_sasl_server(pn_sasl_t *sasl);
 
+/** Configure a SASL server layer to permit the client to skip the SASL exchange.
+ *
+ * If the peer client skips the SASL exchange (i.e. goes right to the AMQP header)
+ * this server layer will succeed and result in the outcome of PN_SASL_SKIPPED.
+ * The default behavior is to fail and close the connection if the client skips
+ * SASL.
+ *
+ * @param[in] sasl the SASL layer to configure
+ * @param[in] allow true -> allow skip; false -> forbid skip
+ */
+    PN_EXTERN void pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow);
+
 /** Configure the SASL layer to use the "PLAIN" mechanism.
  *
  * A utility function to configure a simple client SASL layer using

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/selector.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/selector.h b/proton-c/include/proton/selector.h
index 37370d4..7d599b0 100644
--- a/proton-c/include/proton/selector.h
+++ b/proton-c/include/proton/selector.h
@@ -34,9 +34,7 @@ extern "C" {
 #define PN_WRITABLE (2)
 #define PN_EXPIRED (4)
 
-typedef struct pn_selector_t pn_selector_t;
-
-PN_EXTERN pn_selector_t *pn_selector(void);
+pn_selector_t *pni_selector(void);
 PN_EXTERN void pn_selector_free(pn_selector_t *selector);
 PN_EXTERN void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable);
 PN_EXTERN void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/terminus.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/terminus.h b/proton-c/include/proton/terminus.h
index 9c9096b..3765b28 100644
--- a/proton-c/include/proton/terminus.h
+++ b/proton-c/include/proton/terminus.h
@@ -90,10 +90,10 @@ typedef enum {
  * counting down.
  */
 typedef enum {
-  PN_LINK_CLOSE, /**< the terminus is orphaned when the parent link is closed */
-  PN_SESSION_CLOSE, /**< the terminus is orphaned when the parent session is closed */
-  PN_CONNECTION_CLOSE, /**< the terminus is orphaned when the parent connection is closed */
-  PN_NEVER /**< the terminus is never considered orphaned */
+  PN_EXPIRE_WITH_LINK, /**< the terminus is orphaned when the parent link is closed */
+  PN_EXPIRE_WITH_SESSION, /**< the terminus is orphaned when the parent session is closed */
+  PN_EXPIRE_WITH_CONNECTION, /**< the terminus is orphaned when the parent connection is closed */
+  PN_EXPIRE_NEVER /**< the terminus is never considered orphaned */
 } pn_expiry_policy_t;
 
 /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/transport.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/transport.h b/proton-c/include/proton/transport.h
index 1fa24c8..abe2853 100644
--- a/proton-c/include/proton/transport.h
+++ b/proton-c/include/proton/transport.h
@@ -328,16 +328,17 @@ PN_EXTERN char *pn_transport_tail(pn_transport_t *transport);
  *
  * This is equivalent to copying @c size bytes afther the tail pointer
  * and then calling ::pn_transport_process with an argument of @c
- * size. It is an error to call this with a @c size larger than the
- * capacity reported by ::pn_transport_capacity.
+ * size. Only some of the bytes will be copied if there is
+ * insufficienty capacity available. Use ::pn_transport_capacity to
+ * determine how much capacity the transport has.
  *
  * @param[in] transport the transport
  * @param[in] src the start of the data to push into the transport
  * @param[in] size the amount of data to push into the transport
  *
- * @return 0 on success, or error code if < 0
+ * @return the number of bytes pushed on success, or error code if < 0
  */
-PN_EXTERN int pn_transport_push(pn_transport_t *transport, const char *src, size_t size);
+PN_EXTERN ssize_t pn_transport_push(pn_transport_t *transport, const char *src, size_t size);
 
 /**
  * Process input data following the tail pointer.
@@ -404,9 +405,9 @@ PN_EXTERN const char *pn_transport_head(pn_transport_t *transport);
  * @param[in] transport the transport
  * @param[out] dst the destination buffer
  * @param[in] size the capacity of the destination buffer
- * @return 0 on success, or error code if < 0
+ * @return number of bytes copied on success, or error code if < 0
  */
-PN_EXTERN int pn_transport_peek(pn_transport_t *transport, char *dst, size_t size);
+PN_EXTERN ssize_t pn_transport_peek(pn_transport_t *transport, char *dst, size_t size);
 
 /**
  * Removes @c size bytes of output from the pending output queue

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/include/proton/types.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/types.h b/proton-c/include/proton/types.h
index 4182f25..d15b745 100644
--- a/proton-c/include/proton/types.h
+++ b/proton-c/include/proton/types.h
@@ -23,6 +23,7 @@
  */
 
 #include <proton/import_export.h>
+#include <stddef.h>
 #include <sys/types.h>
 #include <proton/type_compat.h>
 
@@ -58,11 +59,10 @@ typedef struct {
 
 typedef struct {
   size_t size;
-  char *start;
+  const char *start;
 } pn_bytes_t;
 
-PN_EXTERN pn_bytes_t pn_bytes(size_t size, char *start);
-PN_EXTERN pn_bytes_t pn_bytes_dup(size_t size, const char *start);
+PN_EXTERN pn_bytes_t pn_bytes(size_t size, const char *start);
 
 /** @}
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/buffer.c
----------------------------------------------------------------------
diff --git a/proton-c/src/buffer.c b/proton-c/src/buffer.c
index 1371831..b69034b 100644
--- a/proton-c/src/buffer.c
+++ b/proton-c/src/buffer.c
@@ -273,6 +273,18 @@ pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf)
   }
 }
 
+pn_buffer_memory_t pn_buffer_memory(pn_buffer_t *buf)
+{
+  if (buf) {
+    pn_buffer_defrag(buf);
+    pn_buffer_memory_t r = {buf->size, buf->bytes};
+    return r;
+  } else {
+    pn_buffer_memory_t r = {0, NULL};
+    return r;
+  }
+}
+
 int pn_buffer_print(pn_buffer_t *buf)
 {
   printf("pn_buffer(\"");

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/codec/codec.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/codec.c b/proton-c/src/codec/codec.c
index 9370129..0660032 100644
--- a/proton-c/src/codec/codec.c
+++ b/proton-c/src/codec/codec.c
@@ -92,7 +92,7 @@ static void pn_data_finalize(void *object)
   pn_free(data->encoder);
 }
 
-static pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node)
+static const pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node)
 {
   if (!node) return NULL;
   if (node->atom.type != PN_DESCRIBED) return NULL;
@@ -103,8 +103,9 @@ static pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node)
     return NULL;
   }
 
-  if (descriptor->atom.u.as_ulong < 256) {
-    return &FIELDS[descriptor->atom.u.as_ulong];
+  if (descriptor->atom.u.as_ulong >= FIELD_MIN && descriptor->atom.u.as_ulong <= FIELD_MAX) {
+    const pn_fields_t *f = &FIELDS[descriptor->atom.u.as_ulong-FIELD_MIN];
+    return (f->name_index!=0) ? f : NULL;
   } else {
     return NULL;
   }
@@ -233,9 +234,16 @@ int pni_inspect_atom(pn_atom_t *atom, pn_string_t *str)
       if (quote) if ((err = pn_string_addf(str, "\""))) return err;
       return 0;
     }
+  case PN_LIST:
+    return pn_string_addf(str, "<list>");
+  case PN_MAP:
+    return pn_string_addf(str, "<map>");
+  case PN_ARRAY:
+    return pn_string_addf(str, "<array>");
+  case PN_DESCRIBED:
+    return pn_string_addf(str, "<described>");
   default:
-    assert(false);
-    return PN_ERR;
+    return pn_string_addf(str, "<undefined: %i>", atom->type);
   }
 }
 
@@ -245,9 +253,9 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node)
   pn_atom_t *atom = (pn_atom_t *) &node->atom;
 
   pni_node_t *parent = pn_data_node(data, node->parent);
-  pn_fields_t *fields = pni_node_fields(data, parent);
+  const pn_fields_t *fields = pni_node_fields(data, parent);
   pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
-  pn_fields_t *grandfields = pni_node_fields(data, grandparent);
+  const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
   int index = pni_node_index(data, node);
 
   int err;
@@ -256,7 +264,9 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node)
     if (atom->type == PN_NULL) {
       return 0;
     }
-    const char *name = grandfields->fields[index];
+    const char *name = (index < grandfields->field_count)
+        ? FIELD_STRINGPOOL+FIELD_FIELDS[grandfields->first_field_index+index]
+        : NULL;
     if (name) {
       err = pn_string_addf(str, "%s=", name);
       if (err) return err;
@@ -275,7 +285,7 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node)
     return pn_string_addf(str, "{");
   default:
     if (fields && index == 0) {
-      err = pn_string_addf(str, "%s", fields->name);
+      err = pn_string_addf(str, "%s", FIELD_STRINGPOOL+FIELD_NAME[fields->name_index]);
       if (err) return err;
       err = pn_string_addf(str, "(");
       if (err) return err;
@@ -305,7 +315,7 @@ int pni_inspect_exit(void *ctx, pn_data_t *data, pni_node_t *node)
   pn_string_t *str = (pn_string_t *) ctx;
   pni_node_t *parent = pn_data_node(data, node->parent);
   pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
-  pn_fields_t *grandfields = pni_node_fields(data, grandparent);
+  const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
   pni_node_t *next = pn_data_node(data, node->next);
   int err;
 
@@ -356,7 +366,7 @@ static int pn_data_inspect(void *obj, pn_string_t *dst)
 
 pn_data_t *pn_data(size_t capacity)
 {
-  static pn_class_t clazz = PN_CLASS(pn_data);
+  static const pn_class_t clazz = PN_CLASS(pn_data);
   pn_data_t *data = (pn_data_t *) pn_new(sizeof(pn_data_t), &clazz);
   data->capacity = capacity;
   data->size = 0;
@@ -407,12 +417,12 @@ void pn_data_clear(pn_data_t *data)
 
 int pn_data_grow(pn_data_t *data)
 {
-  data->capacity = 2*(data->capacity ? data->capacity : 16);
+  data->capacity = 2*(data->capacity ? data->capacity : 2);
   data->nodes = (pni_node_t *) realloc(data->nodes, data->capacity * sizeof(pni_node_t));
   return 0;
 }
 
-ssize_t pn_data_intern(pn_data_t *data, char *start, size_t size)
+ssize_t pn_data_intern(pn_data_t *data, const char *start, size_t size)
 {
   size_t offset = pn_buffer_size(data->buf);
   int err = pn_buffer_append(data->buf, start, size);
@@ -454,7 +464,7 @@ int pn_data_intern_node(pn_data_t *data, pni_node_t *node)
   node->data = true;
   node->data_offset = offset;
   node->data_size = bytes->size;
-  pn_bytes_t buf = pn_buffer_bytes(data->buf);
+  pn_buffer_memory_t buf = pn_buffer_memory(data->buf);
   bytes->start = buf.start + offset;
 
   if (pn_buffer_capacity(data->buf) != oldcap) {
@@ -1102,7 +1112,7 @@ int pn_data_resize(pn_data_t *data, size_t size)
 }
 
 
-pni_node_t *pn_data_node(pn_data_t *data, size_t nd)
+pni_node_t *pn_data_node(pn_data_t *data, pni_nid_t nd)
 {
   if (nd) {
     return &data->nodes[nd - 1];
@@ -1348,7 +1358,7 @@ bool pn_data_lookup(pn_data_t *data, const char *name)
 
 void pn_data_dump(pn_data_t *data)
 {
-  printf("{current=%" PN_ZI ", parent=%" PN_ZI "}\n", data->current, data->parent);
+  printf("{current=%" PN_ZI ", parent=%" PN_ZI "}\n", (size_t) data->current, (size_t) data->parent);
   for (unsigned i = 0; i < data->size; i++)
   {
     pni_node_t *node = &data->nodes[i];
@@ -1356,7 +1366,11 @@ void pn_data_dump(pn_data_t *data)
     pni_inspect_atom((pn_atom_t *) &node->atom, data->str);
     printf("Node %i: prev=%" PN_ZI ", next=%" PN_ZI ", parent=%" PN_ZI ", down=%" PN_ZI 
            ", children=%" PN_ZI ", type=%s (%s)\n",
-           i + 1, node->prev, node->next, node->parent, node->down, node->children,
+           i + 1, (size_t) node->prev,
+           (size_t) node->next,
+           (size_t) node->parent,
+           (size_t) node->down,
+           (size_t) node->children,
            pn_type_name(node->atom.type), pn_string_get(data->str));
   }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/codec/data.h
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/data.h b/proton-c/src/codec/data.h
index 5ac8d45..be1669a 100644
--- a/proton-c/src/codec/data.h
+++ b/proton-c/src/codec/data.h
@@ -27,39 +27,41 @@
 #include "decoder.h"
 #include "encoder.h"
 
+typedef uint16_t pni_nid_t;
+
 typedef struct {
-  size_t next;
-  size_t prev;
-  size_t down;
-  size_t parent;
-  size_t children;
+  char *start;
+  size_t data_offset;
+  size_t data_size;
   pn_atom_t atom;
+  pn_type_t type;
+  pni_nid_t next;
+  pni_nid_t prev;
+  pni_nid_t down;
+  pni_nid_t parent;
+  pni_nid_t children;
   // for arrays
   bool described;
-  pn_type_t type;
   bool data;
-  size_t data_offset;
-  size_t data_size;
-  char *start;
   bool small;
 } pni_node_t;
 
 struct pn_data_t {
-  size_t capacity;
-  size_t size;
   pni_node_t *nodes;
   pn_buffer_t *buf;
-  size_t parent;
-  size_t current;
-  size_t base_parent;
-  size_t base_current;
   pn_decoder_t *decoder;
   pn_encoder_t *encoder;
   pn_error_t *error;
   pn_string_t *str;
+  pni_nid_t capacity;
+  pni_nid_t size;
+  pni_nid_t parent;
+  pni_nid_t current;
+  pni_nid_t base_parent;
+  pni_nid_t base_current;
 };
 
-pni_node_t *pn_data_node(pn_data_t *data, size_t nd);
+pni_node_t *pn_data_node(pn_data_t *data, pni_nid_t nd);
 int pni_data_traverse(pn_data_t *data,
                       int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
                       int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/codec/decoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/decoder.c b/proton-c/src/codec/decoder.c
index cfdd3b9..28e8ae1 100644
--- a/proton-c/src/codec/decoder.c
+++ b/proton-c/src/codec/decoder.c
@@ -54,7 +54,7 @@ static void pn_decoder_finalize(void *obj) {
 
 pn_decoder_t *pn_decoder()
 {
-  static pn_class_t clazz = PN_CLASS(pn_decoder);
+  static const pn_class_t clazz = PN_CLASS(pn_decoder);
   return (pn_decoder_t *) pn_new(sizeof(pn_decoder_t), &clazz);
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/codec/encoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/encoder.c b/proton-c/src/codec/encoder.c
index 639d132..f0f3cef 100644
--- a/proton-c/src/codec/encoder.c
+++ b/proton-c/src/codec/encoder.c
@@ -56,7 +56,7 @@ static void pn_encoder_finalize(void *obj) {
 
 pn_encoder_t *pn_encoder()
 {
-  static pn_class_t clazz = PN_CLASS(pn_encoder);
+  static const pn_class_t clazz = PN_CLASS(pn_encoder);
   return (pn_encoder_t *) pn_new(sizeof(pn_encoder_t), &clazz);
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/dispatch_actions.h
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatch_actions.h b/proton-c/src/dispatch_actions.h
new file mode 100644
index 0000000..aa7a8f4
--- /dev/null
+++ b/proton-c/src/dispatch_actions.h
@@ -0,0 +1,45 @@
+#ifndef _PROTON_DISPATCH_ACTIONS_H
+#define _PROTON_DISPATCH_ACTIONS_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "dispatcher/dispatcher.h"
+
+/* Transport actions */
+int pn_do_open(pn_dispatcher_t *disp);
+int pn_do_begin(pn_dispatcher_t *disp);
+int pn_do_attach(pn_dispatcher_t *disp);
+int pn_do_transfer(pn_dispatcher_t *disp);
+int pn_do_flow(pn_dispatcher_t *disp);
+int pn_do_disposition(pn_dispatcher_t *disp);
+int pn_do_detach(pn_dispatcher_t *disp);
+int pn_do_end(pn_dispatcher_t *disp);
+int pn_do_close(pn_dispatcher_t *disp);
+
+/* SASL actions */
+int pn_do_init(pn_dispatcher_t *disp);
+int pn_do_mechanisms(pn_dispatcher_t *disp);
+int pn_do_challenge(pn_dispatcher_t *disp);
+int pn_do_response(pn_dispatcher_t *disp);
+int pn_do_outcome(pn_dispatcher_t *disp);
+
+#endif // _PROTON_DISPATCH_ACTIONS_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/dispatcher/dispatcher.c
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatcher/dispatcher.c b/proton-c/src/dispatcher/dispatcher.c
index 3f3ee3c..296c3ab 100644
--- a/proton-c/src/dispatcher/dispatcher.c
+++ b/proton-c/src/dispatcher/dispatcher.c
@@ -30,6 +30,41 @@
 #include "../util.h"
 #include "../platform_fmt.h"
 
+#include "dispatch_actions.h"
+
+int pni_bad_frame(pn_dispatcher_t* disp) {
+  pn_transport_log(disp->transport, "Error dispatching frame: Unknown performative");
+  return PN_ERR;
+}
+
+// We could use a table based approach here if we needed to dynamically
+// add new performatives
+static inline int pni_dispatch_action(pn_dispatcher_t* disp, uint64_t lcode)
+{
+  pn_action_t *action;
+  switch (lcode) {
+  /* Regular AMQP fames */
+  case OPEN:            action = pn_do_open; break;
+  case BEGIN:           action = pn_do_begin; break;
+  case ATTACH:          action = pn_do_attach; break;
+  case FLOW:            action = pn_do_flow; break;
+  case TRANSFER:        action = pn_do_transfer; break;
+  case DISPOSITION:     action = pn_do_disposition; break;
+  case DETACH:          action = pn_do_detach; break;
+  case END:             action = pn_do_end; break;
+  case CLOSE:           action = pn_do_close; break;
+
+  /* SASL frames */
+  case SASL_MECHANISMS: action = pn_do_mechanisms; break;
+  case SASL_INIT:       action = pn_do_init; break;
+  case SASL_CHALLENGE:  action = pn_do_challenge; break;
+  case SASL_RESPONSE:   action = pn_do_response; break;
+  case SASL_OUTCOME:    action = pn_do_outcome; break;
+  default:              action = pni_bad_frame; break;
+  };
+  return action(disp);
+}
+
 pn_dispatcher_t *pn_dispatcher(uint8_t frame_type, pn_transport_t *transport)
 {
   pn_dispatcher_t *disp = (pn_dispatcher_t *) calloc(sizeof(pn_dispatcher_t), 1);
@@ -40,11 +75,7 @@ pn_dispatcher_t *pn_dispatcher(uint8_t frame_type, pn_transport_t *transport)
     (pn_env_bool("PN_TRACE_FRM") ? PN_TRACE_FRM : PN_TRACE_OFF) |
     (pn_env_bool("PN_TRACE_DRV") ? PN_TRACE_DRV : PN_TRACE_OFF);
 
-  disp->input = pn_buffer(1024);
-  disp->fragment = 0;
-
   disp->channel = 0;
-  disp->code = 0;
   disp->args = pn_data(16);
   disp->payload = NULL;
   disp->size = 0;
@@ -67,7 +98,6 @@ pn_dispatcher_t *pn_dispatcher(uint8_t frame_type, pn_transport_t *transport)
 void pn_dispatcher_free(pn_dispatcher_t *disp)
 {
   if (disp) {
-    pn_buffer_free(disp->input);
     pn_data_free(disp->args);
     pn_data_free(disp->output_args);
     pn_buffer_free(disp->frame);
@@ -77,12 +107,6 @@ void pn_dispatcher_free(pn_dispatcher_t *disp)
   }
 }
 
-void pn_dispatcher_action(pn_dispatcher_t *disp, uint8_t code,
-                          pn_action_t *action)
-{
-  disp->actions[code] = action;
-}
-
 typedef enum {IN, OUT} pn_dir_t;
 
 static void pn_do_trace(pn_dispatcher_t *disp, uint16_t ch, pn_dir_t dir,
@@ -92,6 +116,10 @@ static void pn_do_trace(pn_dispatcher_t *disp, uint16_t ch, pn_dir_t dir,
     pn_string_format(disp->scratch, "%u %s ", ch, dir == OUT ? "->" : "<-");
     pn_inspect(args, disp->scratch);
 
+    if (pn_data_size(args)==0) {
+        pn_string_addf(disp->scratch, "(EMPTY FRAME)");
+    }
+
     if (size) {
       char buf[1024];
       int e = pn_quote_data(buf, 1024, payload, size);
@@ -122,7 +150,8 @@ int pn_dispatch_frame(pn_dispatcher_t *disp, pn_frame_t frame)
   }
 
   disp->channel = frame.channel;
-  // XXX: assuming numeric
+  // XXX: assuming numeric -
+  // if we get a symbol we should map it to the numeric value and dispatch on that
   uint64_t lcode;
   bool scanned;
   int e = pn_data_scan(disp->args, "D?L.", &scanned, &lcode);
@@ -134,19 +163,15 @@ int pn_dispatch_frame(pn_dispatcher_t *disp, pn_frame_t frame)
     pn_transport_log(disp->transport, "Error dispatching frame");
     return PN_ERR;
   }
-  uint8_t code = lcode;
-  disp->code = code;
   disp->size = frame.size - dsize;
   if (disp->size)
     disp->payload = frame.payload + dsize;
 
   pn_do_trace(disp, disp->channel, IN, disp->args, disp->payload, disp->size);
 
-  pn_action_t *action = disp->actions[code];
-  int err = action(disp);
+  int err = pni_dispatch_action(disp, lcode);
 
   disp->channel = 0;
-  disp->code = 0;
   pn_data_clear(disp->args);
   disp->size = 0;
   disp->payload = NULL;
@@ -212,7 +237,7 @@ int pn_post_frame(pn_dispatcher_t *disp, uint16_t ch, const char *fmt, ...)
 
  encode_performatives:
   pn_buffer_clear( disp->frame );
-  pn_bytes_t buf = pn_buffer_bytes( disp->frame );
+  pn_buffer_memory_t buf = pn_buffer_memory( disp->frame );
   buf.size = pn_buffer_available( disp->frame );
 
   ssize_t wr = pn_data_encode( disp->output_args, buf.start, buf.size );
@@ -290,7 +315,7 @@ int pn_post_transfer_frame(pn_dispatcher_t *disp, uint16_t ch,
 
   encode_performatives:
     pn_buffer_clear( disp->frame );
-    pn_bytes_t buf = pn_buffer_bytes( disp->frame );
+    pn_buffer_memory_t buf = pn_buffer_memory( disp->frame );
     buf.size = pn_buffer_available( disp->frame );
 
     ssize_t wr = pn_data_encode(disp->output_args, buf.start, buf.size);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/dispatcher/dispatcher.h
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatcher/dispatcher.h b/proton-c/src/dispatcher/dispatcher.h
index 80b6412..a87e383 100644
--- a/proton-c/src/dispatcher/dispatcher.h
+++ b/proton-c/src/dispatcher/dispatcher.h
@@ -33,17 +33,7 @@ typedef struct pn_dispatcher_t pn_dispatcher_t;
 
 typedef int (pn_action_t)(pn_dispatcher_t *disp);
 
-#define SCRATCH (1024)
-#define CODEC_LIMIT (1024)
-
 struct pn_dispatcher_t {
-  pn_action_t *actions[256];
-  uint8_t frame_type;
-  pn_trace_t trace;
-  pn_buffer_t *input;
-  size_t fragment;
-  uint16_t channel;
-  uint8_t code;
   pn_data_t *args;
   const char *payload;
   size_t size;
@@ -55,18 +45,19 @@ struct pn_dispatcher_t {
   size_t capacity;
   size_t available; /* number of raw bytes pending output */
   char *output;
-  pn_transport_t *transport;
-  bool halt;
-  bool batch;
+  pn_transport_t *transport; // TODO: We keep this to get access to logging - perhaps move logging
   uint64_t output_frames_ct;
   uint64_t input_frames_ct;
   pn_string_t *scratch;
+  pn_trace_t trace;
+  uint16_t channel;
+  uint8_t frame_type; // Used when constructing outgoing frames
+  bool halt;
+  bool batch;
 };
 
 pn_dispatcher_t *pn_dispatcher(uint8_t frame_type, pn_transport_t *transport);
 void pn_dispatcher_free(pn_dispatcher_t *disp);
-void pn_dispatcher_action(pn_dispatcher_t *disp, uint8_t code,
-                          pn_action_t *action);
 int pn_scan_args(pn_dispatcher_t *disp, const char *fmt, ...);
 void pn_set_payload(pn_dispatcher_t *disp, const char *data, size_t size);
 int pn_post_frame(pn_dispatcher_t *disp, uint16_t ch, const char *fmt, ...);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
index d13cd58..03cb630 100644
--- a/proton-c/src/engine/engine-internal.h
+++ b/proton-c/src/engine/engine-internal.h
@@ -51,6 +51,7 @@ struct pn_endpoint_t {
   pn_endpoint_t *transport_prev;
   bool modified;
   bool freed;
+  bool posted_final;
 };
 
 typedef struct {
@@ -95,8 +96,6 @@ typedef struct {
   bool disp;
 } pn_session_state_t;
 
-#define SCRATCH (1024)
-
 #include <proton/sasl.h>
 #include <proton/ssl.h>
 
@@ -111,21 +110,14 @@ typedef struct pn_io_layer_t {
 } pn_io_layer_t;
 
 struct pn_transport_t {
-  bool freed;
   pn_tracer_t tracer;
   size_t header_count;
   pn_sasl_t *sasl;
   pn_ssl_t *ssl;
   pn_connection_t *connection;  // reference counted
   pn_dispatcher_t *disp;
-  bool open_sent;
-  bool open_rcvd;
-  bool close_sent;
-  bool close_rcvd;
   char *remote_container;
   char *remote_hostname;
-  uint16_t channel_max;
-  uint16_t remote_channel_max;
   pn_data_t *remote_offered_capabilities;
   pn_data_t *remote_desired_capabilities;
   pn_data_t *remote_properties;
@@ -144,15 +136,14 @@ struct pn_transport_t {
 
   /* dead remote detection */
   pn_millis_t local_idle_timeout;
+  pn_millis_t remote_idle_timeout;
   pn_timestamp_t dead_remote_deadline;
   uint64_t last_bytes_input;
 
   /* keepalive */
-  pn_millis_t remote_idle_timeout;
   pn_timestamp_t keepalive_deadline;
   uint64_t last_bytes_output;
 
-  pn_error_t *error;
   pn_hash_t *local_channels;
   pn_hash_t *remote_channels;
   pn_string_t *scratch;
@@ -166,14 +157,23 @@ struct pn_transport_t {
   size_t output_pending;
   char *output_buf;
 
+  void *context;
+
   /* input from peer */
   size_t input_size;
   size_t input_pending;
   char *input_buf;
+
+  uint16_t channel_max;
+  uint16_t remote_channel_max;
+  bool freed;
+  bool open_sent;
+  bool open_rcvd;
+  bool close_sent;
+  bool close_rcvd;
   bool tail_closed;      // input stream closed by driver
   bool head_closed;
-
-  void *context;
+  bool done_processing; // if true, don't call pn_process again
 };
 
 struct pn_connection_t {
@@ -211,80 +211,80 @@ struct pn_session_t {
 };
 
 struct pn_terminus_t {
-  pn_terminus_type_t type;
   pn_string_t *address;
-  pn_durability_t durability;
-  pn_expiry_policy_t expiry_policy;
-  pn_seconds_t timeout;
-  bool dynamic;
-  pn_distribution_mode_t distribution_mode;
   pn_data_t *properties;
   pn_data_t *capabilities;
   pn_data_t *outcomes;
   pn_data_t *filter;
+  pn_durability_t durability;
+  pn_expiry_policy_t expiry_policy;
+  pn_seconds_t timeout;
+  pn_terminus_type_t type;
+  pn_distribution_mode_t distribution_mode;
+  bool dynamic;
 };
 
 struct pn_link_t {
   pn_endpoint_t endpoint;
-  pn_string_t *name;
-  pn_session_t *session;  // reference counted
   pn_terminus_t source;
   pn_terminus_t target;
   pn_terminus_t remote_source;
   pn_terminus_t remote_target;
+  pn_link_state_t state;
+  pn_string_t *name;
+  pn_session_t *session;  // reference counted
   pn_delivery_t *unsettled_head;
   pn_delivery_t *unsettled_tail;
   pn_delivery_t *current;
   pn_delivery_t *settled_head;
   pn_delivery_t *settled_tail;
-  uint8_t snd_settle_mode;
-  uint8_t rcv_settle_mode;
-  uint8_t remote_snd_settle_mode;
-  uint8_t remote_rcv_settle_mode;
+  void *context;
   size_t unsettled_count;
   pn_sequence_t available;
   pn_sequence_t credit;
   pn_sequence_t queued;
+  int drained; // number of drained credits
+  uint8_t snd_settle_mode;
+  uint8_t rcv_settle_mode;
+  uint8_t remote_snd_settle_mode;
+  uint8_t remote_rcv_settle_mode;
   bool drain_flag_mode; // receiver only
   bool drain;
-  int drained; // number of drained credits
-  void *context;
-  pn_link_state_t state;
 };
 
 struct pn_disposition_t {
+  pn_condition_t condition;
   uint64_t type;
   pn_data_t *data;
   pn_data_t *annotations;
-  pn_condition_t condition;
-  uint32_t section_number;
   uint64_t section_offset;
+  uint32_t section_number;
   bool failed;
   bool undeliverable;
   bool settled;
 };
 
 struct pn_delivery_t {
-  pn_link_t *link;  // reference counted
-  pn_buffer_t *tag;
   pn_disposition_t local;
   pn_disposition_t remote;
-  bool updated;
-  bool settled; // tracks whether we're in the unsettled list or not
+  pn_link_t *link;  // reference counted
+  pn_buffer_t *tag;
   pn_delivery_t *unsettled_next;
   pn_delivery_t *unsettled_prev;
   pn_delivery_t *settled_next;
   pn_delivery_t *settled_prev;
   pn_delivery_t *work_next;
   pn_delivery_t *work_prev;
-  bool work;
   pn_delivery_t *tpwork_next;
   pn_delivery_t *tpwork_prev;
-  bool tpwork;
+  pn_delivery_state_t state;
   pn_buffer_t *bytes;
-  bool done;
   void *context;
-  pn_delivery_state_t state;
+  bool updated;
+  bool settled; // tracks whether we're in the unsettled list or not
+  bool work;
+  bool tpwork;
+  bool done;
 };
 
 #define PN_SET_LOCAL(OLD, NEW)                                          \
@@ -310,5 +310,6 @@ void pn_clear_tpwork(pn_delivery_t *delivery);
 void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery);
 void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint);
 void pn_connection_unbound(pn_connection_t *conn);
+int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...);
 
 #endif /* engine-internal.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/engine/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine.c b/proton-c/src/engine/engine.c
index 718974a..02e5009 100644
--- a/proton-c/src/engine/engine.c
+++ b/proton-c/src/engine/engine.c
@@ -52,34 +52,18 @@ pn_connection_t *pn_ep_get_connection(pn_endpoint_t *endpoint)
   return NULL;
 }
 
-/* map the endpoint type to its local event type */
-static const pn_event_type_t endpoint_event_map[] = {
-  PN_CONNECTION_LOCAL_STATE,  /* CONNECTION */
-  PN_SESSION_LOCAL_STATE,     /* SESSION */
-  PN_LINK_LOCAL_STATE,        /* SENDER */
-  PN_LINK_LOCAL_STATE};       /* RECEIVER */
-
-/* setup the event given the endpoint that generated the event */
-static void endpoint_init_event(pn_event_t *event,
-                                pn_endpoint_t *endpoint)
-{
-  switch (endpoint->type) {
-  case CONNECTION: {
-      pn_connection_t *conn = (pn_connection_t *) endpoint;
-      pn_event_init_connection(event, conn);
-    }
-    break;
-  case SESSION: {
-      pn_session_t *ssn = (pn_session_t *) endpoint;
-      pn_event_init_session(event, ssn);
-    }
-    break;
+static pn_event_type_t endpoint_event(pn_endpoint_type_t type, bool open) {
+  switch (type) {
+  case CONNECTION:
+    return open ? PN_CONNECTION_OPEN : PN_CONNECTION_CLOSE;
+  case SESSION:
+    return open ? PN_SESSION_OPEN : PN_SESSION_CLOSE;
   case SENDER:
-  case RECEIVER: {
-      pn_link_t *link = (pn_link_t*) endpoint;
-      pn_event_init_link(event, link);
-    }
-    break;
+  case RECEIVER:
+    return open ? PN_LINK_OPEN : PN_LINK_CLOSE;
+  default:
+    assert(false);
+    return PN_EVENT_NONE;
   }
 }
 
@@ -88,11 +72,8 @@ static void pn_endpoint_open(pn_endpoint_t *endpoint)
   // TODO: do we care about the current state?
   PN_SET_LOCAL(endpoint->state, PN_LOCAL_ACTIVE);
   pn_connection_t *conn = pn_ep_get_connection(endpoint);
-  pn_event_t *event = pn_collector_put(conn->collector,
-                                       endpoint_event_map[endpoint->type]);
-  if (event) {
-    endpoint_init_event(event, endpoint);
-  }
+  pn_collector_put(conn->collector, endpoint_event(endpoint->type, true),
+                   endpoint);
   pn_modified(conn, endpoint, true);
 }
 
@@ -101,11 +82,8 @@ static void pn_endpoint_close(pn_endpoint_t *endpoint)
   // TODO: do we care about the current state?
   PN_SET_LOCAL(endpoint->state, PN_LOCAL_CLOSED);
   pn_connection_t *conn = pn_ep_get_connection(endpoint);
-  pn_event_t *event = pn_collector_put(conn->collector,
-                                       endpoint_event_map[endpoint->type]);
-  if (event) {
-    endpoint_init_event(event, endpoint);
-  }
+  pn_collector_put(conn->collector, endpoint_event(endpoint->type, false),
+                   endpoint);
   pn_modified(conn, endpoint, true);
 }
 
@@ -133,8 +111,6 @@ void pn_endpoint_tini(pn_endpoint_t *endpoint);
 void pn_connection_free(pn_connection_t *connection)
 {
   assert(!connection->endpoint.freed);
-  if (pn_connection_state(connection) & PN_LOCAL_ACTIVE)
-    pn_connection_close(connection);
   // free those endpoints that haven't been freed by the application
   LL_REMOVE(connection, endpoint, &connection->endpoint);
   while (connection->endpoint_head) {
@@ -200,7 +176,7 @@ void pn_condition_init(pn_condition_t *condition)
 {
   condition->name = pn_string(NULL);
   condition->description = pn_string(NULL);
-  condition->info = pn_data(16);
+  condition->info = pn_data(0);
 }
 
 void pn_condition_tini(pn_condition_t *condition)
@@ -214,7 +190,7 @@ void pn_add_session(pn_connection_t *conn, pn_session_t *ssn)
 {
   pn_list_add(conn->sessions, ssn);
   ssn->connection = conn;
-  pn_incref(conn);  // keep around until finalized
+  pn_incref2(conn, ssn);  // keep around until finalized
 }
 
 void pn_remove_session(pn_connection_t *conn, pn_session_t *ssn)
@@ -248,13 +224,11 @@ void pn_session_free(pn_session_t *session)
     pn_link_t *link = (pn_link_t *)pn_list_get(session->links, 0);
     pn_link_free(link);
   }
-  if (pn_session_state(session) & PN_LOCAL_ACTIVE)
-    pn_session_close(session);
   pn_remove_session(session->connection, session);
   pn_endpoint_t *endpoint = (pn_endpoint_t *) session;
   LL_REMOVE(pn_ep_get_connection(endpoint), endpoint, endpoint);
   session->endpoint.freed = true;
-  pn_decref(session);
+  pn_decref2(session, session->connection);
 }
 
 void *pn_session_get_context(pn_session_t *session)
@@ -304,8 +278,6 @@ void pn_terminus_free(pn_terminus_t *terminus)
 void pn_link_free(pn_link_t *link)
 {
   assert(!link->endpoint.freed);
-  if (pn_link_state(link) & PN_LOCAL_ACTIVE)
-    pn_link_close(link);
   pn_remove_link(link->session, link);
   pn_endpoint_t *endpoint = (pn_endpoint_t *) link;
   LL_REMOVE(pn_ep_get_connection(endpoint), endpoint, endpoint);
@@ -318,10 +290,10 @@ void pn_link_free(pn_link_t *link)
   while (link->settled_head) {
     delivery = link->settled_head;
     LL_POP(link, settled, pn_delivery_t);
-    pn_decref(delivery);
+    pn_decref2(delivery, link);
   }
   link->endpoint.freed = true;
-  pn_decref(link);
+  pn_decref2(link, link->session);
 }
 
 void *pn_link_get_context(pn_link_t *link)
@@ -348,6 +320,7 @@ void pn_endpoint_init(pn_endpoint_t *endpoint, int type, pn_connection_t *conn)
   endpoint->transport_prev = NULL;
   endpoint->modified = false;
   endpoint->freed = false;
+  endpoint->posted_final = false;
 
   LL_ADD(conn, endpoint, endpoint);
 }
@@ -359,16 +332,37 @@ void pn_endpoint_tini(pn_endpoint_t *endpoint)
   pn_condition_tini(&endpoint->condition);
 }
 
+#include "event.h"
+
+static bool pni_post_final(pn_endpoint_t *endpoint, pn_event_type_t type)
+{
+  pn_connection_t *conn = pn_ep_get_connection(endpoint);
+  if (!endpoint->posted_final) {
+    endpoint->posted_final = true;
+    pn_event_t *event = pn_collector_put(conn->collector, type, endpoint);
+    if (event) { return true; }
+  }
+
+  return false;
+}
+
 static void pn_connection_finalize(void *object)
 {
   pn_connection_t *conn = (pn_connection_t *) object;
+
+  pn_endpoint_t *endpoint = &conn->endpoint;
+  if (pni_post_final(endpoint, PN_CONNECTION_FINAL)) {
+    return;
+  }
+
+  pn_decref2(conn->collector, conn);
   pn_free(conn->sessions);
   pn_free(conn->container);
   pn_free(conn->hostname);
   pn_free(conn->offered_capabilities);
   pn_free(conn->desired_capabilities);
   pn_free(conn->properties);
-  pn_endpoint_tini(&conn->endpoint);
+  pn_endpoint_tini(endpoint);
 }
 
 #define pn_connection_initialize NULL
@@ -376,11 +370,9 @@ static void pn_connection_finalize(void *object)
 #define pn_connection_compare NULL
 #define pn_connection_inspect NULL
 
-#include "event.h"
-
 pn_connection_t *pn_connection()
 {
-  static pn_class_t clazz = PN_CLASS(pn_connection);
+  static const pn_class_t clazz = PN_CLASS(pn_connection);
   pn_connection_t *conn = (pn_connection_t *) pn_new(sizeof(pn_connection_t), &clazz);
   if (!conn) return NULL;
 
@@ -398,17 +390,30 @@ pn_connection_t *pn_connection()
   conn->tpwork_tail = NULL;
   conn->container = pn_string(NULL);
   conn->hostname = pn_string(NULL);
-  conn->offered_capabilities = pn_data(16);
-  conn->desired_capabilities = pn_data(16);
-  conn->properties = pn_data(16);
+  conn->offered_capabilities = pn_data(0);
+  conn->desired_capabilities = pn_data(0);
+  conn->properties = pn_data(0);
   conn->collector = NULL;
 
   return conn;
 }
 
+static const pn_event_type_t endpoint_init_event_map[] = {
+  PN_CONNECTION_INIT,  /* CONNECTION */
+  PN_SESSION_INIT,     /* SESSION */
+  PN_LINK_INIT,        /* SENDER */
+  PN_LINK_INIT};       /* RECEIVER */
+
 void pn_connection_collect(pn_connection_t *connection, pn_collector_t *collector)
 {
+  pn_decref2(connection->collector, connection);
   connection->collector = collector;
+  pn_incref2(connection->collector, connection);
+  pn_endpoint_t *endpoint = connection->endpoint_head;
+  while (endpoint) {
+    pn_collector_put(connection->collector, endpoint_init_event_map[endpoint->type], endpoint);
+    endpoint = endpoint->endpoint_next;
+  }
 }
 
 pn_state_t pn_connection_state(pn_connection_t *connection)
@@ -556,7 +561,7 @@ void pn_add_tpwork(pn_delivery_t *delivery)
   {
     LL_ADD(connection, tpwork, delivery);
     delivery->tpwork = true;
-    pn_incref(delivery);
+    pn_incref2(delivery, connection);
   }
   pn_modified(connection, &connection->endpoint, true);
 }
@@ -568,7 +573,7 @@ void pn_clear_tpwork(pn_delivery_t *delivery)
   {
     LL_REMOVE(connection, tpwork, delivery);
     delivery->tpwork = false;
-    pn_decref(delivery);  // may free delivery!
+    pn_decref2(delivery, connection);  // may free delivery!
   }
 }
 
@@ -590,14 +595,12 @@ void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit
   if (!endpoint->modified) {
     LL_ADD(connection, transport, endpoint);
     endpoint->modified = true;
-    pn_incref(endpoint);
+    pn_incref2(endpoint, connection);
   }
 
-  if (emit) {
-    pn_event_t *event = pn_collector_put(connection->collector, PN_TRANSPORT);
-    if (event) {
-      pn_event_init_connection(event, connection);
-    }
+  if (emit && connection->transport) {
+    pn_collector_put(connection->collector, PN_TRANSPORT,
+                     connection->transport);
   }
 }
 
@@ -608,7 +611,7 @@ void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint)
     endpoint->transport_next = NULL;
     endpoint->transport_prev = NULL;
     endpoint->modified = false;
-    pn_decref(endpoint);  // may free endpoint!
+    pn_decref2(endpoint, connection);  // may free endpoint!
   }
 }
 
@@ -687,6 +690,7 @@ pn_link_t *pn_link_next(pn_link_t *link, pn_state_t state)
 static void pn_session_finalize(void *object)
 {
   pn_session_t *session = (pn_session_t *) object;
+  pn_endpoint_t *endpoint = &session->endpoint;
   //pn_transport_t *transport = session->connection->transport;
   //if (transport) {
   /*   if ((int16_t)session->state.local_channel >= 0)  // END not sent */
@@ -695,13 +699,17 @@ static void pn_session_finalize(void *object)
   /*     pn_unmap_channel(transport, session); */
   /* } */
 
+  if (pni_post_final(endpoint, PN_SESSION_FINAL)) {
+    return;
+  }
+
   pn_free(session->links);
-  pn_endpoint_tini(&session->endpoint);
+  pn_endpoint_tini(endpoint);
   pn_delivery_map_free(&session->state.incoming);
   pn_delivery_map_free(&session->state.outgoing);
   pn_free(session->state.local_handles);
   pn_free(session->state.remote_handles);
-  pn_decref(session->connection);
+  pn_decref2(session->connection, session);
 }
 
 #define pn_session_initialize NULL
@@ -712,8 +720,8 @@ static void pn_session_finalize(void *object)
 pn_session_t *pn_session(pn_connection_t *conn)
 {
   assert(conn);
-  static pn_class_t clazz = PN_CLASS(pn_session);
-  pn_session_t *ssn = (pn_session_t *) pn_new(sizeof(pn_session_t), &clazz);
+  static const pn_class_t clazz = PN_CLASS(pn_session);
+  pn_session_t *ssn = (pn_session_t *) pn_new2(sizeof(pn_session_t), &clazz, conn);
   if (!ssn) return NULL;
 
   pn_endpoint_init(&ssn->endpoint, SESSION, conn);
@@ -736,6 +744,7 @@ pn_session_t *pn_session(pn_connection_t *conn)
   ssn->state.remote_handles = pn_hash(0, 0.75, PN_REFCOUNT);
   // end transport state
 
+  pn_collector_put(conn->collector, PN_SESSION_INIT, ssn);
   return ssn;
 }
 
@@ -779,31 +788,36 @@ void pn_terminus_init(pn_terminus_t *terminus, pn_terminus_type_t type)
   terminus->type = type;
   terminus->address = pn_string(NULL);
   terminus->durability = PN_NONDURABLE;
-  terminus->expiry_policy = PN_SESSION_CLOSE;
+  terminus->expiry_policy = PN_EXPIRE_WITH_SESSION;
   terminus->timeout = 0;
   terminus->dynamic = false;
   terminus->distribution_mode = PN_DIST_MODE_UNSPECIFIED;
-  terminus->properties = pn_data(16);
-  terminus->capabilities = pn_data(16);
-  terminus->outcomes = pn_data(16);
-  terminus->filter = pn_data(16);
+  terminus->properties = pn_data(0);
+  terminus->capabilities = pn_data(0);
+  terminus->outcomes = pn_data(0);
+  terminus->filter = pn_data(0);
 }
 
 static void pn_link_finalize(void *object)
 {
   pn_link_t *link = (pn_link_t *) object;
+  pn_endpoint_t *endpoint = &link->endpoint;
 
   // assumptions: all deliveries freed
   assert(link->settled_head == NULL);
   assert(link->unsettled_head == NULL);
 
+  if (pni_post_final(endpoint, PN_LINK_FINAL)) {
+    return;
+  }
+
   pn_terminus_free(&link->source);
   pn_terminus_free(&link->target);
   pn_terminus_free(&link->remote_source);
   pn_terminus_free(&link->remote_target);
   pn_free(link->name);
-  pn_endpoint_tini(&link->endpoint);
-  pn_decref(link->session);
+  pn_endpoint_tini(endpoint);
+  pn_decref2(link->session, link);
 }
 
 #define pn_link_initialize NULL
@@ -813,12 +827,12 @@ static void pn_link_finalize(void *object)
 
 pn_link_t *pn_link_new(int type, pn_session_t *session, const char *name)
 {
-  static pn_class_t clazz = PN_CLASS(pn_link);
-  pn_link_t *link = (pn_link_t *) pn_new(sizeof(pn_link_t), &clazz);
+  static const pn_class_t clazz = PN_CLASS(pn_link);
+  pn_link_t *link = (pn_link_t *) pn_new2(sizeof(pn_link_t), &clazz, session);
 
   pn_endpoint_init(&link->endpoint, type, session->connection);
   pn_add_link(session, link);
-  pn_incref(session);  // keep session until link finalized
+  pn_incref2(session, link);  // keep session until link finalized
   link->name = pn_string(name);
   pn_terminus_init(&link->source, PN_SOURCE);
   pn_terminus_init(&link->target, PN_TARGET);
@@ -844,8 +858,9 @@ pn_link_t *pn_link_new(int type, pn_session_t *session, const char *name)
   link->state.remote_handle = -1;
   link->state.delivery_count = 0;
   link->state.link_credit = 0;
-  // end transport stat
+  // end transport state
 
+  pn_collector_put(session->connection->collector, PN_LINK_INIT, link);
   return link;
 }
 
@@ -1057,13 +1072,13 @@ static void pn_delivery_finalize(void *object)
   pn_buffer_free(delivery->bytes);
   pn_disposition_finalize(&delivery->local);
   pn_disposition_finalize(&delivery->remote);
-  pn_decref(delivery->link);
+  pn_decref2(delivery->link, delivery);
 }
 
 static void pn_disposition_init(pn_disposition_t *ds)
 {
-  ds->data = pn_data(16);
-  ds->annotations = pn_data(16);
+  ds->data = pn_data(0);
+  ds->annotations = pn_data(0);
   pn_condition_init(&ds->condition);
 }
 
@@ -1091,11 +1106,11 @@ pn_delivery_t *pn_delivery(pn_link_t *link, pn_delivery_tag_t tag)
   pn_delivery_t *delivery = link->settled_head;
   LL_POP(link, settled, pn_delivery_t);
   if (!delivery) {
-    static pn_class_t clazz = PN_CLASS(pn_delivery);
-    delivery = (pn_delivery_t *) pn_new(sizeof(pn_delivery_t), &clazz);
+    static const pn_class_t clazz = PN_CLASS(pn_delivery);
+    delivery = (pn_delivery_t *) pn_new2(sizeof(pn_delivery_t), &clazz, link);
     if (!delivery) return NULL;
     delivery->link = link;
-    pn_incref(delivery->link);  // keep link until finalized
+    pn_incref2(delivery->link, delivery);  // keep link until finalized
     delivery->tag = pn_buffer(16);
     delivery->bytes = pn_buffer(64);
     pn_disposition_init(&delivery->local);
@@ -1442,6 +1457,7 @@ ssize_t pn_link_send(pn_link_t *sender, const char *bytes, size_t n)
 {
   pn_delivery_t *current = pn_link_current(sender);
   if (!current) return PN_EOS;
+  if (!bytes || !n) return 0;
   pn_buffer_append(current->bytes, bytes, n);
   sender->session->outgoing_bytes += n;
   pn_add_tpwork(current);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/engine/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/event.c b/proton-c/src/engine/event.c
index 9a3f220..07e3cb5 100644
--- a/proton-c/src/engine/event.c
+++ b/proton-c/src/engine/event.c
@@ -6,16 +6,13 @@ struct pn_collector_t {
   pn_event_t *head;
   pn_event_t *tail;
   pn_event_t *free_head;
+  bool freed;
 };
 
 struct pn_event_t {
-  pn_event_type_t type;
-  pn_connection_t *connection;
-  pn_session_t *session;
-  pn_link_t *link;
-  pn_delivery_t *delivery;
-  pn_transport_t *transport;
+  void *context;    // depends on type
   pn_event_t *next;
+  pn_event_type_t type;
 };
 
 static void pn_collector_initialize(void *obj)
@@ -24,25 +21,36 @@ static void pn_collector_initialize(void *obj)
   collector->head = NULL;
   collector->tail = NULL;
   collector->free_head = NULL;
+  collector->freed = false;
 }
 
-static void pn_collector_finalize(void *obj)
+static void pn_collector_drain(pn_collector_t *collector)
 {
-  pn_collector_t *collector = (pn_collector_t *) obj;
-
   while (pn_collector_peek(collector)) {
     pn_collector_pop(collector);
   }
 
   assert(!collector->head);
   assert(!collector->tail);
+}
 
+static void pn_collector_shrink(pn_collector_t *collector)
+{
   pn_event_t *event = collector->free_head;
   while (event) {
     pn_event_t *next = event->next;
     pn_free(event);
     event = next;
   }
+
+  collector->free_head = NULL;
+}
+
+static void pn_collector_finalize(void *obj)
+{
+  pn_collector_t *collector = (pn_collector_t *) obj;
+  pn_collector_drain(collector);
+  pn_collector_shrink(collector);
 }
 
 static int pn_collector_inspect(void *obj, pn_string_t *dst)
@@ -72,25 +80,39 @@ static int pn_collector_inspect(void *obj, pn_string_t *dst)
 
 pn_collector_t *pn_collector(void)
 {
-  static pn_class_t clazz = PN_CLASS(pn_collector);
+  static const pn_class_t clazz = PN_CLASS(pn_collector);
   pn_collector_t *collector = (pn_collector_t *) pn_new(sizeof(pn_collector_t), &clazz);
   return collector;
 }
 
 void pn_collector_free(pn_collector_t *collector)
 {
-  pn_free(collector);
+  collector->freed = true;
+  pn_collector_drain(collector);
+  pn_collector_shrink(collector);
+  pn_decref(collector);
 }
 
 pn_event_t *pn_event(void);
 static void pn_event_initialize(void *obj);
 
-pn_event_t *pn_collector_put(pn_collector_t *collector, pn_event_type_t type)
+pn_event_t *pn_collector_put(pn_collector_t *collector, pn_event_type_t type, void *context)
 {
   if (!collector) {
     return NULL;
   }
 
+  assert(context);
+
+  if (collector->freed) {
+    return NULL;
+  }
+
+  pn_event_t *tail = collector->tail;
+  if (tail && tail->type == type && tail->context == context) {
+    return NULL;
+  }
+
   pn_event_t *event;
 
   if (collector->free_head) {
@@ -101,8 +123,6 @@ pn_event_t *pn_collector_put(pn_collector_t *collector, pn_event_type_t type)
     event = pn_event();
   }
 
-  pn_event_t *tail = collector->tail;
-
   if (tail) {
     tail->next = event;
     collector->tail = event;
@@ -112,26 +132,16 @@ pn_event_t *pn_collector_put(pn_collector_t *collector, pn_event_type_t type)
   }
 
   event->type = type;
+  event->context = context;
+  pn_incref2(event->context, collector);
+
+  //printf("event %s on %p\n", pn_event_type_name(event->type), event->context);
 
   return event;
 }
 
 pn_event_t *pn_collector_peek(pn_collector_t *collector)
 {
-  // discard any events for objects that no longer exist
-  pn_event_t *event = collector->head;
-  while (event && ((event->delivery && event->delivery->local.settled)
-                   ||
-                   (event->link && event->link->endpoint.freed)
-                   ||
-                   (event->session && event->session->endpoint.freed)
-                   ||
-                   (event->connection && event->connection->endpoint.freed)
-                   ||
-                   (event->transport && event->transport->freed))) {
-    pn_collector_pop(collector);
-    event = collector->head;
-  }
   return collector->head;
 }
 
@@ -148,15 +158,15 @@ bool pn_collector_pop(pn_collector_t *collector)
     collector->tail = NULL;
   }
 
+  // decref before adding to the free list
+  if (event->context) {
+    pn_decref2(event->context, collector);
+    event->context = NULL;
+  }
+
   event->next = collector->free_head;
   collector->free_head = event;
 
-  if (event->connection) pn_decref(event->connection);
-  if (event->session) pn_decref(event->session);
-  if (event->link) pn_decref(event->link);
-  if (event->delivery) pn_decref(event->delivery);
-  if (event->transport) pn_decref(event->transport);
-
   return true;
 }
 
@@ -164,11 +174,7 @@ static void pn_event_initialize(void *obj)
 {
   pn_event_t *event = (pn_event_t *) obj;
   event->type = PN_EVENT_NONE;
-  event->connection = NULL;
-  event->session = NULL;
-  event->link = NULL;
-  event->delivery = NULL;
-  event->transport = NULL;
+  event->context = NULL;
   event->next = NULL;
 }
 
@@ -178,16 +184,12 @@ static int pn_event_inspect(void *obj, pn_string_t *dst)
 {
   assert(obj);
   pn_event_t *event = (pn_event_t *) obj;
-  int err = pn_string_addf(dst, "(%d", event->type);
-  void *objects[] = {event->connection, event->session, event->link,
-                     event->delivery, event->transport};
-  for (int i = 0; i < 5; i++) {
-    if (objects[i]) {
-      err = pn_string_addf(dst, ", ");
-      if (err) return err;
-      err = pn_inspect(objects[i], dst);
-      if (err) return err;
-    }
+  int err = pn_string_addf(dst, "(0x%X", (unsigned int)event->type);
+  if (event->context) {
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    err = pn_inspect(event->context, dst);
+    if (err) return err;
   }
 
   return pn_string_addf(dst, ")");
@@ -198,45 +200,11 @@ static int pn_event_inspect(void *obj, pn_string_t *dst)
 
 pn_event_t *pn_event(void)
 {
-  static pn_class_t clazz = PN_CLASS(pn_event);
+  static const pn_class_t clazz = PN_CLASS(pn_event);
   pn_event_t *event = (pn_event_t *) pn_new(sizeof(pn_event_t), &clazz);
   return event;
 }
 
-void pn_event_init_transport(pn_event_t *event, pn_transport_t *transport)
-{
-  event->transport = transport;
-  pn_incref(event->transport);
-}
-
-void pn_event_init_connection(pn_event_t *event, pn_connection_t *connection)
-{
-  event->connection = connection;
-  pn_event_init_transport(event, event->connection->transport);
-  pn_incref(event->connection);
-}
-
-void pn_event_init_session(pn_event_t *event, pn_session_t *session)
-{
-  event->session = session;
-  pn_event_init_connection(event, pn_session_connection(event->session));
-  pn_incref(event->session);
-}
-
-void pn_event_init_link(pn_event_t *event, pn_link_t *link)
-{
-  event->link = link;
-  pn_event_init_session(event, pn_link_session(event->link));
-  pn_incref(event->link);
-}
-
-void pn_event_init_delivery(pn_event_t *event, pn_delivery_t *delivery)
-{
-  event->delivery = delivery;
-  pn_event_init_link(event, pn_delivery_link(delivery));
-  pn_incref(event->delivery);
-}
-
 pn_event_type_t pn_event_type(pn_event_t *event)
 {
   return event->type;
@@ -247,29 +215,84 @@ pn_event_category_t pn_event_category(pn_event_t *event)
   return (pn_event_category_t)(event->type & 0xFFFF0000);
 }
 
+void *pn_event_context(pn_event_t *event)
+{
+  assert(event);
+  return event->context;
+}
+
 pn_connection_t *pn_event_connection(pn_event_t *event)
 {
-  return event->connection;
+  pn_session_t *ssn;
+  pn_transport_t *transport;
+
+  switch (pn_event_category(event)) {
+  case PN_EVENT_CATEGORY_CONNECTION:
+    return (pn_connection_t *)event->context;
+  case PN_EVENT_CATEGORY_TRANSPORT:
+    transport = pn_event_transport(event);
+    if (transport)
+      return transport->connection;
+    return NULL;
+  default:
+    ssn = pn_event_session(event);
+    if (ssn)
+     return pn_session_connection(ssn);
+  }
+  return NULL;
 }
 
 pn_session_t *pn_event_session(pn_event_t *event)
 {
-  return event->session;
+  pn_link_t *link;
+  switch (pn_event_category(event)) {
+  case PN_EVENT_CATEGORY_SESSION:
+    return (pn_session_t *)event->context;
+  default:
+    link = pn_event_link(event);
+    if (link)
+      return pn_link_session(link);
+  }
+  return NULL;
 }
 
 pn_link_t *pn_event_link(pn_event_t *event)
 {
-  return event->link;
+  pn_delivery_t *dlv;
+  switch (pn_event_category(event)) {
+  case PN_EVENT_CATEGORY_LINK:
+    return (pn_link_t *)event->context;
+  default:
+    dlv = pn_event_delivery(event);
+    if (dlv)
+      return pn_delivery_link(dlv);
+  }
+  return NULL;
 }
 
 pn_delivery_t *pn_event_delivery(pn_event_t *event)
 {
-  return event->delivery;
+  switch (pn_event_category(event)) {
+  case PN_EVENT_CATEGORY_DELIVERY:
+    return (pn_delivery_t *)event->context;
+  default:
+    return NULL;
+  }
 }
 
 pn_transport_t *pn_event_transport(pn_event_t *event)
 {
-  return event->transport;
+  switch (pn_event_category(event)) {
+  case PN_EVENT_CATEGORY_TRANSPORT:
+    return (pn_transport_t *)event->context;
+  default:
+    {
+      pn_connection_t *conn = pn_event_connection(event);
+      if (conn)
+        return pn_connection_transport(conn);
+      return NULL;
+    }
+  }
 }
 
 const char *pn_event_type_name(pn_event_type_t type)
@@ -277,20 +300,44 @@ const char *pn_event_type_name(pn_event_type_t type)
   switch (type) {
   case PN_EVENT_NONE:
     return "PN_EVENT_NONE";
-  case PN_CONNECTION_REMOTE_STATE:
-    return "PN_CONNECTION_REMOTE_STATE";
-  case PN_CONNECTION_LOCAL_STATE:
-    return "PN_CONNECTION_LOCAL_STATE";
-  case PN_SESSION_REMOTE_STATE:
-    return "PN_SESSION_REMOTE_STATE";
-  case PN_SESSION_LOCAL_STATE:
-    return "PN_SESSION_LOCAL_STATE";
-  case PN_LINK_REMOTE_STATE:
-    return "PN_LINK_REMOTE_STATE";
-  case PN_LINK_LOCAL_STATE:
-    return "PN_LINK_LOCAL_STATE";
+  case PN_CONNECTION_INIT:
+    return "PN_CONNECTION_INIT";
+  case PN_CONNECTION_REMOTE_OPEN:
+    return "PN_CONNECTION_REMOTE_OPEN";
+  case PN_CONNECTION_OPEN:
+    return "PN_CONNECTION_OPEN";
+  case PN_CONNECTION_REMOTE_CLOSE:
+    return "PN_CONNECTION_REMOTE_CLOSE";
+  case PN_CONNECTION_CLOSE:
+    return "PN_CONNECTION_CLOSE";
+  case PN_CONNECTION_FINAL:
+    return "PN_CONNECTION_FINAL";
+  case PN_SESSION_INIT:
+    return "PN_SESSION_INIT";
+  case PN_SESSION_REMOTE_OPEN:
+    return "PN_SESSION_REMOTE_OPEN";
+  case PN_SESSION_OPEN:
+    return "PN_SESSION_OPEN";
+  case PN_SESSION_REMOTE_CLOSE:
+    return "PN_SESSION_REMOTE_CLOSE";
+  case PN_SESSION_CLOSE:
+    return "PN_SESSION_CLOSE";
+  case PN_SESSION_FINAL:
+    return "PN_SESSION_FINAL";
+  case PN_LINK_INIT:
+    return "PN_LINK_INIT";
+  case PN_LINK_REMOTE_OPEN:
+    return "PN_LINK_REMOTE_OPEN";
+  case PN_LINK_OPEN:
+    return "PN_LINK_OPEN";
+  case PN_LINK_REMOTE_CLOSE:
+    return "PN_LINK_REMOTE_CLOSE";
+  case PN_LINK_CLOSE:
+    return "PN_LINK_CLOSE";
   case PN_LINK_FLOW:
     return "PN_LINK_FLOW";
+  case PN_LINK_FINAL:
+    return "PN_LINK_FINAL";
   case PN_DELIVERY:
     return "PN_DELIVERY";
   case PN_TRANSPORT:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/engine/event.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/event.h b/proton-c/src/engine/event.h
index 80f3422..b05f2d0 100644
--- a/proton-c/src/engine/event.h
+++ b/proton-c/src/engine/event.h
@@ -22,12 +22,7 @@
  *
  */
 
-pn_event_t *pn_collector_put(pn_collector_t *collector, pn_event_type_t type);
-
-void pn_event_init_transport(pn_event_t *event, pn_transport_t *transport);
-void pn_event_init_connection(pn_event_t *event, pn_connection_t *connection);
-void pn_event_init_session(pn_event_t *event, pn_session_t *session);
-void pn_event_init_link(pn_event_t *event, pn_link_t *link);
-void pn_event_init_delivery(pn_event_t *event, pn_delivery_t *delivery);
+pn_event_t *pn_collector_put(pn_collector_t *collector, pn_event_type_t type,
+                             void *context);
 
 #endif /* event.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/error.c
----------------------------------------------------------------------
diff --git a/proton-c/src/error.c b/proton-c/src/error.c
index 77a3dc2..c3cf36a 100644
--- a/proton-c/src/error.c
+++ b/proton-c/src/error.c
@@ -27,9 +27,9 @@
 #include "platform.h"
 
 struct pn_error_t {
-  int code;
   char *text;
   pn_error_t *root;
+  int code;
 };
 
 pn_error_t *pn_error()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/message/message.c
----------------------------------------------------------------------
diff --git a/proton-c/src/message/message.c b/proton-c/src/message/message.c
index 6c1088a..d91ab63 100644
--- a/proton-c/src/message/message.c
+++ b/proton-c/src/message/message.c
@@ -49,11 +49,8 @@ ssize_t pn_message_data(char *dst, size_t available, const char *src, size_t siz
 // message
 
 struct pn_message_t {
-  bool durable;
-  uint8_t priority;
-  pn_millis_t ttl;
-  bool first_acquirer;
-  uint32_t delivery_count;
+  pn_timestamp_t expiry_time;
+  pn_timestamp_t creation_time;
   pn_data_t *id;
   pn_string_t *user_id;
   pn_string_t *address;
@@ -62,22 +59,28 @@ struct pn_message_t {
   pn_data_t *correlation_id;
   pn_string_t *content_type;
   pn_string_t *content_encoding;
-  pn_timestamp_t expiry_time;
-  pn_timestamp_t creation_time;
   pn_string_t *group_id;
-  pn_sequence_t group_sequence;
   pn_string_t *reply_to_group_id;
 
-  bool inferred;
   pn_data_t *data;
   pn_data_t *instructions;
   pn_data_t *annotations;
   pn_data_t *properties;
   pn_data_t *body;
 
-  pn_format_t format;
   pn_parser_t *parser;
   pn_error_t *error;
+
+  pn_format_t format;
+  pn_sequence_t group_sequence;
+  pn_millis_t ttl;
+  uint32_t delivery_count;
+
+  uint8_t priority;
+
+  bool durable;
+  bool first_acquirer;
+  bool inferred;
 };
 
 void pn_message_finalize(void *obj)
@@ -318,7 +321,7 @@ int pn_message_inspect(void *obj, pn_string_t *dst)
 
 pn_message_t *pn_message()
 {
-  static pn_class_t clazz = PN_CLASS(pn_message);
+  static const pn_class_t clazz = PN_CLASS(pn_message);
   pn_message_t *msg = (pn_message_t *) pn_new(sizeof(pn_message_t), &clazz);
   msg->durable = false;
   msg->priority = PN_DEFAULT_PRIORITY;


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


[39/51] [abbrv] qpid-proton git commit: Improve check for node.js in examples. Add mechanism for clients to increase stack as well as total memory - NB this feature requires emscripten fix only recently applied to incoming so may not be available in SDK

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/examples/messenger/javascript/qpid-config.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/qpid-config.js b/examples/messenger/javascript/qpid-config.js
index 67d84a2..2f2a2ee 100755
--- a/examples/messenger/javascript/qpid-config.js
+++ b/examples/messenger/javascript/qpid-config.js
@@ -37,1472 +37,1475 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("qpid-config.js should be run in Node.js");
-    return;
-}
-
-var qmf = {}; // Create qmf namespace object.
-qmf.Console = function() { // qmf.Console Constructor.
-    var proton = require("qpid-proton");
-    var message = new proton.Message();
-    var messenger = new proton.Messenger();
-
-    var brokerAddress = '';
-    var replyTo = '';
-
-    /**
-     * The correlator object is a mechanism used to correlate requests with their
-     * aynchronous responses. It might possible be better to make use of Promises
-     * to implement part of this behaviour but a mechanism would still be needed to
-     * correlate a request with its response callback in order to wrap things up in
-     * a Promise, so much of the behaviour of this object would still be required.
-     * In addition it seemed to make sense to make this QMF2 implementation fairly
-     * free of dependencies and using Promises would require external libraries.
-     * Instead the correlator implements "Promise-like" semantics, you might call it
-     * a broken Promise :-)
-     * <p>
-     * in particular the request method behaves a *bit* like Promise.all() though it
-     * is mostly fake and takes an array of functions that call the add() method
-     * which is really the method used to associate response objects by correlationID.
-     * The then method is used to register a listener that will be called when all
-     * the requests that have been registered have received responses.
-     * TODO error/timeout handling.
-     */
-    var correlator = {
-        _resolve: null,
-        _objects: {},
-        add: function(id) {
-            this._objects[id] = {complete: false, list: null};
-        },
-        request: function() {
-            this._resolve = function() {console.log("Warning: No resolver has been set")};
-            return this;
-        },
-        then: function(resolver) {
-            this._resolve = resolver ? resolver : this._resolve;
-        },
-        resolve: function() {
-            var opcode = message.properties['qmf.opcode'];
-            var correlationID = message.getCorrelationID();
-            var resp = this._objects[correlationID];
-            if (opcode === '_query_response') {
-                if (resp.list) {
-                    Array.prototype.push.apply(resp.list, message.body); // This is faster than concat.
-                } else {
+if (typeof process === 'object' && typeof require === 'function') {
+
+    var qmf = {}; // Create qmf namespace object.
+    qmf.Console = function() { // qmf.Console Constructor.
+        var proton = require("qpid-proton");
+        var message = new proton.Message();
+        var messenger = new proton.Messenger();
+
+        var brokerAddress = '';
+        var replyTo = '';
+
+        /**
+         * The correlator object is a mechanism used to correlate requests with
+         * their aynchronous responses. It might possible be better to make use
+         * of Promises to implement part of this behaviour but a mechanism would
+         * still be needed to correlate a request with its response callback in
+         * order to wrap things up in a Promise, so much of the behaviour of this
+         * object would still be required. In addition it seemed to make sense to
+         * make this QMF2 implementation fairly free of dependencies and using
+         * Promises would require external libraries. Instead the correlator
+         * implements "Promise-like" semantics, you might say a broken Promise :-)
+         * <p>
+         * in particular the request method behaves a *bit* like Promise.all()
+         * though it is mostly fake and takes an array of functions that call
+         * the add() method which is really the method used to associate response
+         * objects by correlationID. The then method is used to register a
+         * listener that will be called when all the requests that have been
+         * registered have received responses.
+         * TODO error/timeout handling.
+         */
+        var correlator = {
+            _resolve: null,
+            _objects: {},
+            add: function(id) {
+                this._objects[id] = {complete: false, list: null};
+            },
+            request: function() {
+                this._resolve = function() {console.log("Warning: No resolver has been set")};
+                return this;
+            },
+            then: function(resolver) {
+                this._resolve = resolver ? resolver : this._resolve;
+            },
+            resolve: function() {
+                var opcode = message.properties['qmf.opcode'];
+                var correlationID = message.getCorrelationID();
+                var resp = this._objects[correlationID];
+                if (opcode === '_query_response') {
+                    if (resp.list) {
+                        Array.prototype.push.apply(resp.list, message.body); // This is faster than concat.
+                    } else {
+                        resp.list = message.body;
+                    }
+        
+                    var partial = message.properties['partial'];
+                    if (!partial) {
+                        resp.complete = true;
+                    }
+        
+                    this._objects[correlationID] = resp;
+                    this._checkComplete();
+                } else if (opcode === '_method_response' || opcode === '_exception') {
                     resp.list = message.body;
-                }
-    
-                var partial = message.properties['partial'];
-                if (!partial) {
                     resp.complete = true;
+                    this._objects[correlationID] = resp;
+                    this._checkComplete();
+                } else {
+                    console.error("Bad Message response, qmf.opcode = " + opcode);
+                }
+            },
+            _checkComplete: function() {
+                var response = {};
+                for (var id in this._objects) {
+                    var object = this._objects[id];
+                    if (object.complete) {
+                        response[id] = object.list;
+                    } else {
+                        return;
+                    }
                 }
     
-                this._objects[correlationID] = resp;
-                this._checkComplete();
-            } else if (opcode === '_method_response' || opcode === '_exception') {
-                resp.list = message.body;
-                resp.complete = true;
-                this._objects[correlationID] = resp;
-                this._checkComplete();
-            } else {
-                console.error("Bad Message response, qmf.opcode = " + opcode);
+                this._objects = {}; // Clear state ready for next call.
+                this._resolve(response.method ? response.method : response);
             }
-        },
-        _checkComplete: function() {
-            var response = {};
-            for (var id in this._objects) {
-                var object = this._objects[id];
-                if (object.complete) {
-                    response[id] = object.list;
-                } else {
-                    return;
-                }
+        };  // End of correlator object definition.
+
+        var pumpData = function() {
+            while (messenger.incoming()) {
+                // The second parameter forces Binary payloads to be decoded as
+                // strings this is useful because the broker QMF Agent encodes
+                // strings as AMQP binary unfortunately.
+                var t = messenger.get(message, true);
+                correlator.resolve();
+                messenger.accept(t);
             }
     
-            this._objects = {}; // Clear state ready for next call.
-            this._resolve(response.method ? response.method : response);
-        }
-    };  
-
-    var pumpData = function() {
-        while (messenger.incoming()) {
-            // The second parameter forces Binary payloads to be decoded as strings
-            // this is useful because the broker QMF Agent encodes strings as AMQP
-            // binary, which is a right pain from an interoperability perspective.
-            var t = messenger.get(message, true);
-            correlator.resolve();
-            messenger.accept(t);
-        }
-
-        if (messenger.isStopped()) {
-            message.free();
-            messenger.free();
-        }
-    };
-
-    this.getObjects = function(packageName, className) {
-        message.setAddress(brokerAddress);
-        message.setSubject('broker');
-        message.setReplyTo(replyTo);
-        message.setCorrelationID(className);
-        message.properties = {
-            "routing-key": "broker", // Added for Java Broker
-            "x-amqp-0-10.app-id": "qmf2",
-            "method": "request",
-            "qmf.opcode": "_query_request",
-        };
-        message.body = {
-            "_what": "OBJECT",
-            "_schema_id": {
-                "_package_name": packageName,
-                "_class_name": className
+            if (messenger.isStopped()) {
+                message.free();
+                messenger.free();
             }
         };
-
-        correlator.add(className);
-        messenger.put(message);
-    };
-
-    this.invokeMethod = function(object, method, arguments) {
-        var correlationID = 'method';
-        message.setAddress(brokerAddress);
-        message.setSubject('broker');
-        message.setReplyTo(replyTo);
-        message.setCorrelationID(correlationID);
-        message.properties = {
-            "routing-key": "broker", // Added for Java Broker
-            "x-amqp-0-10.app-id": "qmf2",
-            "method": "request",
-            "qmf.opcode": "_method_request",
-        };
-        message.body = {
-            "_object_id": object._object_id,
-            "_method_name" : method,
-            "_arguments"   : arguments
+    
+        this.getObjects = function(packageName, className) {
+            message.setAddress(brokerAddress);
+            message.setSubject('broker');
+            message.setReplyTo(replyTo);
+            message.setCorrelationID(className);
+            message.properties = {
+                "routing-key": "broker", // Added for Java Broker
+                "x-amqp-0-10.app-id": "qmf2",
+                "method": "request",
+                "qmf.opcode": "_query_request",
+            };
+            message.body = {
+                "_what": "OBJECT",
+                "_schema_id": {
+                    "_package_name": packageName,
+                    "_class_name": className
+                }
+            };
+    
+            correlator.add(className);
+            messenger.put(message);
         };
 
-        correlator.add(correlationID);
-        messenger.put(message);
-    };
-
-    this.addConnection = function(addr, callback) {
-        brokerAddress = addr + '/qmf.default.direct';
-        var replyAddress = addr + '/#';
-
-        messenger.on('subscription', function(subscription) {
-            var subscriptionAddress = subscription.getAddress();
-            var splitAddress = subscriptionAddress.split('/');
-            replyTo = splitAddress[splitAddress.length - 1];
-            callback();
-        });
-
-        messenger.subscribe(replyAddress);
-    }
-
-    this.destroy = function() {
-        messenger.stop(); 
-    }
-
-    this.request = function() {return correlator.request();}
-
-    messenger.on('error', function(error) {console.log(error);});
-    messenger.on('work', pumpData);
-    messenger.setOutgoingWindow(1024);
-    messenger.recv(); // Receive as many messages as messenger can buffer.
-    messenger.start();
-};
-
-
-/************************* qpid-config business logic ************************/
-
-var brokerAgent = new qmf.Console();
-
-var _usage =
-'Usage:  qpid-config [OPTIONS]\n' +
-'        qpid-config [OPTIONS] exchanges [filter-string]\n' +
-'        qpid-config [OPTIONS] queues    [filter-string]\n' +
-'        qpid-config [OPTIONS] add exchange <type> <name> [AddExchangeOptions]\n' +
-'        qpid-config [OPTIONS] del exchange <name>\n' +
-'        qpid-config [OPTIONS] add queue <name> [AddQueueOptions]\n' +
-'        qpid-config [OPTIONS] del queue <name> [DelQueueOptions]\n' +
-'        qpid-config [OPTIONS] bind   <exchange-name> <queue-name> [binding-key]\n' +
-'                  <for type xml>     [-f -|filename]\n' +
-'                  <for type header>  [all|any] k1=v1 [, k2=v2...]\n' +
-'        qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]\n' +
-'        qpid-config [OPTIONS] reload-acl\n' +
-'        qpid-config [OPTIONS] add <type> <name> [--argument <property-name>=<property-value>]\n' +
-'        qpid-config [OPTIONS] del <type> <name>\n' +
-'        qpid-config [OPTIONS] list <type> [--show-property <property-name>]\n';
-
-var usage = function() {
-    console.log(_usage);
-    process.exit(-1);
-};
-
-var _description =
-'Examples:\n' +
-'\n' +
-'$ qpid-config add queue q\n' +
-'$ qpid-config add exchange direct d -a localhost:5672\n' +
-'$ qpid-config exchanges -b 10.1.1.7:10000\n' +
-'$ qpid-config queues -b guest/guest@broker-host:10000\n' +
-'\n' +
-'Add Exchange <type> values:\n' +
-'\n' +
-'    direct     Direct exchange for point-to-point communication\n' +
-'    fanout     Fanout exchange for broadcast communication\n' +
-'    topic      Topic exchange that routes messages using binding keys with wildcards\n' +
-'    headers    Headers exchange that matches header fields against the binding keys\n' +
-'    xml        XML Exchange - allows content filtering using an XQuery\n' +
-'\n' +
-'\n' +
-'Queue Limit Actions:\n' +
-'\n' +
-'    none (default) - Use broker\'s default policy\n' +
-'    reject         - Reject enqueued messages\n' +
-'    ring           - Replace oldest unacquired message with new\n' +
-'\n' +
-'Replication levels:\n' +
-'\n' +
-'    none           - no replication\n' +
-'    configuration  - replicate queue and exchange existence and bindings, but not messages.\n' +
-'    all            - replicate configuration and messages\n';
-
-var _options =
-'Options:\n' +
-'  -h, --help            show this help message and exit\n' +
-'\n' +
-'  General Options:\n' +
-'    -t <secs>, --timeout=<secs>\n' +
-'                        Maximum time to wait for broker connection (in\n' +
-'                        seconds)\n' +
-'    -r, --recursive     Show bindings in queue or exchange list\n' +
-'    -b <address>, --broker=<address>\n' +
-'                        Address of qpidd broker with syntax:\n' +
-'                        [username/password@] hostname | ip-address [:<port>]\n' +
-'    -a <address>, --broker-addr=<address>\n' +
-/* TODO Connection options
-'    --sasl-mechanism=<mech>\n' +
-'                        SASL mechanism for authentication (e.g. EXTERNAL,\n' +
-'                        ANONYMOUS, PLAIN, CRAM-MD5, DIGEST-MD5, GSSAPI). SASL\n' +
-'                        automatically picks the most secure available\n' +
-'                        mechanism - use this option to override.\n' +
-'    --ssl-certificate=<cert>\n' +
-'                        Client SSL certificate (PEM Format)\n' +
-'    --ssl-key=<key>     Client SSL private key (PEM Format)\n' +
-'    --ha-admin          Allow connection to a HA backup broker.\n' +
-*/
-'\n' +
-'  Options for Listing Exchanges and Queues:\n' +
-'    --ignore-default    Ignore the default exchange in exchange or queue list\n' +
-'\n' +
-'  Options for Adding Exchanges and Queues:\n' +
-'    --alternate-exchange=<aexname>\n' +
-'                        Name of the alternate-exchange for the new queue or\n' +
-'                        exchange. Exchanges route messages to the alternate\n' +
-'                        exchange if they are unable to route them elsewhere.\n' +
-'                        Queues route messages to the alternate exchange if\n' +
-'                        they are rejected by a subscriber or orphaned by queue\n' +
-'                        deletion.\n' +
-'    --durable           The new queue or exchange is durable.\n' +
-'    --replicate=<level>\n' +
-'                        Enable automatic replication in a HA cluster. <level>\n' +
-'                        is \'none\', \'configuration\' or \'all\').\n' +
-'\n' +
-'  Options for Adding Queues:\n' +
-'    --file-count=<n>    Number of files in queue\'s persistence journal\n' +
-'    --file-size=<n>     File size in pages (64KiB/page)\n' +
-'    --max-queue-size=<n>\n' +
-'                        Maximum in-memory queue size as bytes\n' +
-'    --max-queue-count=<n>\n' +
-'                        Maximum in-memory queue size as a number of messages\n' +
-'    --limit-policy=<policy>\n' +
-'                        Action to take when queue limit is reached\n' +
-'    --lvq-key=<key>     Last Value Queue key\n' +
-'    --generate-queue-events=<n>\n' +
-'                        If set to 1, every enqueue will generate an event that\n' +
-'                        can be processed by registered listeners (e.g. for\n' +
-'                        replication). If set to 2, events will be generated\n' +
-'                        for enqueues and dequeues.\n' +
-'    --flow-stop-size=<n>\n' +
-'                        Turn on sender flow control when the number of queued\n' +
-'                        bytes exceeds this value.\n' +
-'    --flow-resume-size=<n>\n' +
-'                        Turn off sender flow control when the number of queued\n' +
-'                        bytes drops below this value.\n' +
-'    --flow-stop-count=<n>\n' +
-'                        Turn on sender flow control when the number of queued\n' +
-'                        messages exceeds this value.\n' +
-'    --flow-resume-count=<n>\n' +
-'                        Turn off sender flow control when the number of queued\n' +
-'                        messages drops below this value.\n' +
-'    --group-header=<header-name>\n' +
-'                        Enable message groups. Specify name of header that\n' +
-'                        holds group identifier.\n' +
-'    --shared-groups     Allow message group consumption across multiple\n' +
-'                        consumers.\n' +
-'    --argument=<NAME=VALUE>\n' +
-'                        Specify a key-value pair to add to queue arguments\n' +
-'    --start-replica=<broker-url>\n' +
-'                        Start replication from the same-named queue at\n' +
-'                        <broker-url>\n' +
-'\n' +
-'  Options for Adding Exchanges:\n' +
-'    --sequence          Exchange will insert a \'qpid.msg_sequence\' field in\n' +
-'                        the message header\n' +
-'    --ive               Exchange will behave as an \'initial-value-exchange\',\n' +
-'                        keeping a reference  to the last message forwarded and\n' +
-'                        enqueuing that message to newly bound queues.\n' +
-'\n' +
-'  Options for Deleting Queues:\n' +
-'    --force             Force delete of queue even if it\'s currently used or\n' +
-'                        it\'s not empty\n' +
-'    --force-if-not-empty\n' +
-'                        Force delete of queue even if it\'s not empty\n' +
-'    --force-if-used     Force delete of queue even if it\'s currently used\n' +
-'\n' +
-'  Options for Declaring Bindings:\n' +
-'    -f <file.xq>, --file=<file.xq>\n' +
-'                        For XML Exchange bindings - specifies the name of a\n' +
-'                        file containing an XQuery.\n' +
-'\n' +
-'  Formatting options for \'list\' action:\n' +
-'    --show-property=<property-name>\n' +
-'                        Specify a property of an object to be included in\n' +
-'                        output\n';
-
-var REPLICATE_LEVELS = {"none" : true, "configuration": true, "all": true};
-var DEFAULT_PROPERTIES = {"exchange": {"name": true, "type": true, "durable": true},
-                             "queue": {"name": true, "durable": true, "autoDelete": true}};
+        this.invokeMethod = function(object, method, arguments) {
+            var correlationID = 'method';
+            message.setAddress(brokerAddress);
+            message.setSubject('broker');
+            message.setReplyTo(replyTo);
+            message.setCorrelationID(correlationID);
+            message.properties = {
+                "routing-key": "broker", // Added for Java Broker
+                "x-amqp-0-10.app-id": "qmf2",
+                "method": "request",
+                "qmf.opcode": "_method_request",
+            };
+            message.body = {
+                "_object_id": object._object_id,
+                "_method_name" : method,
+                "_arguments"   : arguments
+            };
+    
+            correlator.add(correlationID);
+            messenger.put(message);
+        };
 
-var getValue = function(r) {
-    var value = null;
-    if (r.length === 2) {
-        value = r[1];
-        if (!isNaN(value)) {
-            value = parseInt(value);
+        this.addConnection = function(addr, callback) {
+            brokerAddress = addr + '/qmf.default.direct';
+            var replyAddress = addr + '/#';
+    
+            messenger.on('subscription', function(subscription) {
+                var subscriptionAddress = subscription.getAddress();
+                var splitAddress = subscriptionAddress.split('/');
+                replyTo = splitAddress[splitAddress.length - 1];
+                callback();
+            });
+
+            messenger.subscribe(replyAddress);
         }
-    }
-
-    return value;
-};
 
-var config = {
-    _recursive      : false,
-    _host           : 'guest:guest@localhost:5673', // Note 5673 not 5672 as we use WebSocket transport.
-    _connTimeout    : 10,
-    _ignoreDefault  : false,
-    _altern_ex      : null,
-    _durable        : false,
-    _replicate      : null,
-    _if_empty       : true,
-    _if_unused      : true,
-    _fileCount      : null,
-    _fileSize       : null,
-    _maxQueueSize   : null,
-    _maxQueueCount  : null,
-    _limitPolicy    : null,
-    _msgSequence    : false,
-    _lvq_key        : null,
-    _ive            : null,
-    _eventGeneration: null,
-    _file           : null,
-    _flowStopCount  : null,
-    _flowResumeCount: null,
-    _flowStopSize   : null,
-    _flowResumeSize : null,
-    _msgGroupHeader : null,
-    _sharedMsgGroup : false,
-    _extra_arguments: [],
-    _start_replica  : null,
-    _returnCode     : 0,
-    _list_properties: null,
-
-    getOptions: function() {
-        var options = {};
-        for (var a = 0; a < this._extra_arguments.length; a++) {
-            var r = this._extra_arguments[a].split('=');
-            options[r[0]] = getValue(r);
+        this.destroy = function() {
+            messenger.stop(); 
         }
-        return options;
-    }
-};
 
-var FILECOUNT = 'qpid.file_count';
-var FILESIZE  = 'qpid.file_size';
-var MAX_QUEUE_SIZE  = 'qpid.max_size';
-var MAX_QUEUE_COUNT  = 'qpid.max_count';
-var POLICY_TYPE  = 'qpid.policy_type';
-var LVQ_KEY = 'qpid.last_value_queue_key';
-var MSG_SEQUENCE = 'qpid.msg_sequence';
-var IVE = 'qpid.ive';
-var QUEUE_EVENT_GENERATION = 'qpid.queue_event_generation';
-var FLOW_STOP_COUNT   = 'qpid.flow_stop_count';
-var FLOW_RESUME_COUNT = 'qpid.flow_resume_count';
-var FLOW_STOP_SIZE    = 'qpid.flow_stop_size';
-var FLOW_RESUME_SIZE  = 'qpid.flow_resume_size';
-var MSG_GROUP_HDR_KEY = 'qpid.group_header_key';
-var SHARED_MSG_GROUP  = 'qpid.shared_msg_group';
-var REPLICATE = 'qpid.replicate';
-
-/**
- * There are various arguments to declare that have specific program
- * options in this utility. However there is now a generic mechanism for
- * passing arguments as well. The SPECIAL_ARGS list contains the
- * arguments for which there are specific program options defined
- * i.e. the arguments for which there is special processing on add and
- * list
-*/
-var SPECIAL_ARGS={};
-SPECIAL_ARGS[FILECOUNT] = true;
-SPECIAL_ARGS[FILESIZE] = true;
-SPECIAL_ARGS[MAX_QUEUE_SIZE] = true;
-SPECIAL_ARGS[MAX_QUEUE_COUNT] = true;
-SPECIAL_ARGS[POLICY_TYPE] = true;
-SPECIAL_ARGS[LVQ_KEY] = true;
-SPECIAL_ARGS[MSG_SEQUENCE] = true;
-SPECIAL_ARGS[IVE] = true;
-SPECIAL_ARGS[QUEUE_EVENT_GENERATION] = true;
-SPECIAL_ARGS[FLOW_STOP_COUNT] = true;
-SPECIAL_ARGS[FLOW_RESUME_COUNT] = true;
-SPECIAL_ARGS[FLOW_STOP_SIZE] = true;
-SPECIAL_ARGS[FLOW_RESUME_SIZE] = true;
-SPECIAL_ARGS[MSG_GROUP_HDR_KEY] = true;
-SPECIAL_ARGS[SHARED_MSG_GROUP] = true;
-SPECIAL_ARGS[REPLICATE] = true;
+        this.request = function() {return correlator.request();}
 
-var oid = function(id) {
-    return id._agent_epoch + ':' + id._object_name
-};
+        messenger.on('error', function(error) {console.log(error);});
+        messenger.on('work', pumpData);
+        messenger.setOutgoingWindow(1024);
+        messenger.recv(); // Receive as many messages as messenger can buffer.
+        messenger.start();
+    }; // End of qmf.Console
 
-var filterMatch = function(name, filter) {
-    if (filter === '') {
-        return true;
-    }
-    if (name.indexOf(filter) === -1) {
-        return false;
-    }
-    return true;
-};
+/************************* qpid-config business logic ************************/
 
-var idMap = function(list) {
-    var map = {};
-    for (var i = 0; i < list.length; i++) {
-        var item = list[i];
-        map[oid(item._object_id)] = item;
-    }
-    return map;
-};
+    var brokerAgent = new qmf.Console();
+
+    var _usage =
+    'Usage:  qpid-config [OPTIONS]\n' +
+    '        qpid-config [OPTIONS] exchanges [filter-string]\n' +
+    '        qpid-config [OPTIONS] queues    [filter-string]\n' +
+    '        qpid-config [OPTIONS] add exchange <type> <name> [AddExchangeOptions]\n' +
+    '        qpid-config [OPTIONS] del exchange <name>\n' +
+    '        qpid-config [OPTIONS] add queue <name> [AddQueueOptions]\n' +
+    '        qpid-config [OPTIONS] del queue <name> [DelQueueOptions]\n' +
+    '        qpid-config [OPTIONS] bind   <exchange-name> <queue-name> [binding-key]\n' +
+    '                  <for type xml>     [-f -|filename]\n' +
+    '                  <for type header>  [all|any] k1=v1 [, k2=v2...]\n' +
+    '        qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]\n' +
+    '        qpid-config [OPTIONS] reload-acl\n' +
+    '        qpid-config [OPTIONS] add <type> <name> [--argument <property-name>=<property-value>]\n' +
+    '        qpid-config [OPTIONS] del <type> <name>\n' +
+    '        qpid-config [OPTIONS] list <type> [--show-property <property-name>]\n';
+
+    var usage = function() {
+        console.log(_usage);
+        process.exit(-1);
+    };
 
-var renderObject = function(obj, list) {
-    if (!obj) {
-        return '';
-    }
-    var string = '';
-    var addComma = false;
-    for (var prop in obj) {
-        if (addComma) {
-            string += ', ';
-        }
-        if (obj.hasOwnProperty(prop)) {
-            if (list) {
-                if (SPECIAL_ARGS[prop]) continue;
-                string += " --argument " + prop + "=" + obj[prop];
-            } else {    
-                string += "'" + prop + "'" + ": '" + obj[prop] + "'";
-                addComma = true;
+    var _description =
+    'Examples:\n' +
+    '\n' +
+    '$ qpid-config add queue q\n' +
+    '$ qpid-config add exchange direct d -a localhost:5672\n' +
+    '$ qpid-config exchanges -b 10.1.1.7:10000\n' +
+    '$ qpid-config queues -b guest/guest@broker-host:10000\n' +
+    '\n' +
+    'Add Exchange <type> values:\n' +
+    '\n' +
+    '    direct     Direct exchange for point-to-point communication\n' +
+    '    fanout     Fanout exchange for broadcast communication\n' +
+    '    topic      Topic exchange that routes messages using binding keys with wildcards\n' +
+    '    headers    Headers exchange that matches header fields against the binding keys\n' +
+    '    xml        XML Exchange - allows content filtering using an XQuery\n' +
+    '\n' +
+    '\n' +
+    'Queue Limit Actions:\n' +
+    '\n' +
+    '    none (default) - Use broker\'s default policy\n' +
+    '    reject         - Reject enqueued messages\n' +
+    '    ring           - Replace oldest unacquired message with new\n' +
+    '\n' +
+    'Replication levels:\n' +
+    '\n' +
+    '    none           - no replication\n' +
+    '    configuration  - replicate queue and exchange existence and bindings, but not messages.\n' +
+    '    all            - replicate configuration and messages\n';
+    
+    var _options =
+    'Options:\n' +
+    '  -h, --help            show this help message and exit\n' +
+    '\n' +
+    '  General Options:\n' +
+    '    -t <secs>, --timeout=<secs>\n' +
+    '                        Maximum time to wait for broker connection (in\n' +
+    '                        seconds)\n' +
+    '    -r, --recursive     Show bindings in queue or exchange list\n' +
+    '    -b <address>, --broker=<address>\n' +
+    '                        Address of qpidd broker with syntax:\n' +
+    '                        [username/password@] hostname | ip-address [:<port>]\n' +
+    '    -a <address>, --broker-addr=<address>\n' +
+    /* TODO Connection options
+    '    --sasl-mechanism=<mech>\n' +
+    '                        SASL mechanism for authentication (e.g. EXTERNAL,\n' +
+    '                        ANONYMOUS, PLAIN, CRAM-MD5, DIGEST-MD5, GSSAPI). SASL\n' +
+    '                        automatically picks the most secure available\n' +
+    '                        mechanism - use this option to override.\n' +
+    '    --ssl-certificate=<cert>\n' +
+    '                        Client SSL certificate (PEM Format)\n' +
+    '    --ssl-key=<key>     Client SSL private key (PEM Format)\n' +
+    '    --ha-admin          Allow connection to a HA backup broker.\n' +
+    */
+    '\n' +
+    '  Options for Listing Exchanges and Queues:\n' +
+    '    --ignore-default    Ignore the default exchange in exchange or queue list\n' +
+    '\n' +
+    '  Options for Adding Exchanges and Queues:\n' +
+    '    --alternate-exchange=<aexname>\n' +
+    '                        Name of the alternate-exchange for the new queue or\n' +
+    '                        exchange. Exchanges route messages to the alternate\n' +
+    '                        exchange if they are unable to route them elsewhere.\n' +
+    '                        Queues route messages to the alternate exchange if\n' +
+    '                        they are rejected by a subscriber or orphaned by queue\n' +
+    '                        deletion.\n' +
+    '    --durable           The new queue or exchange is durable.\n' +
+    '    --replicate=<level>\n' +
+    '                        Enable automatic replication in a HA cluster. <level>\n' +
+    '                        is \'none\', \'configuration\' or \'all\').\n' +
+    '\n' +
+    '  Options for Adding Queues:\n' +
+    '    --file-count=<n>    Number of files in queue\'s persistence journal\n' +
+    '    --file-size=<n>     File size in pages (64KiB/page)\n' +
+    '    --max-queue-size=<n>\n' +
+    '                        Maximum in-memory queue size as bytes\n' +
+    '    --max-queue-count=<n>\n' +
+    '                        Maximum in-memory queue size as a number of messages\n' +
+    '    --limit-policy=<policy>\n' +
+    '                        Action to take when queue limit is reached\n' +
+    '    --lvq-key=<key>     Last Value Queue key\n' +
+    '    --generate-queue-events=<n>\n' +
+    '                        If set to 1, every enqueue will generate an event that\n' +
+    '                        can be processed by registered listeners (e.g. for\n' +
+    '                        replication). If set to 2, events will be generated\n' +
+    '                        for enqueues and dequeues.\n' +
+    '    --flow-stop-size=<n>\n' +
+    '                        Turn on sender flow control when the number of queued\n' +
+    '                        bytes exceeds this value.\n' +
+    '    --flow-resume-size=<n>\n' +
+    '                        Turn off sender flow control when the number of queued\n' +
+    '                        bytes drops below this value.\n' +
+    '    --flow-stop-count=<n>\n' +
+    '                        Turn on sender flow control when the number of queued\n' +
+    '                        messages exceeds this value.\n' +
+    '    --flow-resume-count=<n>\n' +
+    '                        Turn off sender flow control when the number of queued\n' +
+    '                        messages drops below this value.\n' +
+    '    --group-header=<header-name>\n' +
+    '                        Enable message groups. Specify name of header that\n' +
+    '                        holds group identifier.\n' +
+    '    --shared-groups     Allow message group consumption across multiple\n' +
+    '                        consumers.\n' +
+    '    --argument=<NAME=VALUE>\n' +
+    '                        Specify a key-value pair to add to queue arguments\n' +
+    '    --start-replica=<broker-url>\n' +
+    '                        Start replication from the same-named queue at\n' +
+    '                        <broker-url>\n' +
+    '\n' +
+    '  Options for Adding Exchanges:\n' +
+    '    --sequence          Exchange will insert a \'qpid.msg_sequence\' field in\n' +
+    '                        the message header\n' +
+    '    --ive               Exchange will behave as an \'initial-value-exchange\',\n' +
+    '                        keeping a reference  to the last message forwarded and\n' +
+    '                        enqueuing that message to newly bound queues.\n' +
+    '\n' +
+    '  Options for Deleting Queues:\n' +
+    '    --force             Force delete of queue even if it\'s currently used or\n' +
+    '                        it\'s not empty\n' +
+    '    --force-if-not-empty\n' +
+    '                        Force delete of queue even if it\'s not empty\n' +
+    '    --force-if-used     Force delete of queue even if it\'s currently used\n' +
+    '\n' +
+    '  Options for Declaring Bindings:\n' +
+    '    -f <file.xq>, --file=<file.xq>\n' +
+    '                        For XML Exchange bindings - specifies the name of a\n' +
+    '                        file containing an XQuery.\n' +
+    '\n' +
+    '  Formatting options for \'list\' action:\n' +
+    '    --show-property=<property-name>\n' +
+    '                        Specify a property of an object to be included in\n' +
+    '                        output\n';
+    
+    var REPLICATE_LEVELS = {"none" : true, "configuration": true, "all": true};
+    var DEFAULT_PROPERTIES = {"exchange": {"name": true, "type": true, "durable": true},
+                                 "queue": {"name": true, "durable": true, "autoDelete": true}};
+    
+    var getValue = function(r) {
+        var value = null;
+        if (r.length === 2) {
+            value = r[1];
+            if (!isNaN(value)) {
+                value = parseInt(value);
             }
         }
-    }
-
-    if (addComma) {
-        return '{' + string + '}';
-    } else {
-        if (list) {
-            return string;
-        } else {
-            return '';
-        }
-    }
-};
-
-/**
- * The following methods illustrate the QMF2 class query mechanism which returns
- * the list of QMF Objects for the specified class that are currently present
- * on the Broker. The Schema <qpid>/cpp/src/qpid/broker/management-schema.xml
- * describes the properties and statistics of each Management Object.
- * <p>
- * One slightly subtle part of QMF is that certain Objects are associated via
- * references, for example Binding contains queueRef and exchangeRef, which lets
- * Objects link to each other using their _object_id property.
- * <p>
- * The implementation of these methods attempts to follow the same general flow
- * as the equivalent method in the "canonical" python based qpid-config version
- * but has the added complication that JavaScript is entirely asynchronous.
- * The approach that has been taken is to use the correlator object that lets a
- * callback function be registered via the "then" method and actually calls the
- * callback when all of the requests specified in the request method have
- * returned their results (which get passed as the callback parameter).
- */
-
-var overview = function() {
-    brokerAgent.request(
-        // Send the QMF query requests for the specified classes.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
-        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
-    ).then(function(objects) {
-        var exchanges = objects.exchange;
-        var queues = objects.queue;
-        console.log("Total Exchanges: " + exchanges.length);
-        var etype = {};
-        for (var i = 0; i < exchanges.length; i++) {
-            var exchange = exchanges[i]._values;
-            if (!etype[exchange.type]) {
-                etype[exchange.type] = 1;
-            } else {
-                etype[exchange.type]++;
+    
+        return value;
+    };
+    
+    var config = {
+        _recursive      : false,
+        _host           : 'guest:guest@localhost:5673', // Note 5673 not 5672 as we use WebSocket transport.
+        _connTimeout    : 10,
+        _ignoreDefault  : false,
+        _altern_ex      : null,
+        _durable        : false,
+        _replicate      : null,
+        _if_empty       : true,
+        _if_unused      : true,
+        _fileCount      : null,
+        _fileSize       : null,
+        _maxQueueSize   : null,
+        _maxQueueCount  : null,
+        _limitPolicy    : null,
+        _msgSequence    : false,
+        _lvq_key        : null,
+        _ive            : null,
+        _eventGeneration: null,
+        _file           : null,
+        _flowStopCount  : null,
+        _flowResumeCount: null,
+        _flowStopSize   : null,
+        _flowResumeSize : null,
+        _msgGroupHeader : null,
+        _sharedMsgGroup : false,
+        _extra_arguments: [],
+        _start_replica  : null,
+        _returnCode     : 0,
+        _list_properties: null,
+    
+        getOptions: function() {
+            var options = {};
+            for (var a = 0; a < this._extra_arguments.length; a++) {
+                var r = this._extra_arguments[a].split('=');
+                options[r[0]] = getValue(r);
             }
+            return options;
         }
-        for (var typ in etype) {
-            var pad = Array(16 - typ.length).join(' ');
-            console.log(pad + typ + ": " + etype[typ]);
+    };
+    
+    var FILECOUNT = 'qpid.file_count';
+    var FILESIZE  = 'qpid.file_size';
+    var MAX_QUEUE_SIZE  = 'qpid.max_size';
+    var MAX_QUEUE_COUNT  = 'qpid.max_count';
+    var POLICY_TYPE  = 'qpid.policy_type';
+    var LVQ_KEY = 'qpid.last_value_queue_key';
+    var MSG_SEQUENCE = 'qpid.msg_sequence';
+    var IVE = 'qpid.ive';
+    var QUEUE_EVENT_GENERATION = 'qpid.queue_event_generation';
+    var FLOW_STOP_COUNT   = 'qpid.flow_stop_count';
+    var FLOW_RESUME_COUNT = 'qpid.flow_resume_count';
+    var FLOW_STOP_SIZE    = 'qpid.flow_stop_size';
+    var FLOW_RESUME_SIZE  = 'qpid.flow_resume_size';
+    var MSG_GROUP_HDR_KEY = 'qpid.group_header_key';
+    var SHARED_MSG_GROUP  = 'qpid.shared_msg_group';
+    var REPLICATE = 'qpid.replicate';
+    
+    /**
+     * There are various arguments to declare that have specific program
+     * options in this utility. However there is now a generic mechanism for
+     * passing arguments as well. The SPECIAL_ARGS list contains the
+     * arguments for which there are specific program options defined
+     * i.e. the arguments for which there is special processing on add and
+     * list
+    */
+    var SPECIAL_ARGS={};
+    SPECIAL_ARGS[FILECOUNT] = true;
+    SPECIAL_ARGS[FILESIZE] = true;
+    SPECIAL_ARGS[MAX_QUEUE_SIZE] = true;
+    SPECIAL_ARGS[MAX_QUEUE_COUNT] = true;
+    SPECIAL_ARGS[POLICY_TYPE] = true;
+    SPECIAL_ARGS[LVQ_KEY] = true;
+    SPECIAL_ARGS[MSG_SEQUENCE] = true;
+    SPECIAL_ARGS[IVE] = true;
+    SPECIAL_ARGS[QUEUE_EVENT_GENERATION] = true;
+    SPECIAL_ARGS[FLOW_STOP_COUNT] = true;
+    SPECIAL_ARGS[FLOW_RESUME_COUNT] = true;
+    SPECIAL_ARGS[FLOW_STOP_SIZE] = true;
+    SPECIAL_ARGS[FLOW_RESUME_SIZE] = true;
+    SPECIAL_ARGS[MSG_GROUP_HDR_KEY] = true;
+    SPECIAL_ARGS[SHARED_MSG_GROUP] = true;
+    SPECIAL_ARGS[REPLICATE] = true;
+    
+    // Returns a String representation of an ObjectID.
+    var oid = function(id) {
+        return id._agent_epoch + ':' + id._object_name
+    };
+    
+    // Check if the supplied name contains the supplied filter String.
+    var filterMatch = function(name, filter) {
+        if (filter === '') {
+            return true;
         }
-
-        console.log("\n   Total Queues: " + queues.length);
-        var durable = 0;
-        for (var i = 0; i < queues.length; i++) {
-            var queue = queues[i]._values;
-            if (queue.durable) {
-                durable++;
-            }
+        if (name.indexOf(filter) === -1) {
+            return false;
         }
-        console.log("        durable: " + durable);
-        console.log("    non-durable: " + (queues.length - durable));
-        brokerAgent.destroy();
-    });
-};
-
-var exchangeList = function(filter) {
-    brokerAgent.request(
-        // Send the QMF query requests for the specified classes.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
-    ).then(function(objects) {
-        var exchanges = objects.exchange;
-        var exMap = idMap(exchanges);
-        var caption1 = "Type      ";
-        var caption2 = "Exchange Name";
-        var maxNameLen = caption2.length;
-        var found = false;
-        for (var i = 0; i < exchanges.length; i++) {
-            var exchange = exchanges[i]._values;
-            if (filterMatch(exchange.name, filter)) {
-                if (exchange.name.length > maxNameLen) {
-                    maxNameLen = exchange.name.length;
-                }
-                found = true;
-            }
+        return true;
+    };
+    
+    // Take the supplied List of QMF2 Objects and return a Map keyed by ObjectID.
+    var idMap = function(list) {
+        var map = {};
+        for (var i = 0; i < list.length; i++) {
+            var item = list[i];
+            map[oid(item._object_id)] = item;
         }
-        if (!found) {
-            config._returnCode = 1;
-            return;
+        return map;
+    };
+    
+    // Pretty-print the supplied Object.
+    var renderObject = function(obj, list) {
+        if (!obj) {
+            return '';
         }
-
-        var pad = Array(maxNameLen + 1 - caption2.length).join(' ');
-        console.log(caption1 + caption2 + pad + "  Attributes");
-        console.log(Array(maxNameLen + caption1.length + 13).join('='));
-
-        for (var i = 0; i < exchanges.length; i++) {
-            var exchange = exchanges[i]._values;
-            if (config._ignoreDefault && !exchange.name) continue;
-            if (filterMatch(exchange.name, filter)) {
-                var pad1 = Array(11 - exchange.type.length).join(' ');
-                var pad2 = Array(maxNameLen + 2 - exchange.name.length).join(' ');
-                var string = exchange.type + pad1 + exchange.name + pad2;
-                var args = exchange.arguments ? exchange.arguments : {};
-                if (exchange.durable) {
-                    string += ' --durable';
-                }
-                if (args[REPLICATE]) {
-                    string += ' --replicate=' + args[REPLICATE];
-                }
-                if (args[MSG_SEQUENCE]) {
-                    string += ' --sequence';
-                }
-                if (args[IVE]) {
-                    string += ' --ive';
-                }
-                if (exchange.altExchange) {
-                    string += ' --alternate-exchange=' + exMap[oid(exchange.altExchange)]._values.name;
+        var string = '';
+        var addComma = false;
+        for (var prop in obj) {
+            if (addComma) {
+                string += ', ';
+            }
+            if (obj.hasOwnProperty(prop)) {
+                if (list) {
+                    if (SPECIAL_ARGS[prop]) continue;
+                    string += " --argument " + prop + "=" + obj[prop];
+                } else {    
+                    string += "'" + prop + "'" + ": '" + obj[prop] + "'";
+                    addComma = true;
                 }
-                console.log(string);
             }
         }
-        brokerAgent.destroy();
-    });
-};
-
-var exchangeListRecurse = function(filter) {
-    brokerAgent.request(
-        // Send the QMF query requests for the specified classes.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
-        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'),
-        brokerAgent.getObjects('org.apache.qpid.broker', 'binding')
-    ).then(function(objects) {
-        var exchanges = objects.exchange;
-        var bindings = objects.binding;
-        var queues = idMap(objects.queue);
-
-        for (var i = 0; i < exchanges.length; i++) {
-            var exchange = exchanges[i];
-            var exchangeId = oid(exchange._object_id);
-            exchange = exchange._values;
-
-            if (config._ignoreDefault && !exchange.name) continue;
-            if (filterMatch(exchange.name, filter)) {
-                console.log("Exchange '" + exchange.name + "' (" + exchange.type + ")");
-                for (var j = 0; j < bindings.length; j++) {
-                    var bind = bindings[j]._values;
-                    var exchangeRef = oid(bind.exchangeRef);
-
-                    if (exchangeRef === exchangeId) {
-                        var queue = queues[oid(bind.queueRef)];
-                        var queueName = queue ? queue._values.name : "<unknown>";
-                        console.log("    bind [" + bind.bindingKey + "] => " + queueName + 
-                                    " " + renderObject(bind.arguments));
-                    }   
-                }
+    
+        if (addComma) {
+            return '{' + string + '}';
+        } else {
+            if (list) {
+                return string;
+            } else {
+                return '';
             }
         }
-        brokerAgent.destroy();
-    });
-};
-
-var queueList = function(filter) {
-    brokerAgent.request(
-        // Send the QMF query requests for the specified classes.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
-        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
-    ).then(function(objects) {
-        var queues = objects.queue;
-        var exMap = idMap(objects.exchange);
-        var caption = "Queue Name";
-        var maxNameLen = caption.length;
-        var found = false;
-        for (var i = 0; i < queues.length; i++) {
-            var queue = queues[i]._values;
-            if (filterMatch(queue.name, filter)) {
-                if (queue.name.length > maxNameLen) {
-                    maxNameLen = queue.name.length;
+    };
+    
+    /**
+     * The following methods illustrate the QMF2 class query mechanism which returns
+     * the list of QMF Objects for the specified class that are currently present
+     * on the Broker. The Schema <qpid>/cpp/src/qpid/broker/management-schema.xml
+     * describes the properties and statistics of each Management Object.
+     * <p>
+     * One slightly subtle part of QMF is that certain Objects are associated via
+     * references, for example Binding contains queueRef and exchangeRef, which lets
+     * Objects link to each other using their _object_id property.
+     * <p>
+     * The implementation of these methods attempts to follow the same general flow
+     * as the equivalent method in the "canonical" python based qpid-config version
+     * but has the added complication that JavaScript is entirely asynchronous.
+     * The approach that has been taken is to use the correlator object that lets a
+     * callback function be registered via the "then" method and actually calls the
+     * callback when all of the requests specified in the request method have
+     * returned their results (which get passed as the callback parameter).
+     */
+    
+    var overview = function() {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
+        ).then(function(objects) {
+            var exchanges = objects.exchange;
+            var queues = objects.queue;
+            console.log("Total Exchanges: " + exchanges.length);
+            var etype = {};
+            for (var i = 0; i < exchanges.length; i++) {
+                var exchange = exchanges[i]._values;
+                if (!etype[exchange.type]) {
+                    etype[exchange.type] = 1;
+                } else {
+                    etype[exchange.type]++;
                 }
-                found = true;
             }
-        }
-        if (!found) {
-            config._returnCode = 1;
-            return;
-        }
-
-        var pad = Array(maxNameLen + 1 - caption.length).join(' ');
-        console.log(caption + pad + "  Attributes");
-        console.log(Array(maxNameLen + caption.length + 3).join('='));
-
-        for (var i = 0; i < queues.length; i++) {
-            var queue = queues[i]._values;
-            if (filterMatch(queue.name, filter)) {
-                var pad2 = Array(maxNameLen + 2 - queue.name.length).join(' ');
-                var string = queue.name + pad2;
-                var args = queue.arguments ? queue.arguments : {};
+            for (var typ in etype) {
+                var pad = Array(16 - typ.length).join(' ');
+                console.log(pad + typ + ": " + etype[typ]);
+            }
+    
+            console.log("\n   Total Queues: " + queues.length);
+            var durable = 0;
+            for (var i = 0; i < queues.length; i++) {
+                var queue = queues[i]._values;
                 if (queue.durable) {
-                    string += ' --durable';
-                }
-                if (args[REPLICATE]) {
-                    string += ' --replicate=' + args[REPLICATE];
-                }
-                if (queue.autoDelete) {
-                    string += ' auto-del';
-                }
-                if (queue.exclusive) {
-                    string += ' excl';
-                }
-                if (args[FILESIZE]) {
-                    string += ' --file-size=' + args[FILESIZE];
-                }
-                if (args[FILECOUNT]) {
-                    string += ' --file-count=' + args[FILECOUNT];
+                    durable++;
                 }
-                if (args[MAX_QUEUE_SIZE]) {
-                    string += ' --max-queue-size=' + args[MAX_QUEUE_SIZE];
-                }
-                if (args[MAX_QUEUE_COUNT]) {
-                    string += ' --max-queue-count=' + args[MAX_QUEUE_COUNT];
-                }
-                if (args[POLICY_TYPE]) {
-                    string += ' --limit-policy=' + args[POLICY_TYPE].replace("_", "-");
-                }
-                if (args[LVQ_KEY]) {
-                    string += ' --lvq-key=' + args[LVQ_KEY];
-                }
-                if (args[QUEUE_EVENT_GENERATION]) {
-                    string += ' --generate-queue-events=' + args[QUEUE_EVENT_GENERATION];
-                }
-                if (queue.altExchange) {
-                    string += ' --alternate-exchange=' + exMap[oid(queue.altExchange)]._values.name;
-                }
-                if (args[FLOW_STOP_SIZE]) {
-                    string += ' --flow-stop-size=' + args[FLOW_STOP_SIZE];
-                }
-                if (args[FLOW_RESUME_SIZE]) {
-                    string += ' --flow-resume-size=' + args[FLOW_RESUME_SIZE];
+            }
+            console.log("        durable: " + durable);
+            console.log("    non-durable: " + (queues.length - durable));
+            brokerAgent.destroy();
+        });
+    };
+    
+    var exchangeList = function(filter) {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
+        ).then(function(objects) {
+            var exchanges = objects.exchange;
+            var exMap = idMap(exchanges);
+            var caption1 = "Type      ";
+            var caption2 = "Exchange Name";
+            var maxNameLen = caption2.length;
+            var found = false;
+            for (var i = 0; i < exchanges.length; i++) {
+                var exchange = exchanges[i]._values;
+                if (filterMatch(exchange.name, filter)) {
+                    if (exchange.name.length > maxNameLen) {
+                        maxNameLen = exchange.name.length;
+                    }
+                    found = true;
                 }
-                if (args[FLOW_STOP_COUNT]) {
-                    string += ' --flow-stop-count=' + args[FLOW_STOP_COUNT];
+            }
+            if (!found) {
+                config._returnCode = 1;
+                return;
+            }
+    
+            var pad = Array(maxNameLen + 1 - caption2.length).join(' ');
+            console.log(caption1 + caption2 + pad + "  Attributes");
+            console.log(Array(maxNameLen + caption1.length + 13).join('='));
+    
+            for (var i = 0; i < exchanges.length; i++) {
+                var exchange = exchanges[i]._values;
+                if (config._ignoreDefault && !exchange.name) continue;
+                if (filterMatch(exchange.name, filter)) {
+                    var pad1 = Array(11 - exchange.type.length).join(' ');
+                    var pad2 = Array(maxNameLen + 2 - exchange.name.length).join(' ');
+                    var string = exchange.type + pad1 + exchange.name + pad2;
+                    var args = exchange.arguments ? exchange.arguments : {};
+                    if (exchange.durable) {
+                        string += ' --durable';
+                    }
+                    if (args[REPLICATE]) {
+                        string += ' --replicate=' + args[REPLICATE];
+                    }
+                    if (args[MSG_SEQUENCE]) {
+                        string += ' --sequence';
+                    }
+                    if (args[IVE]) {
+                        string += ' --ive';
+                    }
+                    if (exchange.altExchange) {
+                        string += ' --alternate-exchange=' + exMap[oid(exchange.altExchange)]._values.name;
+                    }
+                    console.log(string);
                 }
-                if (args[FLOW_RESUME_COUNT]) {
-                    string += ' --flow-resume-count=' + args[FLOW_RESUME_COUNT];
+            }
+            brokerAgent.destroy();
+        });
+    };
+    
+    var exchangeListRecurse = function(filter) {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'binding')
+        ).then(function(objects) {
+            var exchanges = objects.exchange;
+            var bindings = objects.binding;
+            var queues = idMap(objects.queue);
+    
+            for (var i = 0; i < exchanges.length; i++) {
+                var exchange = exchanges[i];
+                var exchangeId = oid(exchange._object_id);
+                exchange = exchange._values;
+    
+                if (config._ignoreDefault && !exchange.name) continue;
+                if (filterMatch(exchange.name, filter)) {
+                    console.log("Exchange '" + exchange.name + "' (" + exchange.type + ")");
+                    for (var j = 0; j < bindings.length; j++) {
+                        var bind = bindings[j]._values;
+                        var exchangeRef = oid(bind.exchangeRef);
+    
+                        if (exchangeRef === exchangeId) {
+                            var queue = queues[oid(bind.queueRef)];
+                            var queueName = queue ? queue._values.name : "<unknown>";
+                            console.log("    bind [" + bind.bindingKey + "] => " + queueName + 
+                                        " " + renderObject(bind.arguments));
+                        }   
+                    }
                 }
-                if (args[MSG_GROUP_HDR_KEY]) {
-                    string += ' --group-header=' + args[MSG_GROUP_HDR_KEY];
+            }
+            brokerAgent.destroy();
+        });
+    };
+    
+    var queueList = function(filter) {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
+        ).then(function(objects) {
+            var queues = objects.queue;
+            var exMap = idMap(objects.exchange);
+            var caption = "Queue Name";
+            var maxNameLen = caption.length;
+            var found = false;
+            for (var i = 0; i < queues.length; i++) {
+                var queue = queues[i]._values;
+                if (filterMatch(queue.name, filter)) {
+                    if (queue.name.length > maxNameLen) {
+                        maxNameLen = queue.name.length;
+                    }
+                    found = true;
                 }
-                if (args[SHARED_MSG_GROUP] === 1) {
-                    string += ' --shared-groups';
+            }
+            if (!found) {
+                config._returnCode = 1;
+                return;
+            }
+    
+            var pad = Array(maxNameLen + 1 - caption.length).join(' ');
+            console.log(caption + pad + "  Attributes");
+            console.log(Array(maxNameLen + caption.length + 3).join('='));
+    
+            for (var i = 0; i < queues.length; i++) {
+                var queue = queues[i]._values;
+                if (filterMatch(queue.name, filter)) {
+                    var pad2 = Array(maxNameLen + 2 - queue.name.length).join(' ');
+                    var string = queue.name + pad2;
+                    var args = queue.arguments ? queue.arguments : {};
+                    if (queue.durable) {
+                        string += ' --durable';
+                    }
+                    if (args[REPLICATE]) {
+                        string += ' --replicate=' + args[REPLICATE];
+                    }
+                    if (queue.autoDelete) {
+                        string += ' auto-del';
+                    }
+                    if (queue.exclusive) {
+                        string += ' excl';
+                    }
+                    if (args[FILESIZE]) {
+                        string += ' --file-size=' + args[FILESIZE];
+                    }
+                    if (args[FILECOUNT]) {
+                        string += ' --file-count=' + args[FILECOUNT];
+                    }
+                    if (args[MAX_QUEUE_SIZE]) {
+                        string += ' --max-queue-size=' + args[MAX_QUEUE_SIZE];
+                    }
+                    if (args[MAX_QUEUE_COUNT]) {
+                        string += ' --max-queue-count=' + args[MAX_QUEUE_COUNT];
+                    }
+                    if (args[POLICY_TYPE]) {
+                        string += ' --limit-policy=' + args[POLICY_TYPE].replace("_", "-");
+                    }
+                    if (args[LVQ_KEY]) {
+                        string += ' --lvq-key=' + args[LVQ_KEY];
+                    }
+                    if (args[QUEUE_EVENT_GENERATION]) {
+                        string += ' --generate-queue-events=' + args[QUEUE_EVENT_GENERATION];
+                    }
+                    if (queue.altExchange) {
+                        string += ' --alternate-exchange=' + exMap[oid(queue.altExchange)]._values.name;
+                    }
+                    if (args[FLOW_STOP_SIZE]) {
+                        string += ' --flow-stop-size=' + args[FLOW_STOP_SIZE];
+                    }
+                    if (args[FLOW_RESUME_SIZE]) {
+                        string += ' --flow-resume-size=' + args[FLOW_RESUME_SIZE];
+                    }
+                    if (args[FLOW_STOP_COUNT]) {
+                        string += ' --flow-stop-count=' + args[FLOW_STOP_COUNT];
+                    }
+                    if (args[FLOW_RESUME_COUNT]) {
+                        string += ' --flow-resume-count=' + args[FLOW_RESUME_COUNT];
+                    }
+                    if (args[MSG_GROUP_HDR_KEY]) {
+                        string += ' --group-header=' + args[MSG_GROUP_HDR_KEY];
+                    }
+                    if (args[SHARED_MSG_GROUP] === 1) {
+                        string += ' --shared-groups';
+                    }
+                    string += ' ' + renderObject(args, true);
+                    console.log(string);
                 }
-                string += ' ' + renderObject(args, true);
-                console.log(string);
             }
-        }
-        brokerAgent.destroy();
-    });
-};
-
-var queueListRecurse = function(filter) {
-    brokerAgent.request(
-        // Send the QMF query requests for the specified classes.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
-        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'),
-        brokerAgent.getObjects('org.apache.qpid.broker', 'binding')
-    ).then(function(objects) {
-        var queues = objects.queue;
-        var bindings = objects.binding;
-        var exchanges = idMap(objects.exchange);
-
-        for (var i = 0; i < queues.length; i++) {
-            var queue = queues[i];
-            var queueId = oid(queue._object_id);
-            queue = queue._values;
-
-            if (filterMatch(queue.name, filter)) {
-                console.log("Queue '" + queue.name + "'");
-                for (var j = 0; j < bindings.length; j++) {
-                    var bind = bindings[j]._values;
-                    var queueRef = oid(bind.queueRef);
-
-                    if (queueRef === queueId) {
-                        var exchange = exchanges[oid(bind.exchangeRef)];
-                        var exchangeName = "<unknown>";
-                        if (exchange) {
-                            exchangeName = exchange._values.name;
-                            if (exchangeName === '') {
-                                if (config._ignoreDefault) continue;
-                                exchangeName = "''";
+            brokerAgent.destroy();
+        });
+    };
+    
+    var queueListRecurse = function(filter) {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'binding')
+        ).then(function(objects) {
+            var queues = objects.queue;
+            var bindings = objects.binding;
+            var exchanges = idMap(objects.exchange);
+    
+            for (var i = 0; i < queues.length; i++) {
+                var queue = queues[i];
+                var queueId = oid(queue._object_id);
+                queue = queue._values;
+    
+                if (filterMatch(queue.name, filter)) {
+                    console.log("Queue '" + queue.name + "'");
+                    for (var j = 0; j < bindings.length; j++) {
+                        var bind = bindings[j]._values;
+                        var queueRef = oid(bind.queueRef);
+    
+                        if (queueRef === queueId) {
+                            var exchange = exchanges[oid(bind.exchangeRef)];
+                            var exchangeName = "<unknown>";
+                            if (exchange) {
+                                exchangeName = exchange._values.name;
+                                if (exchangeName === '') {
+                                    if (config._ignoreDefault) continue;
+                                    exchangeName = "''";
+                                }
                             }
-                        }
-
-                        console.log("    bind [" + bind.bindingKey + "] => " + exchangeName + 
-                                    " " + renderObject(bind.arguments));
-                    }   
+    
+                            console.log("    bind [" + bind.bindingKey + "] => " + exchangeName + 
+                                        " " + renderObject(bind.arguments));
+                        }   
+                    }
                 }
             }
+            brokerAgent.destroy();
+        });
+    };
+    
+    /**
+     * The following methods implement adding and deleting various Broker Management
+     * Objects via QMF. Although <qpid>/cpp/src/qpid/broker/management-schema.xml
+     * describes the basic method schema, for example:
+     *   <method name="create" desc="Create an object of the specified type">
+     *     <arg name="type" dir="I" type="sstr" desc="The type of object to create"/>
+     *     <arg name="name" dir="I" type="sstr" desc="The name of the object to create"/>
+     *     <arg name="properties" dir="I" type="map" desc="Type specific object properties"/>
+     *     <arg name="strict" dir="I" type="bool" desc="If specified, treat unrecognised object properties as an error"/    >
+     *   </method>
+     *
+     *   <method name="delete" desc="Delete an object of the specified type">
+     *     <arg name="type" dir="I" type="sstr" desc="The type of object to delete"/>
+     *     <arg name="name" dir="I" type="sstr" desc="The name of the object to delete"/>
+     *     <arg name="options" dir="I" type="map" desc="Type specific object options for deletion"/>
+     *   </method>
+     *
+     * What the schema doesn't do however is to explain what the properties/options
+     * Map values actually mean, unfortunately these aren't documented anywhere so
+     * the only option is to look in the code, the best place to look is in:
+     * <qpid>/cpp/src/qpid/broker/Broker.cpp, the method Broker::ManagementMethod is
+     * the best place to start, then Broker::createObject and Broker::deleteObject
+     * even then it's pretty hard to figure out all that is possible.
+     */
+    
+    var handleMethodResponse = function(response, dontStop) {
+        if (response._arguments) {
+            //console.log(response._arguments);
+        } if (response._values) {
+            console.error("Exception from Agent: " + renderObject(response._values));
+        }
+        // Mostly we want to stop the Messenger Event loop and exit when a QMF method
+        // returns, but sometimes we don't, the dontStop flag prevents this behaviour.
+        if (!dontStop) {
+            brokerAgent.destroy();
         }
-        brokerAgent.destroy();
-    });
-};
-
-/**
- * The following methods implement adding and deleting various Broker Management
- * Objects via QMF. Although <qpid>/cpp/src/qpid/broker/management-schema.xml
- * describes the basic method schema, for example:
- *   <method name="create" desc="Create an object of the specified type">
- *     <arg name="type" dir="I" type="sstr" desc="The type of object to create"/>
- *     <arg name="name" dir="I" type="sstr" desc="The name of the object to create"/>
- *     <arg name="properties" dir="I" type="map" desc="Type specific object properties"/>
- *     <arg name="strict" dir="I" type="bool" desc="If specified, treat unrecognised object properties as an error"/>
- *   </method>
- *
- *   <method name="delete" desc="Delete an object of the specified type">
- *     <arg name="type" dir="I" type="sstr" desc="The type of object to delete"/>
- *     <arg name="name" dir="I" type="sstr" desc="The name of the object to delete"/>
- *     <arg name="options" dir="I" type="map" desc="Type specific object options for deletion"/>
- *   </method>
- *
- * What the schema doesn't do however is to explain what the properties/options
- * Map values actually mean, unfortunately these aren't documented anywhere so
- * the only option is to look in the code, the best place to look is in:
- * <qpid>/cpp/src/qpid/broker/Broker.cpp, the method Broker::ManagementMethod is
- * the best place to start, then Broker::createObject and Broker::deleteObject
- * even then it's pretty hard to figure out all that is possible.
- */
-
-var handleMethodResponse = function(response, dontStop) {
-    if (response._arguments) {
-        //console.log(response._arguments);
-    } if (response._values) {
-        console.error("Exception from Agent: " + renderObject(response._values));
-    }
-    // Mostly we want to stop the Messenger Event loop and exit when a QMF method
-    // returns, but sometimes we don't, the dontStop flag prevents this behaviour.
-    if (!dontStop) {
-        brokerAgent.destroy();
-    }
-}
-
-var addExchange = function(args) {
-    if (args.length < 2) {
-        usage();
-    }
-
-    var etype = args[0];
-    var ename = args[1];
-    var declArgs = {};
-
-    declArgs['exchange-type'] = etype;
-
-    for (var a = 0; a < config._extra_arguments.length; a++) {
-        var r = config._extra_arguments[a].split('=');
-        declArgs[r[0]] = getValue(r);
     }
-
-    if (config._msgSequence) {
-        declArgs[MSG_SEQUENCE] = 1;
-    }
-
-    if (config._ive) {
-        declArgs[IVE] = 1;
-    }
-
-    if (config._altern_ex) {
-        declArgs['alternate-exchange'] = config._altern_ex;
-    }
-
-    if (config._durable) {
-        declArgs['durable'] = 1;
-    }
-
-    if (config._replicate) {
-        declArgs[REPLICATE] = config._replicate;
-    }
-
-    brokerAgent.request(
-        // We invoke the CRUD methods on the broker object.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
-    ).then(function(objects) {
-        var broker = objects.broker[0];
-        brokerAgent.request(
-            brokerAgent.invokeMethod(broker, 'create', {
-                "type":      "exchange",
-                "name":       ename,
-                "properties": declArgs,
-                "strict":     true})
-        ).then(handleMethodResponse);
-    });
-};
-
-var delExchange = function(args) {
-    if (args.length < 1) {
-        usage();
-    }
-
-    var ename = args[0];
-
-    brokerAgent.request(
-        // We invoke the CRUD methods on the broker object.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
-    ).then(function(objects) {
-        var broker = objects.broker[0];
-        brokerAgent.request(
-            brokerAgent.invokeMethod(broker, 'delete', {
-                "type":   "exchange",
-                "name":    ename})
-        ).then(handleMethodResponse);
-    });
-};
-
-var addQueue = function(args) {
-    if (args.length < 1) {
-        usage();
-    }
-
-    var qname = args[0];
-    var declArgs = {};
-
-    for (var a = 0; a < config._extra_arguments.length; a++) {
-        var r = config._extra_arguments[a].split('=');
-        declArgs[r[0]] = getValue(r);
-    }
-
-    if (config._durable) {
-        // allow the default fileCount and fileSize specified 
-        // in qpid config file to take prededence
-        if (config._fileCount) {
-            declArgs[FILECOUNT] = config._fileCount;
+    
+    var addExchange = function(args) {
+        if (args.length < 2) {
+            usage();
         }
-        if (config._fileSize) {
-            declArgs[FILESIZE]  = config._fileSize;
+    
+        var etype = args[0];
+        var ename = args[1];
+        var declArgs = {};
+    
+        declArgs['exchange-type'] = etype;
+    
+        for (var a = 0; a < config._extra_arguments.length; a++) {
+            var r = config._extra_arguments[a].split('=');
+            declArgs[r[0]] = getValue(r);
         }
-    }
-
-    if (config._maxQueueSize != null) {
-        declArgs[MAX_QUEUE_SIZE] = config._maxQueueSize;
-    }
-
-    if (config._maxQueueCount != null) {
-        declArgs[MAX_QUEUE_COUNT] = config._maxQueueCount;
-    }
     
-    if (config._limitPolicy) {
-        if (config._limitPolicy === 'none') {
-        } else if (config._limitPolicy === 'reject') {
-            declArgs[POLICY_TYPE] = 'reject';
-        } else if (config._limitPolicy === 'ring') {
-            declArgs[POLICY_TYPE] = 'ring';
+        if (config._msgSequence) {
+            declArgs[MSG_SEQUENCE] = 1;
         }
-    }
-
-    if (config._lvq_key) {
-        declArgs[LVQ_KEY] = config._lvq_key;
-    }
-
-    if (config._eventGeneration) {
-        declArgs[QUEUE_EVENT_GENERATION] = config._eventGeneration;
-    }
-
-    if (config._flowStopSize != null) {
-        declArgs[FLOW_STOP_SIZE] = config._flowStopSize;
-    }
-
-    if (config._flowResumeSize != null) {
-        declArgs[FLOW_RESUME_SIZE] = config._flowResumeSize;
-    }
-
-    if (config._flowStopCount != null) {
-        declArgs[FLOW_STOP_COUNT] = config._flowStopCount;
-    }
-
-    if (config._flowResumeCount != null) {
-        declArgs[FLOW_RESUME_COUNT] = config._flowResumeCount;
-    }
-
-    if (config._msgGroupHeader) {
-        declArgs[MSG_GROUP_HDR_KEY] = config._msgGroupHeader;
-    }
-
-    if (config._sharedMsgGroup) {
-        declArgs[SHARED_MSG_GROUP] = 1;
-    }
-
-    if (config._altern_ex) {
-        declArgs['alternate-exchange'] = config._altern_ex;
-    }
-
-    if (config._durable) {
-        declArgs['durable'] = 1;
-    }
-
-    if (config._replicate) {
-        declArgs[REPLICATE] = config._replicate;
-    }
-
-    // This block is a little complex and untidy, the real issue is that the
-    // correlator object isn't as good as a real Promise and doesn't support
-    // chaining of "then" calls, so where we have complex dependencies we still
-    // get somewhat into "callback hell". TODO improve the correlator.
-    brokerAgent.request(
-        // We invoke the CRUD methods on the broker object.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
-    ).then(function(objects) {
-        var broker = objects.broker[0];
+    
+        if (config._ive) {
+            declArgs[IVE] = 1;
+        }
+    
+        if (config._altern_ex) {
+            declArgs['alternate-exchange'] = config._altern_ex;
+        }
+    
+        if (config._durable) {
+            declArgs['durable'] = 1;
+        }
+    
+        if (config._replicate) {
+            declArgs[REPLICATE] = config._replicate;
+        }
+    
         brokerAgent.request(
-            brokerAgent.invokeMethod(broker, 'create', {
-                "type":      "queue",
-                "name":       qname,
-                "properties": declArgs,
-                "strict":     true})
-        ).then(function(response) {
-            if (config._start_replica) {
-                handleMethodResponse(response, true); // The second parameter prevents exiting.
-                // TODO test this stuff!
-                brokerAgent.request(
-                    brokerAgent.getObjects('org.apache.qpid.ha', 'habroker') // Not sure if this is correct
-                ).then(function(objects) {
-                    if (objects.habroker.length > 0) {
-                        var habroker = objects.habroker[0];
-                        brokerAgent.request(
-                            brokerAgent.invokeMethod(habroker, 'replicate', {
-                                "broker": config._start_replica,
-                                "queue":  qname})
-                        ).then(handleMethodResponse);
-                    } else {
-                        brokerAgent.destroy();
-                    }
-                });
-            } else {
-                handleMethodResponse(response);
-            }
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                brokerAgent.invokeMethod(broker, 'create', {
+                    "type":      "exchange",
+                    "name":       ename,
+                    "properties": declArgs,
+                    "strict":     true})
+            ).then(handleMethodResponse);
         });
-    });
-};
-
-var delQueue = function(args) {
-    if (args.length < 1) {
-        usage();
-    }
-
-    var qname = args[0];
-
-    brokerAgent.request(
-        // We invoke the CRUD methods on the broker object.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
-    ).then(function(objects) {
-        var broker = objects.broker[0];
+    };
+    
+    var delExchange = function(args) {
+        if (args.length < 1) {
+            usage();
+        }
+    
+        var ename = args[0];
+    
         brokerAgent.request(
-            brokerAgent.invokeMethod(broker, 'delete', {
-                "type":   "queue",
-                "name":    qname,
-                "options": {"if_empty":  config._if_empty,
-                            "if_unused": config._if_unused}})
-        ).then(handleMethodResponse);
-    });
-};
-
-var snarf_header_args = function(args) {
-    if (args.length < 2) {
-        console.log("Invalid args to bind headers: need 'any'/'all' plus conditions");
-        return false;
-    }
-
-    var op = args[0];
-    if (op === 'all' || op === 'any') {
-        kv = {};
-        var bindings = Array.prototype.slice.apply(args, [1]);
-        for (var i = 0; i < bindings.length; i++) {
-            var binding = bindings[i];
-            binding = binding.split(",")[0];
-            binding = binding.split("=");
-            kv[binding[0]] = binding[1];
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                brokerAgent.invokeMethod(broker, 'delete', {
+                    "type":   "exchange",
+                    "name":    ename})
+            ).then(handleMethodResponse);
+        });
+    };
+    
+    var addQueue = function(args) {
+        if (args.length < 1) {
+            usage();
         }
-        kv['x-match'] = op;
-        return kv;
-    } else {
-        console.log("Invalid condition arg to bind headers, need 'any' or 'all', not '" + op + "'");
-        return false;
-    }
-};
-
-var bind = function(args) {
-    if (args.length < 2) {
-        usage();
-    }
-
-    var ename = args[0];
-    var qname = args[1];
-    var key   = '';
-
-    if (args.length > 2) {
-        key = args[2];
-    }
-
-    brokerAgent.request(
-        // We invoke the CRUD methods on the broker object.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'broker'),
-        brokerAgent.getObjects('org.apache.qpid.broker', 'exchange') // Get exchanges to look up exchange type.
-    ).then(function(objects) {
-        var exchanges = objects.exchange;
-
-        var etype = '';
-        for (var i = 0; i < exchanges.length; i++) {
-            var exchange = exchanges[i]._values;
-            if (exchange.name === ename) {
-                etype = exchange.type;
-                break;
+    
+        var qname = args[0];
+        var declArgs = {};
+    
+        for (var a = 0; a < config._extra_arguments.length; a++) {
+            var r = config._extra_arguments[a].split('=');
+            declArgs[r[0]] = getValue(r);
+        }
+    
+        if (config._durable) {
+            // allow the default fileCount and fileSize specified 
+            // in qpid config file to take prededence
+            if (config._fileCount) {
+                declArgs[FILECOUNT] = config._fileCount;
+            }
+            if (config._fileSize) {
+                declArgs[FILESIZE]  = config._fileSize;
             }
         }
-
-        // type of the xchg determines the processing of the rest of
-        // argv.  if it's an xml xchg, we want to find a file
-        // containing an x-query, and pass that.  if it's a headers
-        // exchange, we need to pass either "any" or all, followed by a
-        // map containing key/value pairs.  if neither of those, extra
-        // args are ignored.
-        var declArgs = {};
-        if (etype === 'xml') {
-
-
-        } else if (etype === 'headers') {
-            declArgs = snarf_header_args(Array.prototype.slice.apply(args, [3]));
+    
+        if (config._maxQueueSize != null) {
+            declArgs[MAX_QUEUE_SIZE] = config._maxQueueSize;
         }
-//console.log(declArgs);
-
-        if (typeof declArgs !== 'object') {
-            process.exit(1);
+    
+        if (config._maxQueueCount != null) {
+            declArgs[MAX_QUEUE_COUNT] = config._maxQueueCount;
         }
-
-        var broker = objects.broker[0];
-        brokerAgent.request(
-            brokerAgent.invokeMethod(broker, 'create', {
-                "type":   "binding",
-                "name":    ename + '/' + qname + '/' + key,
-                "properties": declArgs,
-                "strict":     true})
-        ).then(handleMethodResponse);
-    });
-
-/*
-
-        ok = True
-        _args = {}
-        if not res:
-            pass
-        elif res.type == "xml":
-            # this checks/imports the -f arg
-            [ok, xquery] = snarf_xquery_args()
-            _args = { "xquery" : xquery }
-        else:
-            if res.type == "headers":
-                [ok, op, kv] = snarf_header_args(args[3:])
-                _args = kv
-                _args["x-match"] = op
-
-        if not ok:
-            sys.exit(1)
-
-        self.broker.bind(ename, qname, key, _args)
-*/
-
-};
-
-var unbind = function(args) {
-    if (args.length < 2) {
-        usage();
-    }
-
-    var ename = args[0];
-    var qname = args[1];
-    var key   = '';
-
-    if (args.length > 2) {
-        key = args[2];
-    }
-
-    brokerAgent.request(
-        // We invoke the CRUD methods on the broker object.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
-    ).then(function(objects) {
-        var broker = objects.broker[0];
-        brokerAgent.request(
-            brokerAgent.invokeMethod(broker, 'delete', {
-                "type":   "binding",
-                "name":    ename + '/' + qname + '/' + key})
-        ).then(handleMethodResponse);
-    });
-};
-
-/**
- * The following methods are "generic" create and delete methods to for arbitrary
- * Management Objects e.g. Incoming, Outgoing, Domain, Topic, QueuePolicy,
- * TopicPolicy etc. use --argument k1=v1 --argument k2=v2 --argument k3=v3 to
- * pass arbitrary arguments as key/value pairs to the Object being created/deleted,
- * for example to add a topic object that uses the fanout exchange:
- * ./qpid-config.js add topic fanout --argument exchange=amq.fanout \
- * --argument qpid.max_size=1000000 --argument qpid.policy_type=ring
- */
-
-var createObject = function(type, name, args) {
-    brokerAgent.request(
-        // We invoke the CRUD methods on the broker object.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
-    ).then(function(objects) {
-        var broker = objects.broker[0];
-        brokerAgent.request(
-            // Create an object of the specified type.
-            brokerAgent.invokeMethod(broker, 'create', {
-                "type":       type,
-                "name":       name,
-                "properties": args,
-                "strict":     true})
-        ).then(handleMethodResponse);
-    });
-};
-
-var deleteObject = function(type, name, args) {
-    brokerAgent.request(
-        // We invoke the CRUD methods on the broker object.
-        brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
-    ).then(function(objects) {
-        var broker = objects.broker[0];
+        
+        if (config._limitPolicy) {
+            if (config._limitPolicy === 'none') {
+            } else if (config._limitPolicy === 'reject') {
+                declArgs[POLICY_TYPE] = 'reject';
+            } else if (config._limitPolicy === 'ring') {
+                declArgs[POLICY_TYPE] = 'ring';
+            }
+        }
+    
+        if (config._lvq_key) {
+            declArgs[LVQ_KEY] = config._lvq_key;
+        }
+    
+        if (config._eventGeneration) {
+            declArgs[QUEUE_EVENT_GENERATION] = config._eventGeneration;
+        }
+    
+        if (config._flowStopSize != null) {
+            declArgs[FLOW_STOP_SIZE] = config._flowStopSize;
+        }
+    
+        if (config._flowResumeSize != null) {
+            declArgs[FLOW_RESUME_SIZE] = config._flowResumeSize;
+        }
+    
+        if (config._flowStopCount != null) {
+            declArgs[FLOW_STOP_COUNT] = config._flowStopCount;
+        }
+    
+        if (config._flowResumeCount != null) {
+            declArgs[FLOW_RESUME_COUNT] = config._flowResumeCount;
+        }
+    
+        if (config._msgGroupHeader) {
+            declArgs[MSG_GROUP_HDR_KEY] = config._msgGroupHeader;
+        }
+    
+        if (config._sharedMsgGroup) {
+            declArgs[SHARED_MSG_GROUP] = 1;
+        }
+    
+        if (config._altern_ex) {
+            declArgs['alternate-exchange'] = config._altern_ex;
+        }
+    
+        if (config._durable) {
+            declArgs['durable'] = 1;
+        }
+    
+        if (config._replicate) {
+            declArgs[REPLICATE] = config._replicate;
+        }
+    
+        // This block is a little complex and untidy, the real issue is that the
+        // correlator object isn't as good as a real Promise and doesn't support
+        // chaining of "then" calls, so where we have complex dependencies we still
+        // get somewhat into "callback hell". TODO improve the correlator.
         brokerAgent.request(
-            // Create an object of the specified type and name.
-            brokerAgent.invokeMethod(broker, 'delete', {
-                "type":    type,
-                "name":    name,
-                "options": args})
-        ).then(handleMethodResponse);
-    });
-};
-
-/**
- * This is a "generic" mechanism for listing arbitrary Management Objects.
- */
-var listObjects = function(type) {
-    brokerAgent.request(
-        brokerAgent.getObjects('org.apache.qpid.broker', type)
-    ).then(function(objects) {
-        // The correlator passes an object containing responses for all of the
-        // supplied requests so we index it by the supplied type to get our response.
-        objects = objects[type];
-
-        // Collect available attributes, stringify the values and compute the max
-        // length of the value of each attribute so that we can later create a table.
-        var attributes = {};
-        var lengths = {};
-        for (var i = 0; i < objects.length; i++) {
-            var object = objects[i];
-            object = object._values;
-            for (var prop in object) {
-                if (typeof object[prop] === 'object') { // Stringify Object properties.
-                    // Check if property is an ObjectID (reference property),
-                    // if so replace with the "name" part of the OID.
-                    if (object[prop]['_object_name']) {
-                        var parts = object[prop]['_object_name'].split(':');
-                        object[prop] = parts[parts.length - 1];
-                    } else {
-                        // Stringify general Object properties.
-                        object[prop] = renderObject(object[prop]);
-                    }
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                brokerAgent.invokeMethod(broker, 'create', {
+                    "type":      "queue",
+                    "name":       qname,
+                    

<TRUNCATED>

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


[06/51] [abbrv] qpid-proton git commit: Pulling in changes from proton r1590241

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb b/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb
index 80716bb..86050ed 100644
--- a/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb
+++ b/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb
@@ -212,6 +212,16 @@ module Qpid
         @messenger.incoming_window.should eq(window)
       end
 
+      it "can be put into passive mode" do
+        @messenger.passive = true
+        @messenger.passive?.should be_true
+      end
+
+      it "can be taken out of passive mode" do
+        @messenger.passive = false
+        @messenger.passive?.should_not be_true
+      end
+
       describe "once started" do
 
         before (:each) do

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/codec.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/codec.h b/proton-c/include/proton/codec.h
index b54f7a5..af268fa 100644
--- a/proton-c/include/proton/codec.h
+++ b/proton-c/include/proton/codec.h
@@ -26,12 +26,7 @@
 #include <proton/object.h>
 #include <proton/types.h>
 #include <proton/error.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#include <stdint.h>
-#else
 #include <proton/type_compat.h>
-#endif
 #include <stdarg.h>
 
 #ifdef __cplusplus

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/condition.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/condition.h b/proton-c/include/proton/condition.h
index ab985f0..6fe0333 100644
--- a/proton-c/include/proton/condition.h
+++ b/proton-c/include/proton/condition.h
@@ -24,9 +24,7 @@
 
 #include <proton/import_export.h>
 #include <proton/codec.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/connection.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection.h b/proton-c/include/proton/connection.h
index 22c0652..104f78f 100644
--- a/proton-c/include/proton/connection.h
+++ b/proton-c/include/proton/connection.h
@@ -23,9 +23,7 @@
  */
 
 #include <proton/import_export.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/container.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/container.h b/proton-c/include/proton/container.h
index b0d57e3..a1de525 100644
--- a/proton-c/include/proton/container.h
+++ b/proton-c/include/proton/container.h
@@ -23,9 +23,7 @@
  */
 
 #include <proton/import_export.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/delivery.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/delivery.h b/proton-c/include/proton/delivery.h
index 016fc44..527eaed 100644
--- a/proton-c/include/proton/delivery.h
+++ b/proton-c/include/proton/delivery.h
@@ -24,9 +24,7 @@
 
 #include <proton/import_export.h>
 #include <proton/disposition.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/disposition.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/disposition.h b/proton-c/include/proton/disposition.h
index f4fcec1..2ee7068 100644
--- a/proton-c/include/proton/disposition.h
+++ b/proton-c/include/proton/disposition.h
@@ -23,9 +23,7 @@
  */
 
 #include <proton/import_export.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index 9ddbc05..fdb2803 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -23,9 +23,7 @@
  */
 
 #include <proton/import_export.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 
@@ -79,6 +77,15 @@ extern "C" {
 typedef struct pn_event_t pn_event_t;
 
 /**
+ * Related events are grouped into categories
+ */
+typedef enum {
+    PN_EVENT_CATEGORY_NONE   = 0,
+    PN_EVENT_CATEGORY_PROTOCOL = 0x00010000,
+    PN_EVENT_CATEGORY_COUNT = 2
+} pn_event_category_t;
+
+/**
  * An event type.
  */
 typedef enum {
@@ -92,37 +99,40 @@ typedef enum {
    * this type point to the relevant connection as well as its
    * associated transport.
    */
-  PN_CONNECTION_STATE = 1,
+  PN_CONNECTION_REMOTE_STATE = PN_EVENT_CATEGORY_PROTOCOL+1,
+  PN_CONNECTION_LOCAL_STATE = PN_EVENT_CATEGORY_PROTOCOL+2,
   /**
    * The endpoint state flags for a session have changed. Events of
    * this type point to the relevant session as well as its associated
    * connection and transport.
    */
-  PN_SESSION_STATE = 2,
+  PN_SESSION_REMOTE_STATE = PN_EVENT_CATEGORY_PROTOCOL+3,
+  PN_SESSION_LOCAL_STATE = PN_EVENT_CATEGORY_PROTOCOL+4,
   /**
    * The endpoint state flags for a link have changed. Events of this
    * type point to the relevant link as well as its associated
    * session, connection, and transport.
    */
-  PN_LINK_STATE = 4,
+  PN_LINK_REMOTE_STATE = PN_EVENT_CATEGORY_PROTOCOL+5,
+  PN_LINK_LOCAL_STATE = PN_EVENT_CATEGORY_PROTOCOL+6,
   /**
    * The flow control state for a link has changed. Events of this
    * type point to the relevant link along with its associated
    * session, connection, and transport.
    */
-  PN_LINK_FLOW = 8,
+  PN_LINK_FLOW = PN_EVENT_CATEGORY_PROTOCOL+7,
   /**
    * A delivery has been created or updated. Events of this type point
    * to the relevant delivery as well as its associated link, session,
    * connection, and transport.
    */
-  PN_DELIVERY = 16,
+  PN_DELIVERY = PN_EVENT_CATEGORY_PROTOCOL+8,
   /**
    * The transport has new data to read and/or write. Events of this
    * type point to the relevant transport as well as its associated
    * connection.
    */
-  PN_TRANSPORT = 32
+  PN_TRANSPORT = PN_EVENT_CATEGORY_PROTOCOL+9
 } pn_event_type_t;
 
 /**
@@ -180,6 +190,14 @@ PN_EXTERN bool pn_collector_pop(pn_collector_t *collector);
 PN_EXTERN pn_event_type_t pn_event_type(pn_event_t *event);
 
 /**
+ * Get the category an event belongs to.
+ *
+ * @param[in] event an event object
+ * @return the category the event belongs to
+ */
+PN_EXTERN pn_event_category_t pn_event_category(pn_event_t *event);
+
+/**
  * Get the connection associated with an event.
  *
  * @param[in] event an event object

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/framing.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/framing.h b/proton-c/include/proton/framing.h
index 0e69995..9650979 100644
--- a/proton-c/include/proton/framing.h
+++ b/proton-c/include/proton/framing.h
@@ -23,11 +23,7 @@
  */
 
 #include <proton/import_export.h>
-#ifndef __cplusplus
-#include <stdint.h>
-#else
 #include <proton/type_compat.h>
-#endif
 #include <sys/types.h>
 
 #ifdef __cplusplus

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/io.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/io.h b/proton-c/include/proton/io.h
index dc8ee77..fffc09a 100644
--- a/proton-c/include/proton/io.h
+++ b/proton-c/include/proton/io.h
@@ -26,9 +26,6 @@
 #include <proton/error.h>
 #include <sys/types.h>
 #include <proton/type_compat.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
 
 #ifdef __cplusplus
 extern "C" {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/link.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/link.h b/proton-c/include/proton/link.h
index 1fb73a9..8c5f82c 100644
--- a/proton-c/include/proton/link.h
+++ b/proton-c/include/proton/link.h
@@ -23,9 +23,7 @@
  */
 
 #include <proton/import_export.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/message.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/message.h b/proton-c/include/proton/message.h
index c6bfd5d..2857731 100644
--- a/proton-c/include/proton/message.h
+++ b/proton-c/include/proton/message.h
@@ -27,9 +27,7 @@
 #include <proton/codec.h>
 #include <proton/error.h>
 #include <sys/types.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -42,107 +40,777 @@ extern "C" {
  * @{
  */
 
+/**
+ * An AMQP Message object.
+ *
+ * An AMQP Message object is a mutable holder of message content that
+ * may be used to generate and encode or decode and access AMQP
+ * formatted message data.
+ */
 typedef struct pn_message_t pn_message_t;
 
+/**
+ * Encoding format for message content.
+ */
 typedef enum {
-  PN_DATA,
-  PN_TEXT,
-  PN_AMQP,
-  PN_JSON
+  PN_DATA, /**< Raw binary data. Not all messages can be encoded this way.*/
+  PN_TEXT, /**< Raw text. Not all messages can be encoded this way.*/
+  PN_AMQP, /**< AMQP formatted data. All messages can be encoded this way.*/
+  PN_JSON /**< JSON formatted data. Not all messages can be encoded with full fidelity way.*/
 } pn_format_t;
 
+/**
+ * Default priority for messages.
+ */
 #define PN_DEFAULT_PRIORITY (4)
 
+/**
+ * Construct a new ::pn_message_t.
+ *
+ * Every message that is constructed must be freed using
+ * ::pn_message_free().
+ *
+ * @return pointer to a new ::pn_message_t
+ */
 PN_EXTERN pn_message_t * pn_message(void);
+
+/**
+ * Free a previously constructed ::pn_message_t.
+ *
+ * @param[in] msg pointer to a ::pn_message_t or NULL
+ */
 PN_EXTERN void           pn_message_free(pn_message_t *msg);
 
+/**
+ * Clears the content of a ::pn_message_t.
+ *
+ * When pn_message_clear returns, the supplied ::pn_message_t will be
+ * emptied of all content and effectively returned to the same state
+ * as if it was just created.
+ *
+ * @param[in] msg pointer to the ::pn_message_t to be cleared
+ */
 PN_EXTERN void           pn_message_clear(pn_message_t *msg);
+
+/**
+ * Access the error code of a message.
+ *
+ * Every operation on a message that can result in an error will set
+ * the message's error code in case of error. The pn_message_errno()
+ * call will access the error code of the most recent failed
+ * operation.
+ *
+ * @param[in] msg a message
+ * @return the message's error code
+ */
 PN_EXTERN int            pn_message_errno(pn_message_t *msg);
+
+/**
+ * Access the error information for a message.
+ *
+ * Every operation on a message that can result in an error will
+ * update the error information held by its error descriptor should
+ * that operation fail. The pn_message_error() call will access the
+ * error information of the most recent failed operation. The pointer
+ * returned by this call is valid until the message is freed.
+ *
+ * @param[in] msg a message
+ * @return the message's error descriptor
+ */
 PN_EXTERN pn_error_t    *pn_message_error(pn_message_t *msg);
 
+/**
+ * Get the inferred flag for a message.
+ *
+ * The inferred flag for a message indicates how the message content
+ * is encoded into AMQP sections. If inferred is true then binary and
+ * list values in the body of the message will be encoded as AMQP DATA
+ * and AMQP SEQUENCE sections, respectively. If inferred is false,
+ * then all values in the body of the message will be encoded as AMQP
+ * VALUE sections regardless of their type. Use
+ * ::pn_message_set_inferred to set the value.
+ *
+ * @param[in] msg a message object
+ * @return the value of the inferred flag for the message
+ */
 PN_EXTERN bool           pn_message_is_inferred(pn_message_t *msg);
+
+/**
+ * Set the inferred flag for a message.
+ *
+ * See ::pn_message_is_inferred() for a description of what the
+ * inferred flag is.
+ *
+ * @param[in] msg a message object
+ * @param[in] inferred the new value of the inferred flag
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_inferred(pn_message_t *msg, bool inferred);
 
 // standard message headers and properties
+
+/**
+ * Get the durable flag for a message.
+ *
+ * The durable flag indicates that any parties taking responsibility
+ * for the message must durably store the content.
+ *
+ * @param[in] msg a message object
+ * @return the value of the durable flag
+ */
 PN_EXTERN bool           pn_message_is_durable            (pn_message_t *msg);
+
+/**
+ * Set the durable flag for a message.
+ *
+ * See ::pn_message_is_durable() for a description of the durable
+ * flag.
+ *
+ * @param[in] msg a message object
+ * @param[in] durable the new value of the durable flag
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_durable           (pn_message_t *msg, bool durable);
 
+/**
+ * Get the priority for a message.
+ *
+ * The priority of a message impacts ordering guarantees. Within a
+ * given ordered context, higher priority messages may jump ahead of
+ * lower priority messages.
+ *
+ * @param[in] msg a message object
+ * @return the message priority
+ */
 PN_EXTERN uint8_t        pn_message_get_priority          (pn_message_t *msg);
+
+/**
+ * Set the priority for a message.
+ *
+ * See ::pn_message_get_priority() for details on message priority.
+ *
+ * @param[in] msg a message object
+ * @param[in] priority the new priority for the message
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_priority          (pn_message_t *msg, uint8_t priority);
 
+/**
+ * Get the ttl for a message.
+ *
+ * The ttl for a message determines how long a message is considered
+ * live. When a message is held for retransmit, the ttl is
+ * decremented. Once the ttl reaches zero, the message is considered
+ * dead. Once a message is considered dead it may be dropped. Use
+ * ::pn_message_set_ttl() to set the ttl for a message.
+ *
+ * @param[in] msg a message object
+ * @return the ttl in milliseconds
+ */
 PN_EXTERN pn_millis_t    pn_message_get_ttl               (pn_message_t *msg);
+
+/**
+ * Set the ttl for a message.
+ *
+ * See ::pn_message_get_ttl() for a detailed description of message ttl.
+ *
+ * @param[in] msg a message object
+ * @param[in] ttl the new value for the message ttl
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_ttl               (pn_message_t *msg, pn_millis_t ttl);
 
+/**
+ * Get the first acquirer flag for a message.
+ *
+ * When set to true, the first acquirer flag for a message indicates
+ * that the recipient of the message is the first recipient to acquire
+ * the message, i.e. there have been no failed delivery attempts to
+ * other acquirers. Note that this does not mean the message has not
+ * been delivered to, but not acquired, by other recipients.
+ *
+ * @param[in] msg a message object
+ * @return the first acquirer flag for the message
+ */
 PN_EXTERN bool           pn_message_is_first_acquirer     (pn_message_t *msg);
+
+/**
+ * Set the first acquirer flag for a message.
+ *
+ * See ::pn_message_is_first_acquirer() for details on the first
+ * acquirer flag.
+ *
+ * @param[in] msg a message object
+ * @param[in] first the new value for the first acquirer flag
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_first_acquirer    (pn_message_t *msg, bool first);
 
+/**
+ * Get the delivery count for a message.
+ *
+ * The delivery count field tracks how many attempts have been made to
+ * delivery a message. Use ::pn_message_set_delivery_count() to set
+ * the delivery count for a message.
+ *
+ * @param[in] msg a message object
+ * @return the delivery count for the message
+ */
 PN_EXTERN uint32_t       pn_message_get_delivery_count    (pn_message_t *msg);
+
+/**
+ * Set the delivery count for a message.
+ *
+ * See ::pn_message_get_delivery_count() for details on what the
+ * delivery count means.
+ *
+ * @param[in] msg a message object
+ * @param[in] count the new delivery count
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_delivery_count    (pn_message_t *msg, uint32_t count);
 
+/**
+ * Get/set the id for a message.
+ *
+ * The message id provides a globally unique identifier for a message.
+ * A message id can be an a string, an unsigned long, a uuid or a
+ * binary value. This operation returns a pointer to a ::pn_data_t
+ * that can be used to access and/or modify the value of the message
+ * id. The pointer is valid until the message is freed. See
+ * ::pn_data_t for details on how to get/set the value.
+ *
+ * @param[in] msg a message object
+ * @return pointer to a ::pn_data_t holding the id
+ */
 PN_EXTERN pn_data_t *    pn_message_id                    (pn_message_t *msg);
+
+/**
+ * Get the id for a message.
+ *
+ * The message id provides a globally unique identifier for a message.
+ * A message id can be an a string, an unsigned long, a uuid or a
+ * binary value. This operation returns the value of the id using the
+ * ::pn_atom_t descriminated union. See ::pn_atom_t for details on how
+ * to access the value.
+ *
+ * @param[in] msg a message object
+ * @return the message id
+ */
 PN_EXTERN pn_atom_t      pn_message_get_id                (pn_message_t *msg);
+
+/**
+ * Set the id for a message.
+ *
+ * See ::pn_message_get_id() for more details on the meaning of the
+ * message id. Note that only string, unsigned long, uuid, or binary
+ * values are permitted.
+ *
+ * @param[in] msg a message object
+ * @param[in] id the new value of the message id
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_id                (pn_message_t *msg, pn_atom_t id);
 
+/**
+ * Get the user id for a message.
+ *
+ * The pointer referenced by the ::pn_bytes_t struct will be valid
+ * until any one of the following operations occur:
+ *
+ *  - ::pn_message_free()
+ *  - ::pn_message_clear()
+ *  - ::pn_message_set_user_id()
+ *
+ * @param[in] msg a message object
+ * @return a pn_bytes_t referencing the message's user_id
+ */
 PN_EXTERN pn_bytes_t     pn_message_get_user_id           (pn_message_t *msg);
+
+/**
+ * Set the user id for a message.
+ *
+ * This operation copies the bytes referenced by the provided
+ * ::pn_bytes_t struct.
+ *
+ * @param[in] msg a message object
+ * @param[in] user_id the new user_id for the message
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_user_id           (pn_message_t *msg, pn_bytes_t user_id);
 
+/**
+ * Get the address for a message.
+ *
+ * This operation will return NULL if no address has been set or if
+ * the address has been set to NULL. The pointer returned by this
+ * operation is valid until any one of the following operations occur:
+ *
+ *  - ::pn_message_free()
+ *  - ::pn_message_clear()
+ *  - ::pn_message_set_address()
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the address of the message (or NULL)
+ */
 PN_EXTERN const char *   pn_message_get_address           (pn_message_t *msg);
+
+/**
+ * Set the address for a message.
+ *
+ * The supplied address pointer must either be NULL or reference a NUL
+ * terminated string. When the pointer is NULL, the address of the
+ * message is set to NULL. When the pointer is non NULL, the contents
+ * are copied into the message.
+ *
+ * @param[in] msg a message object
+ * @param[in] address a pointer to the new address (or NULL)
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_address           (pn_message_t *msg, const char *address);
 
+/**
+ * Get the subject for a message.
+ *
+ * This operation will return NULL if no subject has been set or if
+ * the subject has been set to NULL. The pointer returned by this
+ * operation is valid until any one of the following operations occur:
+ *
+ *  - ::pn_message_free()
+ *  - ::pn_message_clear()
+ *  - ::pn_message_set_subject()
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the subject of the message (or NULL)
+ */
 PN_EXTERN const char *   pn_message_get_subject           (pn_message_t *msg);
+
+/**
+ * Set the subject for a message.
+ *
+ * The supplied subject pointer must either be NULL or reference a NUL
+ * terminated string. When the pointer is NULL, the subject is set to
+ * NULL. When the pointer is non NULL, the contents are copied into
+ * the message.
+ *
+ * @param[in] msg a message object
+ * @param[in] subject a pointer to the new subject (or NULL)
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_subject           (pn_message_t *msg, const char *subject);
 
+/**
+ * Get the reply_to for a message.
+ *
+ * This operation will return NULL if no reply_to has been set or if
+ * the reply_to has been set to NULL. The pointer returned by this
+ * operation is valid until any one of the following operations occur:
+ *
+ *  - ::pn_message_free()
+ *  - ::pn_message_clear()
+ *  - ::pn_message_set_reply_to()
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the reply_to of the message (or NULL)
+ */
 PN_EXTERN const char *   pn_message_get_reply_to          (pn_message_t *msg);
+
+/**
+ * Set the reply_to for a message.
+ *
+ * The supplied reply_to pointer must either be NULL or reference a NUL
+ * terminated string. When the pointer is NULL, the reply_to is set to
+ * NULL. When the pointer is non NULL, the contents are copied into
+ * the message.
+ *
+ * @param[in] msg a message object
+ * @param[in] reply_to a pointer to the new reply_to (or NULL)
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_reply_to          (pn_message_t *msg, const char *reply_to);
 
+/**
+ * Get/set the correlation id for a message.
+ *
+ * A correlation id can be an a string, an unsigned long, a uuid or a
+ * binary value. This operation returns a pointer to a ::pn_data_t
+ * that can be used to access and/or modify the value of the
+ * correlation id. The pointer is valid until the message is freed.
+ * See ::pn_data_t for details on how to get/set the value.
+ *
+ * @param[in] msg a message object
+ * @return pointer to a ::pn_data_t holding the correlation id
+ */
 PN_EXTERN pn_data_t *    pn_message_correlation_id        (pn_message_t *msg);
+
+/**
+ * Get the correlation id for a message.
+ *
+ * A correlation id can be an a string, an unsigned long, a uuid or a
+ * binary value. This operation returns the value of the id using the
+ * ::pn_atom_t descriminated union. See ::pn_atom_t for details on how
+ * to access the value.
+ *
+ * @param[in] msg a message object
+ * @return the message id
+ */
 PN_EXTERN pn_atom_t      pn_message_get_correlation_id    (pn_message_t *msg);
-PN_EXTERN int            pn_message_set_correlation_id    (pn_message_t *msg, pn_atom_t atom);
 
+/**
+ * Set the correlation id for a message.
+ *
+ * See ::pn_message_get_correlation_id() for more details on the
+ * meaning of the correlation id. Note that only string, unsigned
+ * long, uuid, or binary values are permitted.
+ *
+ * @param[in] msg a message object
+ * @param[in] id the new value of the message id
+ * @return zero on success or an error code on failure
+ */
+PN_EXTERN int            pn_message_set_correlation_id    (pn_message_t *msg, pn_atom_t id);
+
+/**
+ * Get the content_type for a message.
+ *
+ * This operation will return NULL if no content_type has been set or if
+ * the content_type has been set to NULL. The pointer returned by this
+ * operation is valid until any one of the following operations occur:
+ *
+ *  - ::pn_message_free()
+ *  - ::pn_message_clear()
+ *  - ::pn_message_set_content_type()
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the content_type of the message (or NULL)
+ */
 PN_EXTERN const char *   pn_message_get_content_type      (pn_message_t *msg);
+
+/**
+ * Set the content_type for a message.
+ *
+ * The supplied content_type pointer must either be NULL or reference a NUL
+ * terminated string. When the pointer is NULL, the content_type is set to
+ * NULL. When the pointer is non NULL, the contents are copied into
+ * the message.
+ *
+ * @param[in] msg a message object
+ * @param[in] type a pointer to the new content_type (or NULL)
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_content_type      (pn_message_t *msg, const char *type);
 
+/**
+ * Get the content_encoding for a message.
+ *
+ * This operation will return NULL if no content_encoding has been set or if
+ * the content_encoding has been set to NULL. The pointer returned by this
+ * operation is valid until any one of the following operations occur:
+ *
+ *  - ::pn_message_free()
+ *  - ::pn_message_clear()
+ *  - ::pn_message_set_content_encoding()
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the content_encoding of the message (or NULL)
+ */
 PN_EXTERN const char *   pn_message_get_content_encoding  (pn_message_t *msg);
+
+/**
+ * Set the content_encoding for a message.
+ *
+ * The supplied content_encoding pointer must either be NULL or reference a NUL
+ * terminated string. When the pointer is NULL, the content_encoding is set to
+ * NULL. When the pointer is non NULL, the contents are copied into
+ * the message.
+ *
+ * @param[in] msg a message object
+ * @param[in] encoding a pointer to the new content_encoding (or NULL)
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_content_encoding  (pn_message_t *msg, const char *encoding);
 
+/**
+ * Get the expiry time for a message.
+ *
+ * A zero value for the expiry time indicates that the message will
+ * never expire. This is the default value.
+ *
+ * @param[in] msg a message object
+ * @return the expiry time for the message
+ */
 PN_EXTERN pn_timestamp_t pn_message_get_expiry_time       (pn_message_t *msg);
+
+/**
+ * Set the expiry time for a message.
+ *
+ * See ::pn_message_get_expiry_time() for more details.
+ *
+ * @param[in] msg a message object
+ * @param[in] time the new expiry time for the message
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_expiry_time       (pn_message_t *msg, pn_timestamp_t time);
 
+/**
+ * Get the creation time for a message.
+ *
+ * A zero value for the creation time indicates that the creation time
+ * has not been set. This is the default value.
+ *
+ * @param[in] msg a message object
+ * @return the creation time for the message
+ */
 PN_EXTERN pn_timestamp_t pn_message_get_creation_time     (pn_message_t *msg);
+
+/**
+ * Set the creation time for a message.
+ *
+ * See ::pn_message_get_creation_time() for more details.
+ *
+ * @param[in] msg a message object
+ * @param[in] time the new creation time for the message
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_creation_time     (pn_message_t *msg, pn_timestamp_t time);
 
+/**
+ * Get the group_id for a message.
+ *
+ * This operation will return NULL if no group_id has been set or if
+ * the group_id has been set to NULL. The pointer returned by this
+ * operation is valid until any one of the following operations occur:
+ *
+ *  - ::pn_message_free()
+ *  - ::pn_message_clear()
+ *  - ::pn_message_set_group_id()
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the group_id of the message (or NULL)
+ */
 PN_EXTERN const char *   pn_message_get_group_id          (pn_message_t *msg);
+
+/**
+ * Set the group_id for a message.
+ *
+ * The supplied group_id pointer must either be NULL or reference a NUL
+ * terminated string. When the pointer is NULL, the group_id is set to
+ * NULL. When the pointer is non NULL, the contents are copied into
+ * the message.
+ *
+ * @param[in] msg a message object
+ * @param[in] group_id a pointer to the new group_id (or NULL)
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_group_id          (pn_message_t *msg, const char *group_id);
 
+/**
+ * Get the group sequence for a message.
+ *
+ * The group sequence of a message identifies the relative ordering of
+ * messages within a group. The default value for the group sequence
+ * of a message is zero.
+ *
+ * @param[in] msg a message object
+ * @return the group sequence for the message
+ */
 PN_EXTERN pn_sequence_t  pn_message_get_group_sequence    (pn_message_t *msg);
+
+/**
+ * Set the group sequence for a message.
+ *
+ * See ::pn_message_get_group_sequence() for details on what the group
+ * sequence means.
+ *
+ * @param[in] msg a message object
+ * @param[in] n the new group sequence for the message
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_group_sequence    (pn_message_t *msg, pn_sequence_t n);
 
+/**
+ * Get the reply_to_group_id for a message.
+ *
+ * This operation will return NULL if no reply_to_group_id has been set or if
+ * the reply_to_group_id has been set to NULL. The pointer returned by this
+ * operation is valid until any one of the following operations occur:
+ *
+ *  - ::pn_message_free()
+ *  - ::pn_message_clear()
+ *  - ::pn_message_set_reply_to_group_id()
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the reply_to_group_id of the message (or NULL)
+ */
 PN_EXTERN const char *   pn_message_get_reply_to_group_id (pn_message_t *msg);
+
+/**
+ * Set the reply_to_group_id for a message.
+ *
+ * The supplied reply_to_group_id pointer must either be NULL or reference a NUL
+ * terminated string. When the pointer is NULL, the reply_to_group_id is set to
+ * NULL. When the pointer is non NULL, the contents are copied into
+ * the message.
+ *
+ * @param[in] msg a message object
+ * @param[in] reply_to_group_id a pointer to the new reply_to_group_id (or NULL)
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int            pn_message_set_reply_to_group_id (pn_message_t *msg, const char *reply_to_group_id);
 
+/**
+ * @deprecated
+ */
 PN_EXTERN pn_format_t pn_message_get_format(pn_message_t *message);
+
+/**
+ * @deprecated
+ */
 PN_EXTERN int pn_message_set_format(pn_message_t *message, pn_format_t format);
 
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_load(pn_message_t *message, const char *data, size_t size);
+
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_load_data(pn_message_t *message, const char *data, size_t size);
+
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_load_text(pn_message_t *message, const char *data, size_t size);
+
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_load_amqp(pn_message_t *message, const char *data, size_t size);
+
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_load_json(pn_message_t *message, const char *data, size_t size);
 
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_save(pn_message_t *message, char *data, size_t *size);
+
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_save_data(pn_message_t *message, char *data, size_t *size);
+
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_save_text(pn_message_t *message, char *data, size_t *size);
+
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_save_amqp(pn_message_t *message, char *data, size_t *size);
+
+/**
+ * @deprecated Use ::pn_message_body() instead.
+ */
 PN_EXTERN int pn_message_save_json(pn_message_t *message, char *data, size_t *size);
 
+/**
+ * Get/set the delivery instructions for a message.
+ *
+ * This operation returns a pointer to a ::pn_data_t representing the
+ * content of the delivery instructions section of a message. The
+ * pointer is valid until the message is freed and may be used to both
+ * access and modify the content of the delivery instructions section
+ * of a message.
+ *
+ * The ::pn_data_t must either be empty or consist of a symbol keyed
+ * map in order to be considered valid delivery instructions.
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the delivery instructions
+ */
 PN_EXTERN pn_data_t *pn_message_instructions(pn_message_t *msg);
+
+/**
+ * Get/set the annotations for a message.
+ *
+ * This operation returns a pointer to a ::pn_data_t representing the
+ * content of the annotations section of a message. The pointer is
+ * valid until the message is freed and may be used to both access and
+ * modify the content of the annotations section of a message.
+ *
+ * The ::pn_data_t must either be empty or consist of a symbol keyed
+ * map in order to be considered valid message annotations.
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the message annotations
+ */
 PN_EXTERN pn_data_t *pn_message_annotations(pn_message_t *msg);
+
+/**
+ * Get/set the properties for a message.
+ *
+ * This operation returns a pointer to a ::pn_data_t representing the
+ * content of the properties section of a message. The pointer is
+ * valid until the message is freed and may be used to both access and
+ * modify the content of the properties section of a message.
+ *
+ * The ::pn_data_t must either be empty or consist of a string keyed
+ * map in order to be considered valid message properties.
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the message properties
+ */
 PN_EXTERN pn_data_t *pn_message_properties(pn_message_t *msg);
+
+/**
+ * Get/set the body of a message.
+ *
+ * This operation returns a pointer to a ::pn_data_t representing the
+ * body of a message. The pointer is valid until the message is freed
+ * and may be used to both access and modify the content of the
+ * message body.
+ *
+ * @param[in] msg a message object
+ * @return a pointer to the message body
+ */
 PN_EXTERN pn_data_t *pn_message_body(pn_message_t *msg);
 
+/**
+ * Decode/load message content from AMQP formatted binary data.
+ *
+ * Upon invoking this operation, any existing message content will be
+ * cleared and replaced with the content from the provided binary
+ * data.
+ *
+ * @param[in] msg a message object
+ * @param[in] bytes the start of the encoded AMQP data
+ * @param[in] size the size of the encoded AMQP data
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size);
+
+/**
+ * Encode/save message content as AMQP formatted binary data.
+ *
+ * If the buffer space provided is insufficient to store the content
+ * held in the message, the operation will fail and return a
+ * ::PN_OVERFLOW error code.
+ *
+ * @param[in] msg a message object
+ * @param[in] bytes the start of empty buffer space
+ * @param[in] size the amount of empty buffer space
+ * @param[out] size the amount of data written
+ * @return zero on success or an error code on failure
+ */
 PN_EXTERN int pn_message_encode(pn_message_t *msg, char *bytes, size_t *size);
 
+/**
+ * @deprecated
+ */
 PN_EXTERN ssize_t pn_message_data(char *dst, size_t available, const char *src, size_t size);
 
 /** @}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/object.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/object.h b/proton-c/include/proton/object.h
index 94d82d0..dc4983a 100644
--- a/proton-c/include/proton/object.h
+++ b/proton-c/include/proton/object.h
@@ -24,12 +24,7 @@
 
 #include <proton/types.h>
 #include <stdarg.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#include <stdint.h>
-#else
 #include <proton/type_compat.h>
-#endif
 #include <stddef.h>
 #include <proton/import_export.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/sasl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/sasl.h b/proton-c/include/proton/sasl.h
index 7a4cc2d..0cd9141 100644
--- a/proton-c/include/proton/sasl.h
+++ b/proton-c/include/proton/sasl.h
@@ -24,9 +24,7 @@
 
 #include <proton/import_export.h>
 #include <sys/types.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <proton/engine.h>
 
 #ifdef __cplusplus

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/selectable.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/selectable.h b/proton-c/include/proton/selectable.h
index 078999f..7d048c4 100644
--- a/proton-c/include/proton/selectable.h
+++ b/proton-c/include/proton/selectable.h
@@ -25,9 +25,7 @@
 #include <proton/import_export.h>
 #include <proton/object.h>
 #include <proton/io.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 
 #ifdef __cplusplus
 extern "C" {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/selector.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/selector.h b/proton-c/include/proton/selector.h
index 541caf0..37370d4 100644
--- a/proton-c/include/proton/selector.h
+++ b/proton-c/include/proton/selector.h
@@ -24,9 +24,7 @@
 
 #include <proton/import_export.h>
 #include <proton/selectable.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 
 #ifdef __cplusplus
 extern "C" {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/session.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/session.h b/proton-c/include/proton/session.h
index 711e14e..678b141 100644
--- a/proton-c/include/proton/session.h
+++ b/proton-c/include/proton/session.h
@@ -23,9 +23,7 @@
  */
 
 #include <proton/import_export.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/ssl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/ssl.h b/proton-c/include/proton/ssl.h
index 40fec95..cf5061d 100644
--- a/proton-c/include/proton/ssl.h
+++ b/proton-c/include/proton/ssl.h
@@ -24,9 +24,7 @@
 
 #include <proton/import_export.h>
 #include <sys/types.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <proton/engine.h>
 
 #ifdef __cplusplus

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/terminus.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/terminus.h b/proton-c/include/proton/terminus.h
index af7af8f..9c9096b 100644
--- a/proton-c/include/proton/terminus.h
+++ b/proton-c/include/proton/terminus.h
@@ -23,9 +23,7 @@
  */
 
 #include <proton/import_export.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/transport.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/transport.h b/proton-c/include/proton/transport.h
index ab81e09..1fa24c8 100644
--- a/proton-c/include/proton/transport.h
+++ b/proton-c/include/proton/transport.h
@@ -23,9 +23,7 @@
  */
 
 #include <proton/import_export.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
+#include <proton/type_compat.h>
 #include <stddef.h>
 #include <sys/types.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/type_compat.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/type_compat.h b/proton-c/include/proton/type_compat.h
index 6b5b958..9501d9a 100644
--- a/proton-c/include/proton/type_compat.h
+++ b/proton-c/include/proton/type_compat.h
@@ -22,6 +22,22 @@
  *
  */
 
+// Get Boolean
+#if !defined(__cplusplus) && !defined(__bool_true_false_are_defined)
+# if __STDC_VERSION__ >= 199901L || __GNUC__ >= 3 || _MSC_VER >=1800
+#  include <stdbool.h>
+# else
+// Need to get bool/true/false manually
+#  if _MSC_VER
+#   define bool char
+#   define false 0
+#   define true 1
+#   define __bool_true_false_are_defined
+#  else
+#   error "No definitions for bool/true/false"
+#  endif
+# endif
+#endif
 /*
  * Handle special cases for stdint.h and the definition for ssize_t.
  * Third party libraries (e.g. Boost) may provide competing solutions.
@@ -34,70 +50,70 @@
 
 // Honor positive overrides
 #if defined(PN_DEFINE_STDINT)
-#define PNI_DEFINE_STDINT
+# define PNI_DEFINE_STDINT
 #endif
 #if defined(PN_INCLUDE_STDINT)
-#define PNI_INCLUDE_STDINT)
+# define PNI_INCLUDE_STDINT)
 #endif
 #if defined(PN_DEFINE_SSIZE_T)
-#define PNI_DEFINE_SSIZE_T
+# define PNI_DEFINE_SSIZE_T
 #endif
 
 // Determinine default action
 #ifndef _MSC_VER
 // Not Windows and not using Visual Studio
-#ifndef PNI_INCLUDE_STDINT
-#define PNI_INCLUDE_STDINT
-#endif
+# ifndef PNI_INCLUDE_STDINT
+#  define PNI_INCLUDE_STDINT
+# endif
 #else
 // all versions of Visual Studio
-#ifndef PNI_DEFINE_SSIZE_T
-// ssie_t def is needed, unless third party definition interferes, e.g. python/swig
-#ifndef Py_CONFIG_H
-#define PNI_DEFINE_SSIZE_T
-#endif
-#endif
+# ifndef PNI_DEFINE_SSIZE_T
+// ssize_t def is needed, unless third party definition interferes, e.g. python/swig
+#  ifndef Py_CONFIG_H
+#   define PNI_DEFINE_SSIZE_T
+#  endif
+# endif
 
-#if (_MSC_VER < 1600)
+# if (_MSC_VER < 1600)
 // VS 2008 and earlier
-#ifndef PNI_DEFINE_STDINT
-#define PNI_DEFINE_STDINT
-#endif
-#else
+#  ifndef PNI_DEFINE_STDINT
+#   define PNI_DEFINE_STDINT
+#  endif
+# else
 // VS 2010 and newer
-#ifndef PNI_INCLUDE_STDINT
-#define PNI_INCLUDE_STDINT
-#endif
+#  ifndef PNI_INCLUDE_STDINT
+#   define PNI_INCLUDE_STDINT
+#  endif
 
-#endif // (_MSC_VER < 1600)
+# endif // (_MSC_VER < 1600)
 #endif //_MSC_VER
 
 // Honor negative overrides
 #ifdef PN_NODEFINE_SSIZE_T
-#undef PNI_DEFINE_SSIZE_T
+# undef PNI_DEFINE_SSIZE_T
 #endif
 #ifdef PN_NODEFINE_STDINT
-#undef PNI_DEFINE_STDINT
+# undef PNI_DEFINE_STDINT
 #endif
 #ifdef PN_NOINCLUDE_STDINT
-#undef PNI_INCLUDE_STDINT
+# undef PNI_INCLUDE_STDINT
 #endif
 
 #ifdef PNI_INCLUDE_STDINT
-#include <stdint.h>
+# include <stdint.h>
 #endif
 
 #ifdef PNI_DEFINE_SSIZE_T
-#ifdef _MSC_VER
-#include <BaseTsd.h>
+# ifdef _MSC_VER
+#  include <BaseTsd.h>
 typedef SSIZE_T ssize_t;
-#else
-#error ssize_t definition not kown
-#endif
+# else
+#  error ssize_t definition not kown
+# endif
 #endif // PNI_DEFINE_SSIZE_T
 
 #ifdef PNI_DEFINE_STDINT
-#ifdef _MSC_VER
+# ifdef _MSC_VER
 
 typedef signed __int8 int8_t;
 typedef signed __int16 int16_t;
@@ -109,9 +125,9 @@ typedef unsigned __int16 uint16_t;
 typedef unsigned __int32 uint32_t;
 typedef unsigned __int64 uint64_t;
 
-#else // _MSC_VER
-#error stdint.h definitions not kown
-#endif
+# else // _MSC_VER
+#  error stdint.h definitions not kown
+# endif
 #endif // PNI_DEFINE_SSIZE_T
 
 #endif /* type_compat.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/include/proton/types.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/types.h b/proton-c/include/proton/types.h
index f06bc2a..4182f25 100644
--- a/proton-c/include/proton/types.h
+++ b/proton-c/include/proton/types.h
@@ -24,11 +24,7 @@
 
 #include <proton/import_export.h>
 #include <sys/types.h>
-#ifndef __cplusplus
-#include <stdint.h>
-#else
 #include <proton/type_compat.h>
-#endif
 
 /**
  * @file
@@ -152,6 +148,85 @@ typedef struct pn_link_t pn_link_t;
  * associated with an AMQP Delivery. Every delivery exists within the
  * context of a ::pn_link_t object.
  *
+ * The AMQP model for settlement is based on the lifecycle of a
+ * delivery at an endpoint. At each end of a link, a delivery is
+ * created, it exists for some period of time, and finally it is
+ * forgotten, aka settled. Note that because this lifecycle happens
+ * independently at both the sender and the receiver, there are
+ * actually four events of interest in the combined lifecycle of a
+ * given delivery:
+ *
+ *   - created at sender
+ *   - created at receiver
+ *   - settled at sender
+ *   - settled at receiver
+ *
+ * Because the sender and receiver are operating concurrently, these
+ * events can occur in a variety of different orders, and the order of
+ * these events impacts the types of failures that may occur when
+ * transferring a delivery. Eliminating scenarios where the receiver
+ * creates the delivery first, we have the following possible
+ * sequences of interest:
+ *
+ * Sender presettles (aka at-most-once):
+ * -------------------------------------
+ *
+ *   1. created at sender
+ *   2. settled at sender
+ *   3. created at receiver
+ *   4. settled at receiver
+ *
+ * In this configuration the sender settles (i.e. forgets about) the
+ * delivery before it even reaches the receiver, and if anything
+ * should happen to the delivery in-flight, there is no way to
+ * recover, hence the "at most once" semantics.
+ *
+ * Receiver settles first (aka at-least-once):
+ * -------------------------------------------
+ *
+ *   1. created at sender
+ *   2. created at receiver
+ *   3. settled at receiver
+ *   4. settled at sender
+ *
+ * In this configuration the receiver settles the delivery first, and
+ * the sender settles once it sees the receiver has settled. Should
+ * anything happen to the delivery in-flight, the sender can resend,
+ * however the receiver may have already forgotten the delivery and so
+ * it could interpret the resend as a new delivery, hence the "at
+ * least once" semantics.
+ *
+ * Receiver settles second (aka exactly-once):
+ * -------------------------------------------
+ *
+ *   1. created at sender
+ *   2. created at receiver
+ *   3. settled at sender
+ *   4. settled at receiver
+ *
+ * In this configuration the receiver settles only once it has seen
+ * that the sender has settled. This provides the sender the option to
+ * retransmit, and the receiver has the option to recognize (and
+ * discard) duplicates, allowing for exactly once semantics.
+ *
+ * Note that in the last scenario the sender needs some way to know
+ * when it is safe to settle. This is where delivery state comes in.
+ * In addition to these lifecycle related events surrounding
+ * deliveries there is also the notion of a delivery state that can
+ * change over the lifetime of a delivery, e.g. it might start out as
+ * nothing, transition to ::PN_RECEIVED and then transition to
+ * ::PN_ACCEPTED. In the first two scenarios the delivery state isn't
+ * required, however in final scenario the sender would typically
+ * trigger settlement based on seeing the delivery state transition to
+ * a terminal state like ::PN_ACCEPTED or ::PN_REJECTED.
+ *
+ * In practice settlement is controlled by application policy, so
+ * there may well be more options here, e.g. a sender might not settle
+ * strictly based on what has happened at the receiver, it might also
+ * choose to impose some time limit and settle after that period has
+ * expired, or it could simply have a sliding window of the last N
+ * deliveries and settle the oldest whenever a new one comes along.
+ *
  * @ingroup delivery
  */
 typedef struct pn_delivery_t pn_delivery_t;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/ProtonConfig.cmake.in
----------------------------------------------------------------------
diff --git a/proton-c/src/ProtonConfig.cmake.in b/proton-c/src/ProtonConfig.cmake.in
new file mode 100644
index 0000000..fce1a3a
--- /dev/null
+++ b/proton-c/src/ProtonConfig.cmake.in
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Name: Proton
+# Description: Qpid Proton C library
+# Version: @PN_VERSION@
+# URL: http://qpid.apache.org/proton/
+
+set (Proton_VERSION       @PN_VERSION@)
+
+set (Proton_INCLUDE_DIRS  @INCLUDEDIR@)
+set (Proton_LIBRARIES     optimized @LIBDIR@/@PROTONLIB@ debug @LIBDIR@/@PROTONLIBDEBUG@)
+
+set (Proton_FOUND True)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/ProtonConfigVersion.cmake.in
----------------------------------------------------------------------
diff --git a/proton-c/src/ProtonConfigVersion.cmake.in b/proton-c/src/ProtonConfigVersion.cmake.in
new file mode 100644
index 0000000..d40f5c3
--- /dev/null
+++ b/proton-c/src/ProtonConfigVersion.cmake.in
@@ -0,0 +1,30 @@
+# This is a basic version file for the Config-mode of find_package().
+# It is used by write_basic_package_version_file() as input file for configure_file()
+# to create a version-file which can be installed along a config.cmake file.
+#
+# The created file sets PACKAGE_VERSION_EXACT if the current version string and
+# the requested version string are exactly the same and it sets
+# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
+
+set(PACKAGE_VERSION "@PN_VERSION@")
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+  set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+  set(PACKAGE_VERSION_COMPATIBLE TRUE)
+  if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+    set(PACKAGE_VERSION_EXACT TRUE)
+  endif()
+endif()
+
+# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
+if("${CMAKE_SIZEOF_VOID_P}"  STREQUAL ""  OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "")
+   return()
+endif()
+
+# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
+if(NOT "${CMAKE_SIZEOF_VOID_P}"  STREQUAL  "@CMAKE_SIZEOF_VOID_P@")
+   math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8")
+   set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
+   set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/engine/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine.c b/proton-c/src/engine/engine.c
index fda523f..718974a 100644
--- a/proton-c/src/engine/engine.c
+++ b/proton-c/src/engine/engine.c
@@ -33,6 +33,7 @@
 #include "../platform.h"
 #include "../platform_fmt.h"
 #include "../transport/transport.h"
+#include "../engine/event.h"
 
 // endpoints
 
@@ -51,18 +52,61 @@ pn_connection_t *pn_ep_get_connection(pn_endpoint_t *endpoint)
   return NULL;
 }
 
+/* map the endpoint type to its local event type */
+static const pn_event_type_t endpoint_event_map[] = {
+  PN_CONNECTION_LOCAL_STATE,  /* CONNECTION */
+  PN_SESSION_LOCAL_STATE,     /* SESSION */
+  PN_LINK_LOCAL_STATE,        /* SENDER */
+  PN_LINK_LOCAL_STATE};       /* RECEIVER */
+
+/* setup the event given the endpoint that generated the event */
+static void endpoint_init_event(pn_event_t *event,
+                                pn_endpoint_t *endpoint)
+{
+  switch (endpoint->type) {
+  case CONNECTION: {
+      pn_connection_t *conn = (pn_connection_t *) endpoint;
+      pn_event_init_connection(event, conn);
+    }
+    break;
+  case SESSION: {
+      pn_session_t *ssn = (pn_session_t *) endpoint;
+      pn_event_init_session(event, ssn);
+    }
+    break;
+  case SENDER:
+  case RECEIVER: {
+      pn_link_t *link = (pn_link_t*) endpoint;
+      pn_event_init_link(event, link);
+    }
+    break;
+  }
+}
+
 static void pn_endpoint_open(pn_endpoint_t *endpoint)
 {
   // TODO: do we care about the current state?
   PN_SET_LOCAL(endpoint->state, PN_LOCAL_ACTIVE);
-  pn_modified(pn_ep_get_connection(endpoint), endpoint, true);
+  pn_connection_t *conn = pn_ep_get_connection(endpoint);
+  pn_event_t *event = pn_collector_put(conn->collector,
+                                       endpoint_event_map[endpoint->type]);
+  if (event) {
+    endpoint_init_event(event, endpoint);
+  }
+  pn_modified(conn, endpoint, true);
 }
 
-void pn_endpoint_close(pn_endpoint_t *endpoint)
+static void pn_endpoint_close(pn_endpoint_t *endpoint)
 {
   // TODO: do we care about the current state?
   PN_SET_LOCAL(endpoint->state, PN_LOCAL_CLOSED);
-  pn_modified(pn_ep_get_connection(endpoint), endpoint, true);
+  pn_connection_t *conn = pn_ep_get_connection(endpoint);
+  pn_event_t *event = pn_collector_put(conn->collector,
+                                       endpoint_event_map[endpoint->type]);
+  if (event) {
+    endpoint_init_event(event, endpoint);
+  }
+  pn_modified(conn, endpoint, true);
 }
 
 void pn_connection_reset(pn_connection_t *connection)
@@ -74,12 +118,14 @@ void pn_connection_reset(pn_connection_t *connection)
 
 void pn_connection_open(pn_connection_t *connection)
 {
-  if (connection) pn_endpoint_open((pn_endpoint_t *) connection);
+  assert(connection);
+  pn_endpoint_open(&connection->endpoint);
 }
 
 void pn_connection_close(pn_connection_t *connection)
 {
-  if (connection) pn_endpoint_close((pn_endpoint_t *) connection);
+  assert(connection);
+  pn_endpoint_close(&connection->endpoint);
 }
 
 void pn_endpoint_tini(pn_endpoint_t *endpoint);
@@ -185,12 +231,14 @@ pn_connection_t *pn_session_connection(pn_session_t *session)
 
 void pn_session_open(pn_session_t *session)
 {
-  if (session) pn_endpoint_open((pn_endpoint_t *) session);
+  assert(session);
+  pn_endpoint_open(&session->endpoint);
 }
 
 void pn_session_close(pn_session_t *session)
 {
-  if (session) pn_endpoint_close((pn_endpoint_t *) session);
+  assert(session);
+  pn_endpoint_close(&session->endpoint);
 }
 
 void pn_session_free(pn_session_t *session)
@@ -234,12 +282,14 @@ void pn_remove_link(pn_session_t *ssn, pn_link_t *link)
 
 void pn_link_open(pn_link_t *link)
 {
-  if (link) pn_endpoint_open((pn_endpoint_t *) link);
+  assert(link);
+  pn_endpoint_open(&link->endpoint);
 }
 
 void pn_link_close(pn_link_t *link)
 {
-  if (link) pn_endpoint_close((pn_endpoint_t *) link);
+  assert(link);
+  pn_endpoint_close(&link->endpoint);
 }
 
 void pn_terminus_free(pn_terminus_t *terminus)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/engine/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/event.c b/proton-c/src/engine/event.c
index 5ea612d..9a3f220 100644
--- a/proton-c/src/engine/event.c
+++ b/proton-c/src/engine/event.c
@@ -242,6 +242,11 @@ pn_event_type_t pn_event_type(pn_event_t *event)
   return event->type;
 }
 
+pn_event_category_t pn_event_category(pn_event_t *event)
+{
+  return (pn_event_category_t)(event->type & 0xFFFF0000);
+}
+
 pn_connection_t *pn_event_connection(pn_event_t *event)
 {
   return event->connection;
@@ -272,12 +277,18 @@ const char *pn_event_type_name(pn_event_type_t type)
   switch (type) {
   case PN_EVENT_NONE:
     return "PN_EVENT_NONE";
-  case PN_CONNECTION_STATE:
-    return "PN_CONNECTION_STATE";
-  case PN_SESSION_STATE:
-    return "PN_SESSION_STATE";
-  case PN_LINK_STATE:
-    return "PN_LINK_STATE";
+  case PN_CONNECTION_REMOTE_STATE:
+    return "PN_CONNECTION_REMOTE_STATE";
+  case PN_CONNECTION_LOCAL_STATE:
+    return "PN_CONNECTION_LOCAL_STATE";
+  case PN_SESSION_REMOTE_STATE:
+    return "PN_SESSION_REMOTE_STATE";
+  case PN_SESSION_LOCAL_STATE:
+    return "PN_SESSION_LOCAL_STATE";
+  case PN_LINK_REMOTE_STATE:
+    return "PN_LINK_REMOTE_STATE";
+  case PN_LINK_LOCAL_STATE:
+    return "PN_LINK_LOCAL_STATE";
   case PN_LINK_FLOW:
     return "PN_LINK_FLOW";
   case PN_DELIVERY:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/libqpid-proton.cmake.in
----------------------------------------------------------------------
diff --git a/proton-c/src/libqpid-proton.cmake.in b/proton-c/src/libqpid-proton.cmake.in
deleted file mode 100644
index b99646a..0000000
--- a/proton-c/src/libqpid-proton.cmake.in
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-# Name: Proton
-# Description: Qpid Proton C library
-# Version: @PN_VERSION@
-# URL: http://qpid.apache.org/proton/
-
-set (PROTON_FOUND         "True")
-set (PROTON_VERSION       @PN_VERSION@)
-set (PROTON_INCLUDE_DIRS  "@INCLUDEDIR@")
-set (PROTON_LIBRARY_DIRS  "@PREFIX@/bin")
-set (PROTON_LIBRARIES     "qpid-proton")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/messenger/messenger.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/messenger.c b/proton-c/src/messenger/messenger.c
index 81853d7..d2cd10c 100644
--- a/proton-c/src/messenger/messenger.c
+++ b/proton-c/src/messenger/messenger.c
@@ -373,7 +373,7 @@ static pn_listener_ctx_t *pn_listener_ctx(pn_messenger_t *messenger,
     return NULL;
   }
 
-  pn_listener_ctx_t *ctx = (pn_listener_ctx_t *) malloc(sizeof(pn_listener_ctx_t));
+  pn_listener_ctx_t *ctx = (pn_listener_ctx_t *) pn_new(sizeof(pn_listener_ctx_t), NULL);
   ctx->messenger = messenger;
   ctx->domain = pn_ssl_domain(PN_SSL_MODE_SERVER);
   if (messenger->certificate) {
@@ -384,7 +384,7 @@ static pn_listener_ctx_t *pn_listener_ctx(pn_messenger_t *messenger,
     if (err) {
       pn_error_format(messenger->error, PN_ERR, "invalid credentials");
       pn_ssl_domain_free(ctx->domain);
-      free(ctx);
+      pn_free(ctx);
       pn_close(messenger->io, socket);
       return NULL;
     }
@@ -423,7 +423,7 @@ static void pn_listener_ctx_free(pn_messenger_t *messenger, pn_listener_ctx_t *c
   free(ctx->host);
   free(ctx->port);
   pn_ssl_domain_free(ctx->domain);
-  free(ctx);
+  pn_free(ctx);
 }
 
 static pn_connection_ctx_t *pn_connection_ctx(pn_messenger_t *messenger,
@@ -1217,13 +1217,16 @@ int pn_messenger_process_events(pn_messenger_t *messenger)
   while ((event = pn_collector_peek(messenger->collector))) {
     processed++;
     switch (pn_event_type(event)) {
-    case PN_CONNECTION_STATE:
+    case PN_CONNECTION_REMOTE_STATE:
+    case PN_CONNECTION_LOCAL_STATE:
       pn_messenger_process_connection(messenger, event);
       break;
-    case PN_SESSION_STATE:
+    case PN_SESSION_REMOTE_STATE:
+    case PN_SESSION_LOCAL_STATE:
       pn_messenger_process_session(messenger, event);
       break;
-    case PN_LINK_STATE:
+    case PN_LINK_REMOTE_STATE:
+    case PN_LINK_LOCAL_STATE:
       pn_messenger_process_link(messenger, event);
       break;
     case PN_LINK_FLOW:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/object/object.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/object.c b/proton-c/src/object/object.c
index 4c2f7d6..dd5fd17 100644
--- a/proton-c/src/object/object.c
+++ b/proton-c/src/object/object.c
@@ -484,17 +484,21 @@ size_t pn_map_size(pn_map_t *map)
   return map->size;
 }
 
+static float pni_map_load(pn_map_t *map)
+{
+  return ((float) map->size) / ((float) map->addressable);
+}
+
 static bool pni_map_ensure(pn_map_t *map, size_t capacity)
 {
-  float load = map->size / map->addressable;
+  float load = pni_map_load(map);
   if (capacity <= map->capacity && load < map->load_factor) {
     return false;
   }
 
   size_t oldcap = map->capacity;
 
-  while (map->capacity < capacity ||
-         (map->size / map->addressable) > map->load_factor) {
+  while (map->capacity < capacity || pni_map_load(map) > map->load_factor) {
     map->capacity *= 2;
     map->addressable = (size_t) (0.86 * map->capacity);
   }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/platform.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform.h b/proton-c/src/platform.h
index a9ae580..6b63e2e 100644
--- a/proton-c/src/platform.h
+++ b/proton-c/src/platform.h
@@ -82,16 +82,12 @@ int64_t pn_i_atoll(const char* num);
 #define vsnprintf pn_i_vsnprintf
 int pn_i_snprintf(char *buf, size_t count, const char *fmt, ...);
 int pn_i_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap);
+#endif
 
-/** Windows va_copy
- *
- * Provide function/macro definition
- */
+#if defined _MSC_VER || defined _OPENVMS
 #define va_copy(d,s) ((d) = (s))
 #endif
 
-
-
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/platform_fmt.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform_fmt.h b/proton-c/src/platform_fmt.h
index 8e62b56..17f95f3 100644
--- a/proton-c/src/platform_fmt.h
+++ b/proton-c/src/platform_fmt.h
@@ -37,6 +37,25 @@
 #define PN_ZI "zi"
 #define PN_ZU "zu"
 
+#ifdef _OPENVMS
+
+#undef PN_ZI
+#undef PN_ZU
+#define PN_ZI "i"
+#define PN_ZU "u"
+#define PRIu64 "llu"
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 "llu"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 "lli"
+
+#endif /* _OPENVMS */
+
 #else
 
 #ifdef _MSC_VER

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/posix/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/io.c b/proton-c/src/posix/io.c
index cac7baf..11379ff 100644
--- a/proton-c/src/posix/io.c
+++ b/proton-c/src/posix/io.c
@@ -119,7 +119,7 @@ static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
   }
 }
 
-static inline int pn_create_socket(void);
+static inline int pn_create_socket(int af);
 
 pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
 {
@@ -130,7 +130,7 @@ pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
     return PN_INVALID_SOCKET;
   }
 
-  pn_socket_t sock = pn_create_socket();
+  pn_socket_t sock = pn_create_socket(addr->ai_family);
   if (sock == PN_INVALID_SOCKET) {
     pn_i_error_from_errno(io->error, "pn_create_socket");
     return PN_INVALID_SOCKET;
@@ -170,7 +170,7 @@ pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port)
     return PN_INVALID_SOCKET;
   }
 
-  pn_socket_t sock = pn_create_socket();
+  pn_socket_t sock = pn_create_socket(addr->ai_family);
   if (sock == PN_INVALID_SOCKET) {
     pn_i_error_from_errno(io->error, "pn_create_socket");
     return PN_INVALID_SOCKET;
@@ -195,7 +195,7 @@ pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port)
 pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size)
 {
   struct sockaddr_in addr = {0};
-  addr.sin_family = AF_INET;
+  addr.sin_family = AF_UNSPEC;
   socklen_t addrlen = sizeof(addr);
   pn_socket_t sock = accept(socket, (struct sockaddr *) &addr, &addrlen);
   if (sock == PN_INVALID_SOCKET) {
@@ -224,18 +224,18 @@ ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t len) {
   return count;
 }
 
-static inline int pn_create_socket(void) {
-  return socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
+static inline int pn_create_socket(int af) {
+  return socket(af, SOCK_STREAM, getprotobyname("tcp")->p_proto);
 }
 #elif defined(SO_NOSIGPIPE)
 ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size) {
-  ssize_t count = return send(socket, buf, len, 0);
+  ssize_t count = send(socket, buf, size, 0);
   io->wouldblock = count < 0 && (errno == EAGAIN || errno == EWOULDBLOCK);
   return count;
 }
 
-static inline int pn_create_socket(void) {
-  int sock = socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
+static inline int pn_create_socket(int af) {
+  int sock = socket(af, SOCK_STREAM, getprotobyname("tcp")->p_proto);
   if (sock == -1) return sock;
 
   int optval = 1;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/proton.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proton.c b/proton-c/src/proton.c
index 35c81f0..9cd44ef 100644
--- a/proton-c/src/proton.c
+++ b/proton-c/src/proton.c
@@ -41,12 +41,23 @@
 #include "platform_fmt.h"
 #include "protocol.h"
 
+void error_exit(const char* fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  exit(1);
+}
+
+
 typedef struct {
   char *buf;
   size_t capacity;
 } heap_buffer;
 
 heap_buffer client_msg, client_data, server_data, server_iresp;
+
 void free_heap_buffers(void) {
   free(client_msg.buf);
   free(client_data.buf);
@@ -309,7 +320,7 @@ void client_callback(pn_connector_t *ctor)
     ctx->init = true;
 
     char container[1024];
-    if (gethostname(container, 1024)) pn_fatal("hostname lookup failed");
+    if (gethostname(container, 1024)) error_exit("hostname lookup failed");
 
     pn_connection_set_container(connection, container);
     pn_connection_set_hostname(connection, ctx->hostname);
@@ -418,7 +429,7 @@ int main(int argc, char **argv)
   {
     switch (opt) {
     case 'c':
-      if (url) pn_fatal("multiple connect urls not allowed\n");
+      if (url) error_exit("multiple connect urls not allowed\n");
       url = optarg;
       break;
     case 'a':
@@ -462,7 +473,7 @@ int main(int argc, char **argv)
       printf("    -h    Print this help.\n");
       exit(EXIT_SUCCESS);
     default: /* '?' */
-      pn_fatal("Usage: %s -h\n", argv[0]);
+      error_exit("Usage: %s -h\n", argv[0]);
     }
   }
 
@@ -484,7 +495,7 @@ int main(int argc, char **argv)
     ctx.hostname = host;
     ctx.address = address;
     pn_connector_t *ctor = pn_connector(drv, host, port, &ctx);
-    if (!ctor) pn_fatal("connector failed\n");
+    if (!ctor) error_exit("connector failed\n");
     pn_connector_set_connection(ctor, pn_connection());
     while (!ctx.done) {
       pn_driver_wait(drv, -1);
@@ -502,7 +513,7 @@ int main(int argc, char **argv)
     }
   } else {
     struct server_context ctx = {0, quiet, size};
-    if (!pn_listener(drv, host, port, &ctx)) pn_fatal("listener failed\n");
+    if (!pn_listener(drv, host, port, &ctx)) error_exit("listener failed\n");
     while (true) {
       pn_driver_wait(drv, -1);
       pn_listener_t *l;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index 12205a8..5815845 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -877,13 +877,13 @@ static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_dat
     // write incoming data to app layer
 
     if (!ssl->app_input_closed) {
-      char *data = ssl->inbuf;
       if (ssl->in_count > 0 || ssl->ssl_closed) {  /* if ssl_closed, send 0 count */
         pn_io_layer_t *io_next = ssl->io_layer->next;
-        ssize_t consumed = io_next->process_input( io_next, data, ssl->in_count);
+        ssize_t consumed = io_next->process_input( io_next, ssl->inbuf, ssl->in_count);
         if (consumed > 0) {
           ssl->in_count -= consumed;
-          data += consumed;
+          if (ssl->in_count)
+            memmove( ssl->inbuf, ssl->inbuf + consumed, ssl->in_count );
           work_pending = true;
           _log( ssl, "Application consumed %d bytes from peer\n", (int) consumed );
         } else if (consumed < 0) {
@@ -906,7 +906,7 @@ static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_dat
               // no max frame limit - grow it.
               char *newbuf = (char *)malloc( max_frame );
               if (newbuf) {
-                ssl->in_size *= max_frame;
+                ssl->in_size = max_frame;
                 memmove( newbuf, ssl->inbuf, ssl->in_count );
                 free( ssl->inbuf );
                 ssl->inbuf = newbuf;
@@ -923,8 +923,6 @@ static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_dat
           }
         }
       }
-      if (ssl->in_count > 0 && data != ssl->inbuf)
-        memmove( ssl->inbuf, data, ssl->in_count );
     }
 
   } while (work_pending);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/CMakeLists.txt b/proton-c/src/tests/CMakeLists.txt
index 2292e78..5825b77 100644
--- a/proton-c/src/tests/CMakeLists.txt
+++ b/proton-c/src/tests/CMakeLists.txt
@@ -19,10 +19,10 @@
 
 add_definitions(${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS})
 
-if (ENABLE_VALGRIND AND VALGRIND)
-  set(memcheck-cmd ${VALGRIND} --error-exitcode=1 --quiet
+if (ENABLE_VALGRIND AND VALGRIND_EXE)
+  set(memcheck-cmd ${VALGRIND_EXE} --error-exitcode=1 --quiet
                    --leak-check=full --trace-children=yes)
-endif (ENABLE_VALGRIND AND VALGRIND)
+endif ()
 
 macro (pn_add_c_test test file)
   add_executable (${test} ${file})

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/tests/parse-url.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/parse-url.c b/proton-c/src/tests/parse-url.c
index 1481590..4489ab2 100644
--- a/proton-c/src/tests/parse-url.c
+++ b/proton-c/src/tests/parse-url.c
@@ -20,11 +20,7 @@
  */
 
 #include <stdarg.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#else
 #include <proton/type_compat.h>
-#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -74,6 +70,19 @@ int main(int argc, char **argv)
   assert(test_url_parse("user:1243^&^:pw@host:423", 0, "user", "1243^&^:pw", "host", "423", 0));
   assert(test_url_parse("user:1243^&^:pw@host:423/Foo.bar:90087", 0, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087"));
   assert(test_url_parse("user:1243^&^:pw@host:423/Foo.bar:90087@somewhere", 0, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087@somewhere"));
+  assert(test_url_parse("[::1]", 0, 0, 0, "::1", 0, 0));
+  assert(test_url_parse("[::1]:amqp", 0, 0, 0, "::1", "amqp", 0));
+  assert(test_url_parse("user@[::1]", 0, "user", 0, "::1", 0, 0));
+  assert(test_url_parse("user@[::1]:amqp", 0, "user", 0, "::1", "amqp", 0));
+  assert(test_url_parse("user:1243^&^:pw@[::1]:amqp", 0, "user", "1243^&^:pw", "::1", "amqp", 0));
+  assert(test_url_parse("user:1243^&^:pw@[::1]:amqp/Foo.bar:90087", 0, "user", "1243^&^:pw", "::1", "amqp", "Foo.bar:90087"));
+  assert(test_url_parse("user:1243^&^:pw@[::1:amqp/Foo.bar:90087", 0, "user", "1243^&^:pw", "[", ":1:amqp", "Foo.bar:90087"));
+  assert(test_url_parse("user:1243^&^:pw@::1]:amqp/Foo.bar:90087", 0, "user", "1243^&^:pw", "", ":1]:amqp", "Foo.bar:90087"));
+  assert(test_url_parse("amqp://user@[::1]", "amqp", "user", 0, "::1", 0, 0));
+  assert(test_url_parse("amqp://user@[::1]:amqp", "amqp", "user", 0, "::1", "amqp", 0));
+  assert(test_url_parse("amqp://user@[1234:52:0:1260:f2de:f1ff:fe59:8f87]:amqp", "amqp", "user", 0, "1234:52:0:1260:f2de:f1ff:fe59:8f87", "amqp", 0));
+  assert(test_url_parse("amqp://user:1243^&^:pw@[::1]:amqp", "amqp", "user", "1243^&^:pw", "::1", "amqp", 0));
+  assert(test_url_parse("amqp://user:1243^&^:pw@[::1]:amqp/Foo.bar:90087", "amqp", "user", "1243^&^:pw", "::1", "amqp", "Foo.bar:90087"));
   assert(test_url_parse("amqp://host", "amqp", 0, 0, "host", 0, 0));
   assert(test_url_parse("amqp://user@host", "amqp", "user", 0, "host", 0, 0));
   assert(test_url_parse("amqp://user@host/path:%", "amqp", "user", 0, "host", 0, "path:%"));
@@ -82,5 +91,10 @@ int main(int argc, char **argv)
   assert(test_url_parse("amqp://bigbird@host/queue@host", "amqp", "bigbird", 0, "host", 0, "queue@host"));
   assert(test_url_parse("amqp://host/queue@host", "amqp", 0, 0, "host", 0, "queue@host"));
   assert(test_url_parse("amqp://host:9765/queue@host", "amqp", 0, 0, "host", "9765", "queue@host"));
+  assert(test_url_parse("user:pass%2fword@host", 0, "user", "pass/word", "host", 0, 0));
+  assert(test_url_parse("user:pass%2Fword@host", 0, "user", "pass/word", "host", 0, 0));
+  assert(test_url_parse("us%2fer:password@host", 0, "us/er", "password", "host", 0, 0));
+  assert(test_url_parse("us%2Fer:password@host", 0, "us/er", "password", "host", 0, 0));
+  assert(test_url_parse("user:pass%2fword%@host", 0, "user", "pass/word%", "host", 0, 0));
   return 0;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
index e0bef84..e5b4a31 100644
--- a/proton-c/src/transport/transport.c
+++ b/proton-c/src/transport/transport.c
@@ -284,7 +284,8 @@ int pn_transport_bind(pn_transport_t *transport, pn_connection_t *connection)
   pn_incref(connection);
   if (transport->open_rcvd) {
     PN_SET_REMOTE(connection->endpoint.state, PN_REMOTE_ACTIVE);
-    pn_event_t *event = pn_collector_put(connection->collector, PN_CONNECTION_STATE);
+    pn_event_t *event = pn_collector_put(connection->collector,
+                                         PN_CONNECTION_REMOTE_STATE);
     if (event) {
       pn_event_init_connection(event, connection);
     }
@@ -474,7 +475,8 @@ int pn_do_open(pn_dispatcher_t *disp)
   if (conn) {
     PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_ACTIVE);
 
-    pn_event_t *event = pn_collector_put(conn->collector, PN_CONNECTION_STATE);
+    pn_event_t *event = pn_collector_put(conn->collector,
+                                         PN_CONNECTION_REMOTE_STATE);
     if (event) {
       pn_event_init_connection(event, conn);
     }
@@ -507,7 +509,8 @@ int pn_do_begin(pn_dispatcher_t *disp)
   pn_map_channel(transport, disp->channel, ssn);
   PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_ACTIVE);
 
-  pn_event_t *event = pn_collector_put(transport->connection->collector, PN_SESSION_STATE);
+  pn_event_t *event = pn_collector_put(transport->connection->collector,
+                                       PN_SESSION_REMOTE_STATE);
   if (event) {
     pn_event_init_session(event, ssn);
   }
@@ -681,7 +684,8 @@ int pn_do_attach(pn_dispatcher_t *disp)
     link->state.delivery_count = idc;
   }
 
-  pn_event_t *event = pn_collector_put(transport->connection->collector, PN_LINK_STATE);
+  pn_event_t *event = pn_collector_put(transport->connection->collector,
+                                       PN_LINK_REMOTE_STATE);
   if (event) {
     pn_event_init_link(event, link);
   }
@@ -951,7 +955,8 @@ int pn_do_detach(pn_dispatcher_t *disp)
   if (closed)
   {
     PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_CLOSED);
-    pn_event_t *event = pn_collector_put(transport->connection->collector, PN_LINK_STATE);
+    pn_event_t *event = pn_collector_put(transport->connection->collector,
+                                         PN_LINK_REMOTE_STATE);
     if (event) {
       pn_event_init_link(event, link);
     }
@@ -970,7 +975,8 @@ int pn_do_end(pn_dispatcher_t *disp)
   int err = pn_scan_error(disp->args, &ssn->endpoint.remote_condition, SCAN_ERROR_DEFAULT);
   if (err) return err;
   PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_CLOSED);
-  pn_event_t *event = pn_collector_put(transport->connection->collector, PN_SESSION_STATE);
+  pn_event_t *event = pn_collector_put(transport->connection->collector,
+                                       PN_SESSION_REMOTE_STATE);
   if (event) {
     pn_event_init_session(event, ssn);
   }
@@ -986,7 +992,8 @@ int pn_do_close(pn_dispatcher_t *disp)
   if (err) return err;
   transport->close_rcvd = true;
   PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_CLOSED);
-  pn_event_t *event = pn_collector_put(transport->connection->collector, PN_CONNECTION_STATE);
+  pn_event_t *event = pn_collector_put(transport->connection->collector,
+                                       PN_CONNECTION_REMOTE_STATE);
   if (event) {
     pn_event_init_connection(event, conn);
   }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-c/src/util.c
----------------------------------------------------------------------
diff --git a/proton-c/src/util.c b/proton-c/src/util.c
index 6ac7b51..e6b9af0 100644
--- a/proton-c/src/util.c
+++ b/proton-c/src/util.c
@@ -23,12 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
-#ifndef __cplusplus
-#include <stdint.h>
-#include <stdbool.h>
-#else
 #include <proton/type_compat.h>
-#endif
 #include <ctype.h>
 #include <string.h>
 #include <proton/error.h>
@@ -106,6 +101,42 @@ void pn_print_data(const char *bytes, size_t size)
   pn_fprint_data(stdout, bytes, size);
 }
 
+void pni_urldecode(const char *src, char *dst)
+{
+  const char *in = src;
+  char *out = dst;
+  while (*in != '\0')
+  {
+    if ('%' == *in)
+    {
+      if ((in[1] != '\0') && (in[2] != '\0'))
+      {
+        char esc[3];
+        esc[0] = in[1];
+        esc[1] = in[2];
+        esc[2] = '\0';
+        unsigned long d = strtoul(esc, NULL, 16);
+        *out = (char)d;
+        in += 3;
+        out++;
+      }
+      else
+      {
+        *out = *in;
+        in++;
+        out++;
+      }
+    }
+    else
+    {
+      *out = *in;
+      in++;
+      out++;
+    }
+  }
+  *out = '\0';
+}
+
 // Parse URL syntax:
 // [ <scheme> :// ] [ <user> [ : <password> ] @ ] <host> [ : <port> ] [ / <path> ]
 // <user>, <password>, <host>, <port> cannot contain any of '@', ':', '/'
@@ -141,13 +172,24 @@ void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **ho
   }
 
   *host = url;
+  char *open = (*url == '[') ? url : 0;
+  if (open) {
+    char *close = strchr(open, ']');
+    if (close) {
+        *host = open + 1;
+        *close = '\0';
+        url = close + 1;
+    }
+  }
 
-  char *colon = strchr(*host, ':');
+  char *colon = strchr(url, ':');
   if (colon) {
     *colon = '\0';
     *port = colon + 1;
   }
 
+  if (*user) pni_urldecode(*user, *user);
+  if (*pass) pni_urldecode(*pass, *pass);
 }
 
 void pn_vfatal(const char *fmt, va_list ap)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-j/CMakeLists.txt b/proton-j/CMakeLists.txt
index 5e70457..d614196 100644
--- a/proton-j/CMakeLists.txt
+++ b/proton-j/CMakeLists.txt
@@ -17,8 +17,12 @@
 # under the License.
 #
 
+include(UseJava)
+include(ProtonUseJava)
 set(CMAKE_JAVA_TARGET_VERSION ${PN_VERSION})
 file(GLOB_RECURSE SOURCES_ABS "src/main/java/*.java")
 add_jar(proton-j ${SOURCES_ABS})
 rebuild_jar(proton-j proton-j-${PN_VERSION}.jar)
+set (JAVA_INSTALL_DIR ${SHARE_INSTALL_DIR}/java CACHE PATH "Installation directory for all JARs except those using JNI")
+mark_as_advanced (JAVA_INSTALL_DIR)
 install_jar(proton-j ${JAVA_INSTALL_DIR})

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
index a995926..14c0dc7 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Event.java
@@ -28,16 +28,38 @@ package org.apache.qpid.proton.engine;
 
 public interface Event
 {
+    public enum Category {
+        PROTOCOL;
+    }
 
     public enum Type {
-        CONNECTION_STATE,
-        SESSION_STATE,
-        LINK_STATE,
-        LINK_FLOW,
-        DELIVERY,
-        TRANSPORT
+        CONNECTION_REMOTE_STATE(Category.PROTOCOL, 1),
+        CONNECTION_LOCAL_STATE(Category.PROTOCOL, 2),
+        SESSION_REMOTE_STATE(Category.PROTOCOL, 3),
+        SESSION_LOCAL_STATE(Category.PROTOCOL, 4),
+        LINK_REMOTE_STATE(Category.PROTOCOL, 5),
+        LINK_LOCAL_STATE(Category.PROTOCOL, 6),
+        LINK_FLOW(Category.PROTOCOL, 7),
+        DELIVERY(Category.PROTOCOL, 8),
+        TRANSPORT(Category.PROTOCOL, 9);
+
+        private int _opcode;
+        private Category _category;
+
+        private Type(Category c, int o)
+        {
+            this._category = c;
+            this._opcode = o;
+        }
+
+        public Category getCategory()
+        {
+            return this._category;
+        }
     }
 
+    Category getCategory();
+
     Type getType();
 
     Connection getConnection();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
index 7401e5b..6a27103 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
@@ -31,7 +31,7 @@ import org.apache.qpid.proton.amqp.transport.Open;
 
 public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
 {
-    public static final int MAX_CHANNELS = 255;
+    public static final int MAX_CHANNELS = 65535;
 
     private List<SessionImpl> _sessions = new ArrayList<SessionImpl>();
     private EndpointImpl _transportTail;
@@ -201,7 +201,7 @@ public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
         setRemoteDesiredCapabilities(open.getDesiredCapabilities());
         setRemoteOfferedCapabilities(open.getOfferedCapabilities());
         setRemoteProperties(open.getProperties());
-        EventImpl ev = put(Event.Type.CONNECTION_STATE);
+        EventImpl ev = put(Event.Type.CONNECTION_REMOTE_STATE);
         if (ev != null) {
             ev.init(this);
         }
@@ -582,4 +582,12 @@ public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
         }
     }
 
+    @Override
+    protected void localStateChanged()
+    {
+        EventImpl ev = put(Event.Type.CONNECTION_LOCAL_STATE);
+        if (ev != null) {
+            ev.init(this);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
index 0d52e8f..72ae1a6 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
@@ -37,6 +37,8 @@ public abstract class EndpointImpl implements ProtonJEndpoint
     private EndpointImpl _transportPrev;
     private Object _context;
 
+    protected abstract void localStateChanged();
+
     public void open()
     {
         switch(_localState)
@@ -47,6 +49,7 @@ public abstract class EndpointImpl implements ProtonJEndpoint
                 // TODO
             case UNINITIALIZED:
                 _localState = EndpointState.ACTIVE;
+                localStateChanged();
         }
         modified();
     }
@@ -62,6 +65,7 @@ public abstract class EndpointImpl implements ProtonJEndpoint
                 // TODO
             case ACTIVE:
                 _localState = EndpointState.CLOSED;
+                localStateChanged();
         }
         modified();
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
index 2049cf8..7d57909 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/EventImpl.java
@@ -47,6 +47,11 @@ class EventImpl implements Event
         this.type = type;
     }
 
+    public Category getCategory()
+    {
+        return type.getCategory();
+    }
+
     public Type getType()
     {
         return type;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java
index 58ae67b..a83f888 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/FrameParser.java
@@ -338,7 +338,7 @@ class FrameParser implements TransportInput
                     // type
 
                     int type = in.get() & 0xFF;
-                    int channel = in.getShort() & 0xFF;
+                    int channel = in.getShort() & 0xFFFF;
 
                     if(type != 0)
                     {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33c895ec/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
index 0159c41..dda2171 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
@@ -27,6 +27,7 @@ import org.apache.qpid.proton.engine.EndpointState;
 import org.apache.qpid.proton.engine.Link;
 import org.apache.qpid.proton.amqp.transport.Source;
 import org.apache.qpid.proton.amqp.transport.Target;
+import org.apache.qpid.proton.engine.Event;
 
 public abstract class LinkImpl extends EndpointImpl implements Link
 {
@@ -373,4 +374,12 @@ public abstract class LinkImpl extends EndpointImpl implements Link
         return _head;
     }
 
+    @Override
+    protected void localStateChanged()
+    {
+        EventImpl ev = getConnectionImpl().put(Event.Type.LINK_LOCAL_STATE);
+        if (ev != null) {
+            ev.init(this);
+        }
+    }
 }


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


[14/51] [abbrv] qpid-proton git commit: JavaScript binding now pretty much in a releasable state. Needs a little bit of tidying up, a few more tests and examples, but it now has a more or less complete implementation of qpid-config to test interoperabili

Posted by rh...@apache.org.
JavaScript binding now pretty much in a releasable state. Needs a little bit of tidying up, a few more tests and examples, but it now has a more or less complete implementation of qpid-config to test interoperability with C++ Maps and Lists. Proton-c compiles cleanly now using emscripten as I have made all the necessary changes to emscripten itself, so all the Proton JavaScript code is what might be considered a wrapper around proton-c, it is very similar indeed to the Python binding. Needs some performance tests added and profiling, but it functionally covers pretty much all of Messenger, Message and Codec

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1616550 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/a61e5f9c
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/a61e5f9c
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/a61e5f9c

Branch: refs/heads/master
Commit: a61e5f9c35b530097b808f27424781271495e9f9
Parents: 6aed854
Author: fadams <fa...@unknown>
Authored: Thu Aug 7 17:20:37 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Thu Aug 7 17:20:37 2014 +0000

----------------------------------------------------------------------
 examples/messenger/c/recv-async.c            |  246 ++--
 examples/messenger/c/send-async.c            |  183 ++-
 examples/messenger/javascript/client.js      |  102 ++
 examples/messenger/javascript/drain.js       |   58 +-
 examples/messenger/javascript/proxy.js       |  100 ++
 examples/messenger/javascript/qpid-config.js | 1375 +++++++++++++++++++++
 examples/messenger/javascript/recv.js        |   67 +
 examples/messenger/javascript/send.js        |   92 ++
 examples/messenger/javascript/server.js      |   79 ++
 examples/messenger/javascript/spout.js       |  144 ++-
 examples/messenger/javascript/ws2tcp.js      |  162 +++
 proton-c/bindings/javascript/CMakeLists.txt  |   22 +-
 proton-c/bindings/javascript/TODO            |   24 +-
 proton-c/bindings/javascript/binding.c       |   78 +-
 proton-c/bindings/javascript/binding.js      | 1067 ++++++++++++++--
 proton-c/bindings/javascript/my-library.js   |   68 +-
 tests/javascript/codec.js                    |    2 +-
 tests/javascript/message.js                  |  301 +++++
 18 files changed, 3619 insertions(+), 551 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/c/recv-async.c
----------------------------------------------------------------------
diff --git a/examples/messenger/c/recv-async.c b/examples/messenger/c/recv-async.c
index cb50635..1f49166 100644
--- a/examples/messenger/c/recv-async.c
+++ b/examples/messenger/c/recv-async.c
@@ -18,6 +18,8 @@
  *
  */
 
+// This is a re-implementation of recv.c using non-blocking/asynchronous calls.
+
 #include "proton/message.h"
 #include "proton/messenger.h"
 
@@ -28,9 +30,11 @@
 
 #if EMSCRIPTEN
 #include <emscripten.h>
-void emscripten_set_network_callback(void (*func)());
 #endif
 
+pn_message_t * message;
+pn_messenger_t * messenger;
+
 #define check(messenger)                                                     \
   {                                                                          \
     if(pn_messenger_errno(messenger))                                        \
@@ -39,171 +43,151 @@ void emscripten_set_network_callback(void (*func)());
     }                                                                        \
   }                                                                          \
 
-// FA Temporarily make these global
-  pn_message_t * message;
-  pn_messenger_t * messenger;
-
 void die(const char *file, int line, const char *message)
 {
-  fprintf(stderr, "%s:%i: %s\n", file, line, message);
-  exit(1);
+    fprintf(stderr, "%s:%i: %s\n", file, line, message);
+    exit(1);
 }
 
 void usage(void)
 {
-  printf("Usage: recv [options] <addr>\n");
-  printf("-c    \tPath to the certificate file.\n");
-  printf("-k    \tPath to the private key file.\n");
-  printf("-p    \tPassword for the private key.\n");
-  printf("<addr>\tAn address.\n");
-  exit(0);
+    printf("Usage: recv [options] <addr>\n");
+    printf("-c    \tPath to the certificate file.\n");
+    printf("-k    \tPath to the private key file.\n");
+    printf("-p    \tPassword for the private key.\n");
+    printf("<addr>\tAn address.\n");
+    exit(0);
 }
 
 void process(void) {
-//printf("                          *** process ***\n");
-
-    // Process incoming messages
-
     while(pn_messenger_incoming(messenger))
     {
-printf("in while loop\n");
-
-      pn_messenger_get(messenger, message);
-      check(messenger);
-      pn_tracker_t tracker = pn_messenger_incoming_tracker(messenger);
-printf("tracker = %ld:%ld\n", (long)(tracker >> 32), (long)tracker);
-
-      char buffer[1024];
-      size_t buffsize = sizeof(buffer);
-      pn_data_t *body = pn_message_body(message);
-      pn_data_format(body, buffer, &buffsize);
-
-      printf("Address: %s\n", pn_message_get_address(message));
-      const char* subject = pn_message_get_subject(message);
-      printf("Subject: %s\n", subject ? subject : "(no subject)");
-      printf("Content: %s\n", buffer);
-
-
-
-      int err = pn_messenger_accept(messenger, tracker, 0);
-printf("err = %d\n\n", err);
+        pn_messenger_get(messenger, message);
+        check(messenger);
+
+        {
+        pn_tracker_t tracker = pn_messenger_incoming_tracker(messenger);
+        char buffer[1024];
+        size_t buffsize = sizeof(buffer);
+        const char* subject = pn_message_get_subject(message);
+        pn_data_t* body = pn_message_body(message);
+        pn_data_format(body, buffer, &buffsize);
+
+        printf("Address: %s\n", pn_message_get_address(message));
+        printf("Subject: %s\n", subject ? subject : "(no subject)");
+        printf("Content: %s\n", buffer);
+
+        pn_messenger_accept(messenger, tracker, 0);
+        }
     }
 }
 
-// Callback used by emscripten to ensure pn_messenger_work gets called.
-void work(void) {
-//printf("                          *** work ***\n");
-
-    int err = pn_messenger_work(messenger, 0);
-printf("err = %d\n", err);
-
-    if (err >= 0) {
+#if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler.
+void pump(int fd, void* userData) {
+    while (pn_messenger_work(messenger, 0) >= 0) {
         process();
     }
+}
 
-    err = pn_messenger_work(messenger, 0);
-printf("err = %d\n", err);
+void onclose(int fd, void* userData) {
+    process();
+}
 
-    if (err >= 0) {
-        process();
-    }
+void onerror(int fd, int errno, const char* msg, void* userData) {
+    printf("error callback fd = %d, errno = %d, msg = %s\n", fd, errno, msg);
 }
+#endif
 
 int main(int argc, char** argv)
 {
-  char* certificate = NULL;
-  char* privatekey = NULL;
-  char* password = NULL;
-  char* address = (char *) "amqp://~0.0.0.0";
-  int c;
-  opterr = 0;
-
-  while((c = getopt(argc, argv, "hc:k:p:")) != -1)
-  {
-    switch(c)
-    {
-    case 'h':
-      usage();
-      break;
-
-    case 'c': certificate = optarg; break;
-    case 'k': privatekey = optarg; break;
-    case 'p': password = optarg; break;
-
-    case '?':
-      if(optopt == 'c' ||
-         optopt == 'k' ||
-         optopt == 'p')
-      {
-        fprintf(stderr, "Option -%c requires an argument.\n", optopt);
-      }
-      else if(isprint(optopt))
-      {
-        fprintf(stderr, "Unknown option `-%c'.\n", optopt);
-      }
-      else
-      {
-        fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
-      }
-      return 1;
-    default:
-      abort();
-    }
-  }
-
-  if (optind < argc)
-  {
-    address = argv[optind];
-  }
-
-//  pn_message_t * message;
-//  pn_messenger_t * messenger;
-
-  message = pn_message();
-  messenger = pn_messenger(NULL);
-pn_messenger_set_blocking(messenger, false); // FA Addition.
-
+    char* certificate = NULL;
+    char* privatekey = NULL;
+    char* password = NULL;
+    char* address = (char *) "amqp://~0.0.0.0";
+    int c;
 
+    message = pn_message();
+    messenger = pn_messenger(NULL);
+    pn_messenger_set_blocking(messenger, false); // Needs to be set non-blocking to behave asynchronously.
 
-//pn_messenger_set_incoming_window(messenger, 1024); // FA Addition.
+    opterr = 0;
 
+    while((c = getopt(argc, argv, "hc:k:p:")) != -1)
+    {
+        switch(c)
+        {
+            case 'h':
+                usage();
+                break;
+
+            case 'c': certificate = optarg; break;
+            case 'k': privatekey = optarg; break;
+            case 'p': password = optarg; break;
+
+            case '?':
+                if (optopt == 'c' ||
+                    optopt == 'k' ||
+                    optopt == 'p')
+                {
+                    fprintf(stderr, "Option -%c requires an argument.\n", optopt);
+                }
+                else if(isprint(optopt))
+                {
+                    fprintf(stderr, "Unknown option `-%c'.\n", optopt);
+                }
+                else
+                {
+                    fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
+                }
+                return 1;
+            default:
+                abort();
+        }
+    }
 
+    if (optind < argc)
+    {
+        address = argv[optind];
+    }
 
-  /* load the various command line options if they're set */
-  if(certificate)
-  {
-    pn_messenger_set_certificate(messenger, certificate);
-  }
+    /* load the various command line options if they're set */
+    if(certificate)
+    {
+        pn_messenger_set_certificate(messenger, certificate);
+    }
 
-  if(privatekey)
-  {
-    pn_messenger_set_private_key(messenger, privatekey);
-  }
+    if(privatekey)
+    {
+        pn_messenger_set_private_key(messenger, privatekey);
+    }
 
-  if(password)
-  {
-    pn_messenger_set_password(messenger, password);
-  }
+    if(password)
+    {
+        pn_messenger_set_password(messenger, password);
+    }
 
-  pn_messenger_start(messenger);
-  check(messenger);
+    pn_messenger_start(messenger);
+    check(messenger);
 
-  pn_messenger_subscribe(messenger, address);
-  check(messenger);
+    pn_messenger_subscribe(messenger, address);
+    check(messenger);
 
-  pn_messenger_recv(messenger, -1); // Receive as many messages as messenger can buffer
+    pn_messenger_recv(messenger, -1); // Set to receive as many messages as messenger can buffer.
 
-#if EMSCRIPTEN
-  //emscripten_set_main_loop(work, 0, 0);
+#if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler.
+    emscripten_set_socket_error_callback(NULL, onerror);
 
-  emscripten_set_network_callback(work);
-#else
-  while (1) {
-    pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
-    process();
-  }
+    emscripten_set_socket_open_callback(NULL, pump);
+    emscripten_set_socket_connection_callback(NULL, pump);
+    emscripten_set_socket_message_callback(NULL, pump);
+    emscripten_set_socket_close_callback(NULL, onclose);
+#else // For native compiler.
+    while (1) {
+        pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
+        process();
+    }
 #endif
 
-  return 0;
+    return 0;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/c/send-async.c
----------------------------------------------------------------------
diff --git a/examples/messenger/c/send-async.c b/examples/messenger/c/send-async.c
index f8437c4..2c76e6c 100644
--- a/examples/messenger/c/send-async.c
+++ b/examples/messenger/c/send-async.c
@@ -18,6 +18,8 @@
  *
  */
 
+// This is a re-implementation of send.c using non-blocking/asynchronous calls.
+
 #include "proton/message.h"
 #include "proton/messenger.h"
 #include "proton/driver.h"
@@ -30,9 +32,13 @@
 
 #if EMSCRIPTEN
 #include <emscripten.h>
-void emscripten_set_network_callback(void (*func)());
 #endif
 
+pn_message_t * message;
+pn_messenger_t * messenger;
+pn_tracker_t tracker;
+int running = 1;
+
 #define check(messenger)                                                     \
   {                                                                          \
     if(pn_messenger_errno(messenger))                                        \
@@ -41,152 +47,121 @@ void emscripten_set_network_callback(void (*func)());
     }                                                                        \
   }                                                                          \
 
-// FA Temporarily make global
-  pn_message_t * message;
-  pn_messenger_t * messenger;
-
-pn_tracker_t tracker;
-int tracked = 1;
-
-int running = 1;
-
-
 void die(const char *file, int line, const char *message)
 {
-  fprintf(stderr, "%s:%i: %s\n", file, line, message);
-  exit(1);
+    fprintf(stderr, "%s:%i: %s\n", file, line, message);
+    exit(1);
 }
 
 void usage(void)
 {
-  printf("Usage: send [-a addr] [message]\n");
-  printf("-a     \tThe target address [amqp[s]://domain[/name]]\n");
-  printf("message\tA text string to send.\n");
-  exit(0);
+    printf("Usage: send [-a addr] [message]\n");
+    printf("-a     \tThe target address [amqp[s]://domain[/name]]\n");
+    printf("message\tA text string to send.\n");
+    exit(0);
 }
 
 void process(void) {
-//printf("                          *** process ***\n");
-
-    // Process outgoing messages
-
     pn_status_t status = pn_messenger_status(messenger, tracker);
-//printf("status = %d\n", status);
-
     if (status != PN_STATUS_PENDING) {
-printf("status = %d\n", status);
-
-        //pn_messenger_settle(messenger, tracker, 0);
-        //tracked--;
-
         if (running) {
-printf("stopping\n");
             pn_messenger_stop(messenger);
             running = 0;
         } 
     }
 
     if (pn_messenger_stopped(messenger)) {
-printf("exiting\n");
         pn_message_free(message);
         pn_messenger_free(messenger);
-        exit(0);
     }
 }
 
-
-
-// Callback used by emscripten to ensure pn_messenger_work gets called.
-void work(void) {
-//printf("                          *** work ***\n");
-
-    int err = pn_messenger_work(messenger, 0);
-printf("err = %d\n", err);
-
-    if (err >= 0) {
+#if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler.
+void pump(int fd, void* userData) {
+    while (pn_messenger_work(messenger, 0) >= 0) {
         process();
     }
+}
 
-    err = pn_messenger_work(messenger, 0);
-printf("err = %d\n", err);
+void onclose(int fd, void* userData) {
+    process();
+}
 
-    if (err >= 0) {
-        process();
-    }
+void onerror(int fd, int errno, const char* msg, void* userData) {
+    printf("error callback fd = %d, errno = %d, msg = %s\n", fd, errno, msg);
 }
+#endif
 
 int main(int argc, char** argv)
 {
-  int c;
-  opterr = 0;
-  char * address = (char *) "amqp://0.0.0.0";
-  char * msgtext = (char *) "Hello World!";
-
-  while((c = getopt(argc, argv, "ha:b:c:")) != -1)
-  {
-    switch(c)
+    int c;
+    opterr = 0;
+    char * address = (char *) "amqp://0.0.0.0";
+    char * msgtext = (char *) "Hello World!";
+
+    while((c = getopt(argc, argv, "ha:b:c:")) != -1)
     {
-    case 'a': address = optarg; break;
-    case 'h': usage(); break;
-
-    case '?':
-      if(optopt == 'a')
-      {
-        fprintf(stderr, "Option -%c requires an argument.\n", optopt);
-      }
-      else if(isprint(optopt))
-      {
-        fprintf(stderr, "Unknown option `-%c'.\n", optopt);
-      }
-      else
-      {
-        fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
-      }
-      return 1;
-    default:
-      abort();
+        switch(c)
+        {
+            case 'a': address = optarg; break;
+            case 'h': usage(); break;
+
+            case '?':
+                if(optopt == 'a')
+                {
+                    fprintf(stderr, "Option -%c requires an argument.\n", optopt);
+                }
+                else if(isprint(optopt))
+                {
+                    fprintf(stderr, "Unknown option `-%c'.\n", optopt);
+                }
+                else
+                {
+                    fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
+                }
+                return 1;
+            default:
+                abort();
+        }
     }
-  }
-
-  if (optind < argc) msgtext = argv[optind];
-
-//  pn_message_t * message;
-//  pn_messenger_t * messenger;
-
-  message = pn_message();
-  messenger = pn_messenger(NULL);
-  pn_messenger_set_blocking(messenger, false); // Put messenger into non-blocking mode.
 
+    if (optind < argc) msgtext = argv[optind];
 
-  pn_messenger_set_outgoing_window(messenger, 1024); // FA Addition.
+    message = pn_message();
+    messenger = pn_messenger(NULL);
+    pn_messenger_set_blocking(messenger, false); // Needs to be set non-blocking to behave asynchronously.
+    pn_messenger_set_outgoing_window(messenger, 1024); 
 
+    pn_messenger_start(messenger);
 
+    pn_message_set_address(message, address);
+    pn_data_t* body = pn_message_body(message);
+    pn_data_put_string(body, pn_bytes(strlen(msgtext), msgtext));
 
+    pn_messenger_put(messenger, message);
+    check(messenger);
 
-  pn_messenger_start(messenger);
+    tracker = pn_messenger_outgoing_tracker(messenger);
 
-  pn_message_set_address(message, address);
-  pn_data_t *body = pn_message_body(message);
-  pn_data_put_string(body, pn_bytes(strlen(msgtext), msgtext));
+#if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler.
+    emscripten_set_socket_error_callback(NULL, onerror);
 
-  pn_messenger_put(messenger, message);
-  check(messenger);
-
-  tracker = pn_messenger_outgoing_tracker(messenger);
-//printf("tracker = %lld\n", (long long int)tracker);
-
-
-#if EMSCRIPTEN
-  //emscripten_set_main_loop(work, 0, 0);
+    emscripten_set_socket_open_callback(NULL, pump);
+    emscripten_set_socket_connection_callback(NULL, pump);
+    emscripten_set_socket_message_callback(NULL, pump);
+    emscripten_set_socket_close_callback(NULL, onclose);
+#else // For native compiler.
+    while (running) {
+        pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
+        process();
+    }
 
-  emscripten_set_network_callback(work);
-#else
-  while (1) {
-    pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
-    process();
-  }
+    while (!pn_messenger_stopped(messenger)) {
+        pn_messenger_work(messenger, 0);
+        process();
+    }
 #endif
 
-  return 0;
+    return 0;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/javascript/client.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/client.js b/examples/messenger/javascript/client.js
new file mode 100644
index 0000000..c9419a2
--- /dev/null
+++ b/examples/messenger/javascript/client.js
@@ -0,0 +1,102 @@
+#!/usr/bin/env node
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Simple client for use with server.js illustrating request/response
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("qpid-proton");
+}
+
+var address = "amqp://0.0.0.0";
+var subject = "UK.WEATHER";
+var replyTo = "~/replies";
+var msgtext = "Hello World!";
+var tracker = null;
+var running = true;
+
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+
+var pumpData = function() {
+    while (messenger.incoming()) {
+        var t = messenger.get(message);
+
+        console.log("Reply");
+        console.log("Address: " + message.getAddress());
+        console.log("Subject: " + message.getSubject());
+
+        // body is the body as a native JavaScript Object, useful for most real cases.
+        //console.log("Content: " + message.body);
+
+        // data is the body as a proton.Data Object, used in this case because
+        // format() returns exactly the same representation as recv.c
+        console.log("Content: " + message.data.format());
+
+        messenger.accept(t);
+        messenger.stop();
+    }
+
+    if (messenger.isStopped()) {
+        message.free();
+        messenger.free();
+    }
+};
+
+var args = process.argv.slice(2);
+if (args.length > 0) {
+    if (args[0] === '-h' || args[0] === '--help') {
+        console.log("Usage: node client.js [-r replyTo] [-s subject] <addr> (default " + address + ")");
+        console.log("Options:");
+        console.log("  -r <reply to> The message replyTo (default " + replyTo + ")");
+        console.log("  -s <subject> The message subject (default " + subject + ")");
+        process.exit(0);
+    }
+
+    for (var i = 0; i < args.length; i++) {
+        var arg = args[i];
+        if (arg.charAt(0) === '-') {
+            i++;
+            var val = args[i];
+            if (arg === '-r') {
+                replyTo = val;
+            } else if (arg === '-s') {
+                subject = val;
+            }
+        } else {
+            address = arg;
+        }
+    }
+}
+
+messenger.on('error', function(error) {console.log(error);});
+messenger.on('work', pumpData);
+messenger.setOutgoingWindow(1024);
+messenger.start();
+
+message.setAddress(address);
+message.setSubject(subject);
+message.setReplyTo(replyTo);
+message.body = msgtext;
+
+tracker = messenger.put(message);
+messenger.recv(); // Receive as many messages as messenger can buffer.
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/javascript/drain.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/drain.js b/examples/messenger/javascript/drain.js
index eacd8a2..923e29a 100644
--- a/examples/messenger/javascript/drain.js
+++ b/examples/messenger/javascript/drain.js
@@ -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
@@ -23,40 +24,45 @@ if (typeof exports !== "undefined" && exports !== null) {
     proton = require("qpid-proton");
 }
 
-try {
-    var address = "amqp://~0.0.0.0";
-    var message = new proton.Message();
-    var messenger = new proton.Messenger();
+console.log("drain not implemented yet");
+process.exit(0);
 
-    function _process() {
-//        console.log("                          *** process ***");
+var address = "amqp://~0.0.0.0";
+var message = new proton.Message();
+var messenger = new proton.Messenger();
 
-        // Process incoming messages
+var pumpData = function() {
+    while (messenger.incoming()) {
+        var t = messenger.get(message);
 
-        while (messenger.incoming()) {
-console.log("in while loop\n");
+        console.log("Address: " + message.getAddress());
+        console.log("Subject: " + message.getSubject());
 
-            var tracker = messenger.get(message);
-console.log("tracker = " + tracker);
+        // body is the body as a native JavaScript Object, useful for most real cases.
+        //console.log("Content: " + message.body);
 
-            console.log("Address: " + message.getAddress());
-            console.log("Subject: " + message.getSubject());
-            console.log("Content: " + message.body);
+        // data is the body as a proton.Data Object, used in this case because
+        // format() returns exactly the same representation as recv.c
+        console.log("Content: " + message.data.format());
 
-            messenger.accept(tracker);
-        }
-    };
+        messenger.accept(t);
+    }
+};
 
-    //messenger.setIncomingWindow(1024);
+var args = process.argv.slice(2);
+if (args.length > 0) {
+    if (args[0] === '-h' || args[0] === '--help') {
+        console.log("Usage: recv <addr> (default " + address + ").");
+        process.exit(0);
+    }
 
-    messenger.setNetworkCallback(_process);
-    messenger.start();
-
-    messenger.subscribe(address);
-    messenger.recv(); // Receive as many messages as messenger can buffer.
-
-} catch(e) {
-    console.log("Caught Exception " + e);
+    address = args[0];
 }
 
+messenger.on('error', function(error) {console.log(error);});
+messenger.on('work', pumpData);
+messenger.start();
+
+messenger.subscribe(address);
+messenger.recv(); // Receive as many messages as messenger can buffer.
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/javascript/proxy.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/proxy.js b/examples/messenger/javascript/proxy.js
new file mode 100755
index 0000000..bd1c208
--- /dev/null
+++ b/examples/messenger/javascript/proxy.js
@@ -0,0 +1,100 @@
+#!/usr/bin/env node
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * proxy.js is a simple node.js command line application that uses the ws2tcp.js
+ * library to proxy from a WebSocket to a TCP Socket or vice versa.
+ * <p>
+ * Usage: node proxy.js [options]
+ * Options:");
+ *  -p <listen port>, --port  <listen port> (default 5673 for ws2tcp
+ *                                                   5672 for tcp2ws)
+ *  -t <target port>, --tport <target port> (default listen port - 1 for ws2tcp
+ *                                                   listen port + 1 for tcp2ws)
+ *  -h <target host>, --thost <target host> (default 0.0.0.0)
+ *  -m <ws2tcp or tcp2ws>, --method <ws2tcp or tcp2ws> (default ws2tcp)
+ * @Author Fraser Adams
+ * @file
+ */
+
+var proxy = require('./ws2tcp.js');
+
+var lport = 5673;
+var tport = lport - 1;
+var thost = '0.0.0.0';
+var method = 'ws2tcp';
+
+var args = process.argv.slice(2);
+if (args.length > 0) {
+    if (args[0] === '-h' || args[0] === '--help') {
+        console.log("Usage: node proxy.js [options]");
+        console.log("Options:");
+        console.log("  -p <listen port>, --port  <listen port> (default " + lport + " for ws2tcp");
+        console.log("                                                   " + tport + " for tcp2ws)");
+        console.log("  -t <target port>, --tport <target port> (default listen port - 1 for ws2tcp");
+        console.log("                                                   listen port + 1 for tcp2ws)");
+        console.log("  -h <target host>, --thost <target host> (default " + thost + ")");
+        console.log("  -m <ws2tcp or tcp2ws>, --method <ws2tcp or tcp2ws> (default " + method + ")");
+        process.exit(0);
+    }
+
+    var lportSet = false;
+    var tportSet = false;
+    for (var i = 0; i < args.length; i++) {
+        var arg = args[i];
+        if (arg.charAt(0) === '-') {
+            i++;
+            var val = args[i];
+            if (arg === '-p' || arg === '--port') {
+                lport = val;
+                lportSet = true;
+            } else if (arg === '-t' || arg === '--tport') {
+                tport = val;
+                tportSet = true;
+            } else if (arg === '-h' || arg === '--thost') {
+                thost = val;
+            } else if (arg === '-m' || arg === '--method') {
+                method = val;
+            }
+        }
+    }
+
+    if (method === 'tcp2ws' && !lportSet) {
+        lport--;
+    }
+
+    if (!tportSet) {
+        tport = (method === 'ws2tcp') ? lport - 1 : +lport + 1;
+    }
+}
+
+if (method === 'tcp2ws') {
+    console.log("Proxying tcp -> ws");
+    console.log("Forwarding port " + lport + " to " + thost + ":" + tport);
+    proxy.tcp2ws(lport, thost, tport, 'AMQPWSB10');
+} else if (method === 'ws2tcp') {
+    console.log("Proxying ws -> tcp");
+    console.log("Forwarding port " + lport + " to " + thost + ":" + tport);
+    proxy.ws2tcp(lport, thost, tport);
+} else {
+    console.error("Method must be either ws2tcp or tcp2ws.");
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/javascript/qpid-config.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/qpid-config.js b/examples/messenger/javascript/qpid-config.js
new file mode 100755
index 0000000..466f8b6
--- /dev/null
+++ b/examples/messenger/javascript/qpid-config.js
@@ -0,0 +1,1375 @@
+#!/usr/bin/env node
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * Port of qpid-config to JavaScript for node.js, mainly intended as a demo to
+ * illustrate using QMF2 in JavaScript using the proton.Messenger JS binding.
+ * It illustrates a few things including how to use Messenger completely
+ * asynchronously including using an async request/response pattern with
+ * correlation IDs. It also proves interoperability of AMQP Map, List etc.
+ * between C++ and JavaScript as QMF2 is pretty much all about Lists of Maps.
+ * <p>
+ * The actual QMF2 code is pretty simple as we're just doing a basic getObjects
+ * it's made all the simpler because we can use JavaScript object literals as
+ * the JavaScript binding serialises and deserialises directly between JavaScript
+ * Objects and Lists and the AMQP type system so something that can be quite
+ * involved in languages like C++ and Java becomes quite simple in JavaScript,
+ * though the asynchronous nature of JavaScript provides its own opportunities
+ * for complication best illustrated by the need for the correlator object.
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("qpid-proton");
+}
+
+var address = 'amqp://0.0.0.0:5673/qmf.default.direct';
+var replyTo = '';
+var subscription;
+var subscribed = false;
+
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+
+/**
+ * The correlator object is a mechanism used to correlate requests with their
+ * aynchronous responses. It might possible be better to make use of Promises
+ * to implement part of this behaviour but a mechanism would still be meeded to
+ * correlate a request with its response callback in order to wrap things up in
+ * a Promise, so much of the behaviour of this object would still be required.
+ * In addition it seemed to make sense to make this QMF2 implementation fairly
+ * free of dependencies and using Promises would require external libraries.
+ * Instead the correlator implements Promise-like semantics, you might call it
+ * a broken Promise :-)
+ * in particular the request method behaves a *bit* like Promise.all() though it
+ * is mostly fake and takes an array of functions that call the add() method
+ * which is really the method used to associate response objects by correlationID.
+ * The then method is used to register a listener that will be called when all
+ * the requests that have been registered have received responses.
+ * TODO error/timeout handling.
+ */
+var correlator = {
+    _resolve: null,
+    _objects: {},
+    add: function(id) {
+        this._objects[id] = {complete: false, list: null};
+    },
+    request: function() {
+        this._resolve = function() {console.log("Warning: No resolver has been set")};
+        return this;
+    },
+    then: function(resolver) {
+        this._resolve = resolver ? resolver : this._resolve;
+    },
+    resolve: function() {
+        var opcode = message.properties['qmf.opcode'];
+        var correlationID = message.getCorrelationID();
+        var resp = this._objects[correlationID];
+        if (opcode === '_query_response') {
+            if (resp.list) {
+                Array.prototype.push.apply(resp.list, message.body); // This is faster than concat.
+            } else {
+                resp.list = message.body;
+            }
+
+            var partial = message.properties['partial'];
+            if (!partial) {
+                resp.complete = true;
+            }
+
+            this._objects[correlationID] = resp;
+            this._checkComplete();
+        } else if (opcode === '_method_response' || opcode === '_exception') {
+            resp.list = message.body;
+            resp.complete = true;
+            this._objects[correlationID] = resp;
+            this._checkComplete();
+        } else {
+            console.error("Bad Message response, qmf.opcode = " + opcode);
+        }
+    },
+    _checkComplete: function() {
+        var response = {};
+        for (var id in this._objects) {
+            var object = this._objects[id];
+            if (object.complete) {
+                response[id] = object.list;
+            } else {
+                return;
+            }
+        }
+
+        this._objects = {}; // Clear state ready for next call.
+        this._resolve(response.method ? response.method : response);
+    }
+};
+
+var pumpData = function() {
+    if (!subscribed) {
+        var subscriptionAddress = subscription.getAddress();
+        if (subscriptionAddress) {
+            subscribed = true;
+            var splitAddress = subscriptionAddress.split('/');
+            replyTo = splitAddress[splitAddress.length - 1];
+
+            onSubscription();
+        }
+    }
+
+    while (messenger.incoming()) {
+        // The second parameter forces Binary payloads to be decoded as strings
+        // this is useful because the broker QMF Agent encodes strings as AMQP
+        // binary, which is a right pain from an interoperability perspective.
+        var t = messenger.get(message, true);
+        correlator.resolve();
+        messenger.accept(t);
+    }
+
+    if (messenger.isStopped()) {
+        message.free();
+        messenger.free();
+    }
+};
+
+var getObjects = function(packageName, className) {
+    message.setAddress(address);
+    message.setSubject('broker');
+    message.setReplyTo(replyTo);
+    message.setCorrelationID(className);
+    message.properties = {
+        "x-amqp-0-10.app-id": "qmf2",
+        "method": "request",
+        "qmf.opcode": "_query_request",
+    };
+    message.body = {
+        "_what": "OBJECT",
+        "_schema_id": {
+            "_package_name": packageName,
+            "_class_name": className
+        }
+    };
+
+    correlator.add(className);
+    messenger.put(message);
+};
+
+var invokeMethod = function(object, method, arguments) {
+    var correlationID = 'method';
+    message.setAddress(address);
+    message.setSubject('broker');
+    message.setReplyTo(replyTo);
+    message.setCorrelationID(correlationID);
+    message.properties = {
+        "x-amqp-0-10.app-id": "qmf2",
+        "method": "request",
+        "qmf.opcode": "_method_request",
+    };
+    message.body = {
+        "_object_id": object._object_id,
+        "_method_name" : method,
+        "_arguments"   : arguments
+    };
+
+    correlator.add(correlationID);
+    messenger.put(message);
+};
+
+messenger.on('error', function(error) {console.log(error);});
+messenger.on('work', pumpData);
+messenger.setOutgoingWindow(1024);
+messenger.start();
+
+subscription = messenger.subscribe('amqp://0.0.0.0:5673/#');
+messenger.recv(); // Receive as many messages as messenger can buffer.
+
+
+/************************* qpid-config business logic ************************/
+
+var _usage =
+'Usage:  qpid-config [OPTIONS]\n' +
+'        qpid-config [OPTIONS] exchanges [filter-string]\n' +
+'        qpid-config [OPTIONS] queues    [filter-string]\n' +
+'        qpid-config [OPTIONS] add exchange <type> <name> [AddExchangeOptions]\n' +
+'        qpid-config [OPTIONS] del exchange <name>\n' +
+'        qpid-config [OPTIONS] add queue <name> [AddQueueOptions]\n' +
+'        qpid-config [OPTIONS] del queue <name> [DelQueueOptions]\n' +
+'        qpid-config [OPTIONS] bind   <exchange-name> <queue-name> [binding-key]\n' +
+'                  <for type xml>     [-f -|filename]\n' +
+'                  <for type header>  [all|any] k1=v1 [, k2=v2...]\n' +
+'        qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]\n' +
+'        qpid-config [OPTIONS] reload-acl\n' +
+'        qpid-config [OPTIONS] add <type> <name> [--argument <property-name>=<property-value>]\n' +
+'        qpid-config [OPTIONS] del <type> <name>\n' +
+'        qpid-config [OPTIONS] list <type> [--show-property <property-name>]\n';
+
+var usage = function() {
+    console.log(_usage);
+    process.exit(-1);
+};
+
+var _description =
+'Examples:\n' +
+'\n' +
+'$ qpid-config add queue q\n' +
+'$ qpid-config add exchange direct d -a localhost:5672\n' +
+'$ qpid-config exchanges -b 10.1.1.7:10000\n' +
+'$ qpid-config queues -b guest/guest@broker-host:10000\n' +
+'\n' +
+'Add Exchange <type> values:\n' +
+'\n' +
+'    direct     Direct exchange for point-to-point communication\n' +
+'    fanout     Fanout exchange for broadcast communication\n' +
+'    topic      Topic exchange that routes messages using binding keys with wildcards\n' +
+'    headers    Headers exchange that matches header fields against the binding keys\n' +
+'    xml        XML Exchange - allows content filtering using an XQuery\n' +
+'\n' +
+'\n' +
+'Queue Limit Actions:\n' +
+'\n' +
+'    none (default) - Use broker\'s default policy\n' +
+'    reject         - Reject enqueued messages\n' +
+'    ring           - Replace oldest unacquired message with new\n' +
+'\n' +
+'Replication levels:\n' +
+'\n' +
+'    none           - no replication\n' +
+'    configuration  - replicate queue and exchange existence and bindings, but not messages.\n' +
+'    all            - replicate configuration and messages\n';
+
+var _options =
+'Options:\n' +
+'  -h, --help            show this help message and exit\n' +
+'\n' +
+'  General Options:\n' +
+'    -t <secs>, --timeout=<secs>\n' +
+'                        Maximum time to wait for broker connection (in\n' +
+'                        seconds)\n' +
+'    -r, --recursive     Show bindings in queue or exchange list\n' +
+'    -b <address>, --broker=<address>\n' +
+'                        Address of qpidd broker with syntax:\n' +
+'                        [username/password@] hostname | ip-address [:<port>]\n' +
+'    -a <address>, --broker-addr=<address>\n' +
+/* TODO Connection options
+'    --sasl-mechanism=<mech>\n' +
+'                        SASL mechanism for authentication (e.g. EXTERNAL,\n' +
+'                        ANONYMOUS, PLAIN, CRAM-MD5, DIGEST-MD5, GSSAPI). SASL\n' +
+'                        automatically picks the most secure available\n' +
+'                        mechanism - use this option to override.\n' +
+'    --ssl-certificate=<cert>\n' +
+'                        Client SSL certificate (PEM Format)\n' +
+'    --ssl-key=<key>     Client SSL private key (PEM Format)\n' +
+'    --ha-admin          Allow connection to a HA backup broker.\n' +
+*/
+'\n' +
+'  Options for Listing Exchanges and Queues:\n' +
+'    --ignore-default    Ignore the default exchange in exchange or queue list\n' +
+'\n' +
+'  Options for Adding Exchanges and Queues:\n' +
+'    --alternate-exchange=<aexname>\n' +
+'                        Name of the alternate-exchange for the new queue or\n' +
+'                        exchange. Exchanges route messages to the alternate\n' +
+'                        exchange if they are unable to route them elsewhere.\n' +
+'                        Queues route messages to the alternate exchange if\n' +
+'                        they are rejected by a subscriber or orphaned by queue\n' +
+'                        deletion.\n' +
+'    --durable           The new queue or exchange is durable.\n' +
+'    --replicate=<level>\n' +
+'                        Enable automatic replication in a HA cluster. <level>\n' +
+'                        is \'none\', \'configuration\' or \'all\').\n' +
+'\n' +
+'  Options for Adding Queues:\n' +
+'    --file-count=<n>    Number of files in queue\'s persistence journal\n' +
+'    --file-size=<n>     File size in pages (64KiB/page)\n' +
+'    --max-queue-size=<n>\n' +
+'                        Maximum in-memory queue size as bytes\n' +
+'    --max-queue-count=<n>\n' +
+'                        Maximum in-memory queue size as a number of messages\n' +
+'    --limit-policy=<policy>\n' +
+'                        Action to take when queue limit is reached\n' +
+'    --lvq-key=<key>     Last Value Queue key\n' +
+'    --generate-queue-events=<n>\n' +
+'                        If set to 1, every enqueue will generate an event that\n' +
+'                        can be processed by registered listeners (e.g. for\n' +
+'                        replication). If set to 2, events will be generated\n' +
+'                        for enqueues and dequeues.\n' +
+'    --flow-stop-size=<n>\n' +
+'                        Turn on sender flow control when the number of queued\n' +
+'                        bytes exceeds this value.\n' +
+'    --flow-resume-size=<n>\n' +
+'                        Turn off sender flow control when the number of queued\n' +
+'                        bytes drops below this value.\n' +
+'    --flow-stop-count=<n>\n' +
+'                        Turn on sender flow control when the number of queued\n' +
+'                        messages exceeds this value.\n' +
+'    --flow-resume-count=<n>\n' +
+'                        Turn off sender flow control when the number of queued\n' +
+'                        messages drops below this value.\n' +
+'    --group-header=<header-name>\n' +
+'                        Enable message groups. Specify name of header that\n' +
+'                        holds group identifier.\n' +
+'    --shared-groups     Allow message group consumption across multiple\n' +
+'                        consumers.\n' +
+'    --argument=<NAME=VALUE>\n' +
+'                        Specify a key-value pair to add to queue arguments\n' +
+'    --start-replica=<broker-url>\n' +
+'                        Start replication from the same-named queue at\n' +
+'                        <broker-url>\n' +
+'\n' +
+'  Options for Adding Exchanges:\n' +
+'    --sequence          Exchange will insert a \'qpid.msg_sequence\' field in\n' +
+'                        the message header\n' +
+'    --ive               Exchange will behave as an \'initial-value-exchange\',\n' +
+'                        keeping a reference  to the last message forwarded and\n' +
+'                        enqueuing that message to newly bound queues.\n' +
+'\n' +
+'  Options for Deleting Queues:\n' +
+'    --force             Force delete of queue even if it\'s currently used or\n' +
+'                        it\'s not empty\n' +
+'    --force-if-not-empty\n' +
+'                        Force delete of queue even if it\'s not empty\n' +
+'    --force-if-used     Force delete of queue even if it\'s currently used\n' +
+'\n' +
+'  Options for Declaring Bindings:\n' +
+'    -f <file.xq>, --file=<file.xq>\n' +
+'                        For XML Exchange bindings - specifies the name of a\n' +
+'                        file containing an XQuery.\n' +
+'\n' +
+'  Formatting options for \'list\' action:\n' +
+'    --show-property=<property-name>\n' +
+'                        Specify a property of an object to be included in\n' +
+'                        output\n';
+
+var REPLICATE_LEVELS = {"none" : true, "configuration": true, "all": true};
+var DEFAULT_PROPERTIES = {"exchange":["name", "type", "durable"], "queue":["name", "durable", "autoDelete"]};
+
+var config = {
+    _recursive      : false,
+    _host           : 'localhost',
+    _connTimeout    : 10,
+    _ignoreDefault  : false,
+    _altern_ex      : null,
+    _durable        : false,
+    _replicate      : null,
+    _if_empty       : true,
+    _if_unused      : true,
+    _fileCount      : null,
+    _fileSize       : null,
+    _maxQueueSize   : null,
+    _maxQueueCount  : null,
+    _limitPolicy    : null,
+    _msgSequence    : false,
+    _lvq_key        : null,
+    _ive            : null,
+    _eventGeneration: null,
+    _file           : null,
+    _flowStopCount  : null,
+    _flowResumeCount: null,
+    _flowStopSize   : null,
+    _flowResumeSize : null,
+    _msgGroupHeader : null,
+    _sharedMsgGroup : false,
+    _extra_arguments: [],
+    _start_replica  : null,
+    _returnCode     : 0,
+    _list_properties: [],
+
+    getOptions: function() {
+        var options = {};
+        for (var a = 0; a < this._extra_arguments.length; a++) {
+            var r = this._extra_arguments[a].split('=');
+            var value = null;
+            if (r.length === 2) {
+                value = r[1]; 
+            }
+            options[r[0]] = value;
+        }
+        return options;
+    }
+};
+
+var FILECOUNT = 'qpid.file_count';
+var FILESIZE  = 'qpid.file_size';
+var MAX_QUEUE_SIZE  = 'qpid.max_size';
+var MAX_QUEUE_COUNT  = 'qpid.max_count';
+var POLICY_TYPE  = 'qpid.policy_type';
+var LVQ_KEY = 'qpid.last_value_queue_key';
+var MSG_SEQUENCE = 'qpid.msg_sequence';
+var IVE = 'qpid.ive';
+var QUEUE_EVENT_GENERATION = 'qpid.queue_event_generation';
+var FLOW_STOP_COUNT   = 'qpid.flow_stop_count';
+var FLOW_RESUME_COUNT = 'qpid.flow_resume_count';
+var FLOW_STOP_SIZE    = 'qpid.flow_stop_size';
+var FLOW_RESUME_SIZE  = 'qpid.flow_resume_size';
+var MSG_GROUP_HDR_KEY = 'qpid.group_header_key';
+var SHARED_MSG_GROUP  = 'qpid.shared_msg_group';
+var REPLICATE = 'qpid.replicate';
+
+/**
+ * There are various arguments to declare that have specific program
+ * options in this utility. However there is now a generic mechanism for
+ * passing arguments as well. The SPECIAL_ARGS list contains the
+ * arguments for which there are specific program options defined
+ * i.e. the arguments for which there is special processing on add and
+ * list
+*/
+var SPECIAL_ARGS={};
+SPECIAL_ARGS[FILECOUNT] = true;
+SPECIAL_ARGS[FILESIZE] = true;
+SPECIAL_ARGS[MAX_QUEUE_SIZE] = true;
+SPECIAL_ARGS[MAX_QUEUE_COUNT] = true;
+SPECIAL_ARGS[POLICY_TYPE] = true;
+SPECIAL_ARGS[LVQ_KEY] = true;
+SPECIAL_ARGS[MSG_SEQUENCE] = true;
+SPECIAL_ARGS[IVE] = true;
+SPECIAL_ARGS[QUEUE_EVENT_GENERATION] = true;
+SPECIAL_ARGS[FLOW_STOP_COUNT] = true;
+SPECIAL_ARGS[FLOW_RESUME_COUNT] = true;
+SPECIAL_ARGS[FLOW_STOP_SIZE] = true;
+SPECIAL_ARGS[FLOW_RESUME_SIZE] = true;
+SPECIAL_ARGS[MSG_GROUP_HDR_KEY] = true;
+SPECIAL_ARGS[SHARED_MSG_GROUP] = true;
+SPECIAL_ARGS[REPLICATE] = true;
+
+var oid = function(id) {
+    return id._agent_epoch + ':' + id._object_name
+};
+
+var filterMatch = function(name, filter) {
+    if (filter === '') {
+        return true;
+    }
+    if (name.indexOf(filter) === -1) {
+        return false;
+    }
+    return true;
+};
+
+var idMap = function(list) {
+    var map = {};
+    for (var i = 0; i < list.length; i++) {
+        var item = list[i];
+        map[oid(item._object_id)] = item;
+    }
+    return map;
+};
+
+var renderArguments = function(obj, list) {
+    if (!obj) {
+        return '';
+    }
+    var string = '';
+    var addComma = false;
+    for (var prop in obj) {
+        if (addComma) {
+            string += ', ';
+        }
+        if (obj.hasOwnProperty(prop)) {
+            if (list) {
+                if (SPECIAL_ARGS[prop]) continue;
+                string += " --argument " + prop + "=" + obj[prop];
+            } else {    
+                string += "'" + prop + "'" + ": '" + obj[prop] + "'";
+                addComma = true;
+            }
+        }
+    }
+
+    if (addComma) {
+        return ' {' + string + '}';
+    } else {
+        if (list) {
+            return string;
+        } else {
+            return '';
+        }
+    }
+};
+
+/**
+ * The following methods illustrate the QMF2 class query mechanism which returns
+ * the list of QMF Objects for the specified class that are currently present
+ * on the Broker. The Schema <qpid>/cpp/src/qpid/broker/management-schema.xml
+ * describes the properties and statistics of each Management Object.
+ * <p>
+ * One slightly subtle part of QMF is that certain Objects are associated via
+ * references, for example Binding contains queueRef and exchangeRef, which lets
+ * Objects link to each other using their _object_id property.
+ * <p>
+ * The implementation of these methods attempts to follow the same general flow
+ * as the equivalent method in the "canonical" python based qpid-config version
+ * but has the added complication that JavaScript is entirely asynchronous.
+ * The approach that has been taken is to use the correlator object that lets a
+ * callback function be registered via the "then" method and actually calls the
+ * callback when all of the requests specified in the request method have
+ * returned their results (which get passed as the callback parameter).
+ */
+
+var overview = function() {
+    correlator.request(
+        // Send the QMF query requests for the specified classes.
+        getObjects('org.apache.qpid.broker', 'queue'),
+        getObjects('org.apache.qpid.broker', 'exchange')
+    ).then(function(objects) {
+        var exchanges = objects.exchange;
+        var queues = objects.queue;
+        console.log("Total Exchanges: " + exchanges.length);
+        var etype = {};
+        for (var i = 0; i < exchanges.length; i++) {
+            var exchange = exchanges[i]._values;
+            if (!etype[exchange.type]) {
+                etype[exchange.type] = 1;
+            } else {
+                etype[exchange.type]++;
+            }
+        }
+        for (var typ in etype) {
+            var pad = Array(16 - typ.length).join(' ');
+            console.log(pad + typ + ": " + etype[typ]);
+        }
+
+        console.log("\n   Total Queues: " + queues.length);
+        var durable = 0;
+        for (var i = 0; i < queues.length; i++) {
+            var queue = queues[i]._values;
+            if (queue.durable) {
+                durable++;
+            }
+        }
+        console.log("        durable: " + durable);
+        console.log("    non-durable: " + (queues.length - durable));
+        messenger.stop();
+    });
+};
+
+var exchangeList = function(filter) {
+    correlator.request(
+        // Send the QMF query requests for the specified classes.
+        getObjects('org.apache.qpid.broker', 'exchange')
+    ).then(function(objects) {
+        var exchanges = objects.exchange;
+        var exMap = idMap(exchanges);
+        var caption1 = "Type      ";
+        var caption2 = "Exchange Name";
+        var maxNameLen = caption2.length;
+        var found = false;
+        for (var i = 0; i < exchanges.length; i++) {
+            var exchange = exchanges[i]._values;
+            if (filterMatch(exchange.name, filter)) {
+                if (exchange.name.length > maxNameLen) {
+                    maxNameLen = exchange.name.length;
+                }
+                found = true;
+            }
+        }
+        if (!found) {
+            config._returnCode = 1;
+            return;
+        }
+
+        var pad = Array(maxNameLen + 1 - caption2.length).join(' ');
+        console.log(caption1 + caption2 + pad + "  Attributes");
+        console.log(Array(maxNameLen + caption1.length + 13).join('='));
+
+        for (var i = 0; i < exchanges.length; i++) {
+            var exchange = exchanges[i]._values;
+            if (config._ignoreDefault && !exchange.name) continue;
+            if (filterMatch(exchange.name, filter)) {
+                var pad1 = Array(11 - exchange.type.length).join(' ');
+                var pad2 = Array(maxNameLen + 2 - exchange.name.length).join(' ');
+                var string = exchange.type + pad1 + exchange.name + pad2;
+                var args = exchange.arguments ? exchange.arguments : {};
+                if (exchange.durable) {
+                    string += ' --durable';
+                }
+                if (args[REPLICATE]) {
+                    string += ' --replicate=' + args[REPLICATE];
+                }
+                if (args[MSG_SEQUENCE]) {
+                    string += ' --sequence';
+                }
+                if (args[IVE]) {
+                    string += ' --ive';
+                }
+                if (exchange.altExchange) {
+                    string += ' --alternate-exchange=' + exMap[oid(exchange.altExchange)]._values.name;
+                }
+                console.log(string);
+            }
+        }
+        messenger.stop();
+    });
+};
+
+var exchangeListRecurse = function(filter) {
+    correlator.request(
+        // Send the QMF query requests for the specified classes.
+        getObjects('org.apache.qpid.broker', 'queue'),
+        getObjects('org.apache.qpid.broker', 'exchange'),
+        getObjects('org.apache.qpid.broker', 'binding')
+    ).then(function(objects) {
+        var exchanges = objects.exchange;
+        var bindings = objects.binding;
+        var queues = idMap(objects.queue);
+
+        for (var i = 0; i < exchanges.length; i++) {
+            var exchange = exchanges[i];
+            var exchangeId = oid(exchange._object_id);
+            exchange = exchange._values;
+
+            if (config._ignoreDefault && !exchange.name) continue;
+            if (filterMatch(exchange.name, filter)) {
+                console.log("Exchange '" + exchange.name + "' (" + exchange.type + ")");
+                for (var j = 0; j < bindings.length; j++) {
+                    var bind = bindings[j]._values;
+                    var exchangeRef = oid(bind.exchangeRef);
+
+                    if (exchangeRef === exchangeId) {
+                        var queue = queues[oid(bind.queueRef)];
+                        var queueName = queue ? queue._values.name : "<unknown>";
+                        console.log("    bind [" + bind.bindingKey + "] => " + queueName + 
+                                    renderArguments(bind.arguments));
+                    }   
+                }
+            }
+        }
+        messenger.stop();
+    });
+};
+
+var queueList = function(filter) {
+    correlator.request(
+        // Send the QMF query requests for the specified classes.
+        getObjects('org.apache.qpid.broker', 'queue'),
+        getObjects('org.apache.qpid.broker', 'exchange')
+    ).then(function(objects) {
+        var queues = objects.queue;
+        var exMap = idMap(objects.exchange);
+        var caption = "Queue Name";
+        var maxNameLen = caption.length;
+        var found = false;
+        for (var i = 0; i < queues.length; i++) {
+            var queue = queues[i]._values;
+            if (filterMatch(queue.name, filter)) {
+                if (queue.name.length > maxNameLen) {
+                    maxNameLen = queue.name.length;
+                }
+                found = true;
+            }
+        }
+        if (!found) {
+            config._returnCode = 1;
+            return;
+        }
+
+        var pad = Array(maxNameLen + 1 - caption.length).join(' ');
+        console.log(caption + pad + "  Attributes");
+        console.log(Array(maxNameLen + caption.length + 3).join('='));
+
+        for (var i = 0; i < queues.length; i++) {
+            var queue = queues[i]._values;
+            if (filterMatch(queue.name, filter)) {
+                var pad2 = Array(maxNameLen + 2 - queue.name.length).join(' ');
+                var string = queue.name + pad2;
+                var args = queue.arguments ? queue.arguments : {};
+                if (queue.durable) {
+                    string += ' --durable';
+                }
+                if (args[REPLICATE]) {
+                    string += ' --replicate=' + args[REPLICATE];
+                }
+                if (queue.autoDelete) {
+                    string += ' auto-del';
+                }
+                if (queue.exclusive) {
+                    string += ' excl';
+                }
+                if (args[FILESIZE]) {
+                    string += ' --file-size=' + args[FILESIZE];
+                }
+                if (args[FILECOUNT]) {
+                    string += ' --file-count=' + args[FILECOUNT];
+                }
+                if (args[MAX_QUEUE_SIZE]) {
+                    string += ' --max-queue-size=' + args[MAX_QUEUE_SIZE];
+                }
+                if (args[MAX_QUEUE_COUNT]) {
+                    string += ' --max-queue-count=' + args[MAX_QUEUE_COUNT];
+                }
+                if (args[POLICY_TYPE]) {
+                    string += ' --limit-policy=' + args[POLICY_TYPE].replace("_", "-");
+                }
+                if (args[LVQ_KEY]) {
+                    string += ' --lvq-key=' + args[LVQ_KEY];
+                }
+                if (args[QUEUE_EVENT_GENERATION]) {
+                    string += ' --generate-queue-events=' + args[QUEUE_EVENT_GENERATION];
+                }
+                if (queue.altExchange) {
+                    string += ' --alternate-exchange=' + exMap[oid(queue.altExchange)]._values.name;
+                }
+                if (args[FLOW_STOP_SIZE]) {
+                    string += ' --flow-stop-size=' + args[FLOW_STOP_SIZE];
+                }
+                if (args[FLOW_RESUME_SIZE]) {
+                    string += ' --flow-resume-size=' + args[FLOW_RESUME_SIZE];
+                }
+                if (args[FLOW_STOP_COUNT]) {
+                    string += ' --flow-stop-count=' + args[FLOW_STOP_COUNT];
+                }
+                if (args[FLOW_RESUME_COUNT]) {
+                    string += ' --flow-resume-count=' + args[FLOW_RESUME_COUNT];
+                }
+                if (args[MSG_GROUP_HDR_KEY]) {
+                    string += ' --group-header=' + args[MSG_GROUP_HDR_KEY];
+                }
+                if (args[SHARED_MSG_GROUP] === 1) {
+                    string += ' --shared-groups';
+                }
+                string += renderArguments(args, true);
+                console.log(string);
+            }
+        }
+        messenger.stop();
+    });
+};
+
+var queueListRecurse = function(filter) {
+    correlator.request(
+        // Send the QMF query requests for the specified classes.
+        getObjects('org.apache.qpid.broker', 'queue'),
+        getObjects('org.apache.qpid.broker', 'exchange'),
+        getObjects('org.apache.qpid.broker', 'binding')
+    ).then(function(objects) {
+        var queues = objects.queue;
+        var bindings = objects.binding;
+        var exchanges = idMap(objects.exchange);
+
+        for (var i = 0; i < queues.length; i++) {
+            var queue = queues[i];
+            var queueId = oid(queue._object_id);
+            queue = queue._values;
+
+            if (filterMatch(queue.name, filter)) {
+                console.log("Queue '" + queue.name + "'");
+                for (var j = 0; j < bindings.length; j++) {
+                    var bind = bindings[j]._values;
+                    var queueRef = oid(bind.queueRef);
+
+                    if (queueRef === queueId) {
+                        var exchange = exchanges[oid(bind.exchangeRef)];
+                        var exchangeName = "<unknown>";
+                        if (exchange) {
+                            exchangeName = exchange._values.name;
+                            if (exchangeName === '') {
+                                if (config._ignoreDefault) continue;
+                                exchangeName = "''";
+                            }
+                        }
+
+                        console.log("    bind [" + bind.bindingKey + "] => " + exchangeName + 
+                                    renderArguments(bind.arguments));
+                    }   
+                }
+            }
+        }
+        messenger.stop();
+    });
+};
+
+/**
+ * The following methods implement adding and deleting various Broker Management
+ * Objects via QMF. Although <qpid>/cpp/src/qpid/broker/management-schema.xml
+ * describes the basic method schema, for example:
+ *   <method name="create" desc="Create an object of the specified type">
+ *     <arg name="type" dir="I" type="sstr" desc="The type of object to create"/>
+ *     <arg name="name" dir="I" type="sstr" desc="The name of the object to create"/>
+ *     <arg name="properties" dir="I" type="map" desc="Type specific object properties"/>
+ *     <arg name="strict" dir="I" type="bool" desc="If specified, treat unrecognised object properties as an error"/>
+ *   </method>
+ *
+ *   <method name="delete" desc="Delete an object of the specified type">
+ *     <arg name="type" dir="I" type="sstr" desc="The type of object to delete"/>
+ *     <arg name="name" dir="I" type="sstr" desc="The name of the object to delete"/>
+ *     <arg name="options" dir="I" type="map" desc="Type specific object options for deletion"/>
+ *   </method>
+ *
+ * What the schema doesn't do however is to explain what the properties/options
+ * Map values actually mean, unfortunately these aren't documented anywhere so
+ * the only option is to look in the code, the best place to look is in:
+ * <qpid>/cpp/src/qpid/broker/Broker.cpp, the method Broker::ManagementMethod is
+ * the best place to start, then Broker::createObject and Broker::deleteObject
+ * even then it's pretty hard to figure out all that is possible.
+ */
+
+var handleMethodResponse = function(response, dontStop) {
+console.log("Method result");
+    if (response._arguments) {
+        //console.log(response._arguments);
+    } if (response._values) {
+        console.error("Exception from Agent: " + renderArguments(response._values));
+    }
+    // Mostly we want to stop the Messenger Event loop and exit when a QMF method
+    // call returns, but sometimes we don't.
+    if (!dontStop) {
+        messenger.stop();
+    }
+}
+
+var addExchange = function(args) {
+    if (args.length < 2) {
+        usage();
+    }
+
+    var etype = args[0];
+    var ename = args[1];
+    var declArgs = {};
+
+    declArgs['exchange-type'] = etype;
+
+    for (var a = 0; a < config._extra_arguments.length; a++) {
+        var r = config._extra_arguments[a].split('=');
+        var value = null;
+        if (r.length === 2) {
+            value = r[1]; 
+        }
+        declArgs[r[0]] = value;
+    }
+
+    if (config._msgSequence) {
+        declArgs[MSG_SEQUENCE] = 1;
+    }
+
+    if (config._ive) {
+        declArgs[IVE] = 1;
+    }
+
+    if (config._altern_ex) {
+        declArgs['alternate-exchange'] = config._altern_ex;
+    }
+
+    if (config._durable) {
+        declArgs['durable'] = 1;
+    }
+
+    if (config._replicate) {
+        declArgs[REPLICATE] = config._replicate;
+    }
+
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker')
+    ).then(function(objects) {
+        var broker = objects.broker[0];
+        correlator.request(
+            invokeMethod(broker, 'create', {
+                "type":      "exchange",
+                "name":       ename,
+                "properties": declArgs,
+                "strict":     true})
+        ).then(handleMethodResponse);
+    });
+};
+
+var delExchange = function(args) {
+    if (args.length < 1) {
+        usage();
+    }
+
+    var ename = args[0];
+
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker')
+    ).then(function(objects) {
+        var broker = objects.broker[0];
+        correlator.request(
+            invokeMethod(broker, 'delete', {
+                "type":   "exchange",
+                "name":    ename})
+        ).then(handleMethodResponse);
+    });
+};
+
+var addQueue = function(args) {
+    if (args.length < 1) {
+        usage();
+    }
+
+    var qname = args[0];
+    var declArgs = {};
+
+    for (var a = 0; a < config._extra_arguments.length; a++) {
+        var r = config._extra_arguments[a].split('=');
+        var value = null;
+        if (r.length === 2) {
+            value = r[1]; 
+        }
+        declArgs[r[0]] = value;
+    }
+
+    if (config._durable) {
+        // allow the default fileCount and fileSize specified 
+        // in qpid config file to take prededence
+        if (config._fileCount) {
+            declArgs[FILECOUNT] = config._fileCount;
+        }
+        if (config._fileSize) {
+            declArgs[FILESIZE]  = config._fileSize;
+        }
+    }
+
+    if (config._maxQueueSize != null) {
+        declArgs[MAX_QUEUE_SIZE] = config._maxQueueSize;
+    }
+
+    if (config._maxQueueCount != null) {
+        declArgs[MAX_QUEUE_COUNT] = config._maxQueueCount;
+    }
+    
+    if (config._limitPolicy) {
+        if (config._limitPolicy === 'none') {
+        } else if (config._limitPolicy === 'reject') {
+            declArgs[POLICY_TYPE] = 'reject';
+        } else if (config._limitPolicy === 'ring') {
+            declArgs[POLICY_TYPE] = 'ring';
+        }
+    }
+
+    if (config._lvq_key) {
+        declArgs[LVQ_KEY] = config._lvq_key;
+    }
+
+    if (config._eventGeneration) {
+        declArgs[QUEUE_EVENT_GENERATION] = config._eventGeneration;
+    }
+
+    if (config._flowStopSize != null) {
+        declArgs[FLOW_STOP_SIZE] = config._flowStopSize;
+    }
+
+    if (config._flowResumeSize != null) {
+        declArgs[FLOW_RESUME_SIZE] = config._flowResumeSize;
+    }
+
+    if (config._flowStopCount != null) {
+        declArgs[FLOW_STOP_COUNT] = config._flowStopCount;
+    }
+
+    if (config._flowResumeCount != null) {
+        declArgs[FLOW_RESUME_COUNT] = config._flowResumeCount;
+    }
+
+    if (config._msgGroupHeader) {
+        declArgs[MSG_GROUP_HDR_KEY] = config._msgGroupHeader;
+    }
+
+    if (config._sharedMsgGroup) {
+        declArgs[SHARED_MSG_GROUP] = 1;
+    }
+
+    if (config._altern_ex) {
+        declArgs['alternate-exchange'] = config._altern_ex;
+    }
+
+    if (config._durable) {
+        declArgs['durable'] = 1;
+    }
+
+    if (config._replicate) {
+        declArgs[REPLICATE] = config._replicate;
+    }
+
+    // This block is a little complex and untidy, the real issue is that the
+    // correlator object isn't as good as a real Promise and doesn't support
+    // chaining of "then" calls, so where we have complex dependencies we still
+    // get somewhat into "callback hell". TODO improve the correlator.
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker')
+    ).then(function(objects) {
+        var broker = objects.broker[0];
+        correlator.request(
+            invokeMethod(broker, 'create', {
+                "type":      "queue",
+                "name":       qname,
+                "properties": declArgs,
+                "strict":     true})
+        ).then(function(response) {
+            if (config._start_replica) {
+                handleMethodResponse(response, true); // The second parameter prevents exiting.
+                // TODO test this stuff!
+                correlator.request(
+                    getObjects('org.apache.qpid.ha', 'habroker') // Not sure if this is correct
+                ).then(function(objects) {
+                    if (objects.habroker.length > 0) {
+                        var habroker = objects.habroker[0];
+                        correlator.request(
+                            invokeMethod(habroker, 'replicate', {
+                                "broker": config._start_replica,
+                                "queue":  qname})
+                        ).then(handleMethodResponse);
+                    } else {
+                        messenger.stop();
+                    }
+                });
+            } else {
+                handleMethodResponse(response);
+            }
+        });
+    });
+};
+
+var delQueue = function(args) {
+    if (args.length < 1) {
+        usage();
+    }
+
+    var qname = args[0];
+
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker')
+    ).then(function(objects) {
+        var broker = objects.broker[0];
+        correlator.request(
+            invokeMethod(broker, 'delete', {
+                "type":   "queue",
+                "name":    qname,
+                "options": {"if_empty":  config._if_empty,
+                            "if_unused": config._if_unused}})
+        ).then(handleMethodResponse);
+    });
+};
+
+var snarf_header_args = function(args) {
+    if (args.length < 2) {
+        console.log("Invalid args to bind headers: need 'any'/'all' plus conditions");
+        return false;
+    }
+
+    var op = args[0];
+    if (op === 'all' || op === 'any') {
+        kv = {};
+        var bindings = Array.prototype.slice.apply(args, [1]);
+        for (var i = 0; i < bindings.length; i++) {
+            var binding = bindings[i];
+            binding = binding.split(",")[0];
+            binding = binding.split("=");
+            kv[binding[0]] = binding[1];
+        }
+        kv['x-match'] = op;
+        return kv;
+    } else {
+        console.log("Invalid condition arg to bind headers, need 'any' or 'all', not '" + op + "'");
+        return false;
+    }
+};
+
+var bind = function(args) {
+console.log("bind");
+console.log(args);
+
+    if (args.length < 2) {
+        usage();
+    }
+
+    var ename = args[0];
+    var qname = args[1];
+    var key   = '';
+
+    if (args.length > 2) {
+        key = args[2];
+    }
+
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker'),
+        getObjects('org.apache.qpid.broker', 'exchange') // Get exchanges to look up exchange type.
+    ).then(function(objects) {
+        var exchanges = objects.exchange;
+
+        var etype = '';
+        for (var i = 0; i < exchanges.length; i++) {
+            var exchange = exchanges[i]._values;
+            if (exchange.name === ename) {
+                etype = exchange.type;
+                break;
+            }
+        }
+
+        // type of the xchg determines the processing of the rest of
+        // argv.  if it's an xml xchg, we want to find a file
+        // containing an x-query, and pass that.  if it's a headers
+        // exchange, we need to pass either "any" or all, followed by a
+        // map containing key/value pairs.  if neither of those, extra
+        // args are ignored.
+        var declArgs = {};
+        if (etype === 'xml') {
+
+
+        } else if (etype === 'headers') {
+            declArgs = snarf_header_args(Array.prototype.slice.apply(args, [3]));
+        }
+console.log(declArgs);
+
+        if (typeof declArgs !== 'object') {
+            process.exit(1);
+        }
+
+        var broker = objects.broker[0];
+        correlator.request(
+            invokeMethod(broker, 'create', {
+                "type":   "binding",
+                "name":    ename + '/' + qname + '/' + key,
+                "properties": declArgs,
+                "strict":     true})
+        ).then(handleMethodResponse);
+    });
+
+/*
+
+        ok = True
+        _args = {}
+        if not res:
+            pass
+        elif res.type == "xml":
+            # this checks/imports the -f arg
+            [ok, xquery] = snarf_xquery_args()
+            _args = { "xquery" : xquery }
+        else:
+            if res.type == "headers":
+                [ok, op, kv] = snarf_header_args(args[3:])
+                _args = kv
+                _args["x-match"] = op
+
+        if not ok:
+            sys.exit(1)
+
+        self.broker.bind(ename, qname, key, _args)
+*/
+
+};
+
+var unbind = function(args) {
+console.log("unbind");
+console.log(args);
+
+    if (args.length < 2) {
+        usage();
+    }
+
+    var ename = args[0];
+    var qname = args[1];
+    var key   = '';
+
+    if (args.length > 2) {
+        key = args[2];
+    }
+
+    correlator.request(
+        // We invoke the CRUD methods on the broker object.
+        getObjects('org.apache.qpid.broker', 'broker')
+    ).then(function(objects) {
+        var broker = objects.broker[0];
+        correlator.request(
+            invokeMethod(broker, 'delete', {
+                "type":   "binding",
+                "name":    ename + '/' + qname + '/' + key})
+        ).then(handleMethodResponse);
+    });
+};
+
+/**
+ * The following methods are "generic" create and delete methods to for arbitrary
+ * Management Objects e.g. Incoming, Outgoing, Domain, Topic, QueuePolicy,
+ * TopicPolicy etc. use --argument k1=v1 --argument k2=v2 --argument k3=v3 to
+ * pass arbitrary arguments as key/value pairs to the Object being created/deleted.
+ */
+
+var createObject = function(type, name, args) {
+console.log("createObject");
+console.log(type);
+console.log(name);
+console.log(args);
+
+};
+
+var deleteObject = function(args) {
+console.log("deleteObject");
+console.log(args);
+
+};
+
+
+/*********************** process command line options ************************/
+
+var params = [];
+var extra_arguments = [];
+var args = process.argv.slice(2);
+if (args.length > 0) {
+    if (args[0] === '-h' || args[0] === '--help') {
+        console.log(_usage);
+        console.log(_description);
+        console.log(_options);
+        process.exit(0);
+    }
+
+    for (var i = 0; i < args.length; i++) {
+        var arg = args[i];
+        if (arg === '-r' || arg === '--recursive') {
+            config._recursive = true;
+        } else if (arg === '--ignore-default') {
+            config._ignoreDefault = true;
+        } else if (arg === '--durable') {
+            config._durable = true;
+        } else if (arg === '--shared-groups') {
+            config._sharedMsgGroup = true;
+        } else if (arg === '--sequence') {
+            config._sequence = true;
+        } else if (arg === '--ive') {
+            config._ive = true;
+        } else if (arg === '--force') {
+            config._if_empty = false;
+            config._if_unused = false;
+        } else if (arg === '--force-if-not-empty') {
+            config._if_empty = false;
+        } else if (arg === '--force-if-used') {
+            config._if_unused = false;
+        } else if (arg === '--sequence') {
+            config._msgSequence = true;
+        } else if (arg.charAt(0) === '-') {
+            i++;
+            var val = args[i];
+            if (arg === '-t' || arg === '--timeout') {
+                config._connTimeout = parseInt(val);
+                if (config._connTimeout === 0) {
+                    config._connTimeout = null;
+                }
+            } else if (arg === '-b' || arg === '--broker' || arg === '-b' || arg === '--broker-addr') {
+                config._host = val;
+                if (config._host == null) {
+                    config._host = 'localhost:5672';
+                }
+            } else if (arg === '--alternate-exchange') {
+                config._altern_ex = val;
+            } else if (arg === '--replicate') {
+                if (!REPLICATE_LEVELS[val]) {
+                    console.error("Invalid replication level " + val + ", should be one of 'none', 'configuration' or 'all'");
+                }
+                config._replicate = val;
+            } else if (arg === '--file-count') {
+                config._fileCount = parseInt(val);
+            } else if (arg === '--file-size') {
+                config._fileSize = parseInt(val);
+            } else if (arg === '--max-queue-size') {
+                config._maxQueueSize = parseInt(val);
+            } else if (arg === '--max-queue-count') {
+                config._maxQueueCount = parseInt(val);
+            } else if (arg === '--limit-policy') {
+                config._limitPolicy = val;
+            } else if (arg === '--lvq-key') {
+                config._lvq_key = val;
+            } else if (arg === '--generate-queue-events') {
+                config._eventGeneration = parseInt(val);
+            } else if (arg === '--flow-stop-size') {
+                config._flowStopSize = parseInt(val);
+            } else if (arg === '--flow-resume-size') {
+                config._flowResumeSize = parseInt(val);
+            } else if (arg === '--flow-stop-count') {
+                config._flowStopCount = parseInt(val);
+            } else if (arg === '--flow-resume-count') {
+                config._flowResumeCount = parseInt(val);
+            } else if (arg === '--group-header') {
+                config._msgGroupHeader = val;
+            } else if (arg === '--argument') {
+                extra_arguments.push(val);
+            } else if (arg === '--start-replica') {
+                config._start_replica = val;
+            } else if (arg === '--f' || arg === '--file') { // TODO Won't work in node.js
+                config._file = val;
+            } else if (arg === '--show-property') {
+                config._list_properties = val;
+            }
+        } else {
+            params.push(arg);
+        }
+    }
+}
+
+config._extra_arguments = extra_arguments;
+
+console.log("params");
+console.log(params);
+
+// The command only *actually* gets called when the QMF connection has actually
+// been established so we wrap up the function we want to get called in a lambda.
+var command = function() {overview();};
+if (params.length > 0) {
+    var cmd = params[0];
+    var modifier = '';
+    if (params.length > 1) {
+        modifier = params[1];
+    }
+
+    if (cmd === 'exchanges') {
+        if (config._recursive) {
+            command = function() {exchangeListRecurse(modifier);};
+        } else {
+            command = function() {exchangeList(modifier);};
+        }
+    } else if (cmd === 'queues') {
+        if (config._recursive) {
+            command = function() {queueListRecurse(modifier);};
+        } else {
+            command = function() {queueList(modifier);};
+        }
+    } else if (cmd === 'add') {
+        if (modifier === 'exchange') {
+            command = function() {addExchange(Array.prototype.slice.apply(params, [2]));};
+        } else if (modifier === 'queue') {
+            command = function() {addQueue(Array.prototype.slice.apply(params, [2]));};
+        } else if (params.length > 2) {
+            command = function() {createObject(modifier, params[2], config.getOptions());};
+        } else {
+            usage();
+        }
+    } else if (cmd === 'del') {
+        if (modifier === 'exchange') {
+            command = function() {delExchange(Array.prototype.slice.apply(params, [2]));};
+        } else if (modifier === 'queue') {
+            command = function() {delQueue(Array.prototype.slice.apply(params, [2]));};
+        } else if (params.length > 2) {
+            command = function() {deleteObject(modifier, params[2], {});};
+        } else {
+            usage();
+        }
+    } else if (cmd === 'bind') {
+        command = function() {bind(Array.prototype.slice.apply(params, [1]));};
+    } else if (cmd === 'unbind') {
+        command = function() {unbind(Array.prototype.slice.apply(params, [1]));};
+    }
+}
+
+var onSubscription = function() {
+    command();
+};
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/javascript/recv.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/recv.js b/examples/messenger/javascript/recv.js
new file mode 100644
index 0000000..3d2b468
--- /dev/null
+++ b/examples/messenger/javascript/recv.js
@@ -0,0 +1,67 @@
+#!/usr/bin/env node
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("qpid-proton");
+}
+
+var address = "amqp://~0.0.0.0";
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+
+var pumpData = function() {
+    while (messenger.incoming()) {
+        var t = messenger.get(message);
+
+        console.log("Address: " + message.getAddress());
+        console.log("Subject: " + message.getSubject());
+
+        // body is the body as a native JavaScript Object, useful for most real cases.
+        //console.log("Content: " + message.body);
+
+        // data is the body as a proton.Data Object, used in this case because
+        // format() returns exactly the same representation as recv.c
+        console.log("Content: " + message.data.format());
+
+        messenger.accept(t);
+    }
+};
+
+var args = process.argv.slice(2);
+if (args.length > 0) {
+    if (args[0] === '-h' || args[0] === '--help') {
+        console.log("Usage: node recv.js <addr> (default " + address + ")");
+        process.exit(0);
+    }
+
+    address = args[0];
+}
+
+messenger.setIncomingWindow(1024);
+
+messenger.on('error', function(error) {console.log(error);});
+messenger.on('work', pumpData);
+messenger.start();
+
+messenger.subscribe(address);
+messenger.recv(); // Receive as many messages as messenger can buffer.
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/javascript/send.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.js b/examples/messenger/javascript/send.js
new file mode 100644
index 0000000..77a605c
--- /dev/null
+++ b/examples/messenger/javascript/send.js
@@ -0,0 +1,92 @@
+#!/usr/bin/env node
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("qpid-proton");
+}
+
+var address = "amqp://0.0.0.0";
+var subject = "UK.WEATHER";
+var msgtext = "Hello World!";
+var tracker = null;
+var running = true;
+
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+
+var pumpData = function() {
+    var status = messenger.status(tracker);
+    if (status != proton.Status.PENDING) {
+        if (running) {
+            messenger.stop();
+            running = false;
+        } 
+    }
+
+    if (messenger.isStopped()) {
+        message.free();
+        messenger.free();
+    }
+};
+
+var args = process.argv.slice(2);
+if (args.length > 0) {
+    if (args[0] === '-h' || args[0] === '--help') {
+        console.log("Usage: node send.js [options] [message]");
+        console.log("Options:");
+        console.log("  -a <addr> The target address [amqp[s]://domain[/name]] (default " + address + ")");
+        console.log("  -s <subject> The message subject (default " + subject + ")");
+        console.log("message A text string to send.");
+        process.exit(0);
+    }
+
+    for (var i = 0; i < args.length; i++) {
+        var arg = args[i];
+        if (arg.charAt(0) === '-') {
+            i++;
+            var val = args[i];
+            if (arg === '-a') {
+                address = val;
+            } else if (arg === '-s') {
+                subject = val;
+            }
+        } else {
+            msgtext = arg;
+        }
+    }
+}
+
+console.log("Address: " + address);
+console.log("Subject: " + subject);
+console.log("Content: " + msgtext);
+
+messenger.on('error', function(error) {console.log(error);});
+messenger.on('work', pumpData);
+messenger.setOutgoingWindow(1024);
+messenger.start();
+
+message.setAddress(address);
+message.setSubject(subject);
+message.body = msgtext;
+
+tracker = messenger.put(message);
+


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


[20/51] [abbrv] qpid-proton git commit: Update with merge of latest proton codebase and checked against latest emscripten incoming branch

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/windows/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/io.c b/proton-c/src/windows/io.c
index 2e3800b..b5660be 100644
--- a/proton-c/src/windows/io.c
+++ b/proton-c/src/windows/io.c
@@ -27,32 +27,47 @@
 #error "Proton requires Windows API support for XP or later."
 #endif
 #include <winsock2.h>
+#include <mswsock.h>
 #include <Ws2tcpip.h>
 #define PN_WINAPI
 
-#include "../platform.h"
+#include "platform.h"
 #include <proton/io.h>
 #include <proton/object.h>
+#include <proton/selector.h>
+#include "iocp.h"
+#include "util.h"
 
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <assert.h>
 
-static int pni_error_from_wsaerr(pn_error_t *error, const char *msg) {
-  errno = WSAGetLastError();
-  return pn_i_error_from_errno(error, msg);
+int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code)
+{
+  // Error code can be from GetLastError or WSAGetLastError,
+  char err[1024] = {0};
+  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
+                FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, code, 0, (LPSTR)&err, sizeof(err), NULL);
+  return pn_error_format(error, PN_ERR, "%s: %s", msg, err);
 }
 
-
-#define MAX_HOST (1024)
-#define MAX_SERV (64)
+static void io_log(const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fflush(stderr);
+}
 
 struct pn_io_t {
-  char host[MAX_HOST];
-  char serv[MAX_SERV];
+  char host[NI_MAXHOST];
+  char serv[NI_MAXSERV];
   pn_error_t *error;
+  bool trace;
   bool wouldblock;
+  iocp_t *iocp;
 };
 
 void pn_io_initialize(void *obj)
@@ -60,21 +75,24 @@ void pn_io_initialize(void *obj)
   pn_io_t *io = (pn_io_t *) obj;
   io->error = pn_error();
   io->wouldblock = false;
+  io->trace = pn_env_bool("PN_TRACE_DRV");
 
   /* Request WinSock 2.2 */
   WORD wsa_ver = MAKEWORD(2, 2);
   WSADATA unused;
   int err = WSAStartup(wsa_ver, &unused);
   if (err) {
-    pni_error_from_wsaerr(io->error, "pipe");
-    fprintf(stderr, "Can't load WinSock: %d\n", err);
+    pni_win32_error(io->error, "WSAStartup", WSAGetLastError());
+    fprintf(stderr, "Can't load WinSock: %d\n", pn_error_text(io->error));
   }
+  io->iocp = pni_iocp();
 }
 
 void pn_io_finalize(void *obj)
 {
   pn_io_t *io = (pn_io_t *) obj;
   pn_error_free(io->error);
+  pn_free(io->iocp);
   WSACleanup();
 }
 
@@ -84,7 +102,7 @@ void pn_io_finalize(void *obj)
 
 pn_io_t *pn_io(void)
 {
-  static pn_class_t clazz = PN_CLASS(pn_io);
+  static const pn_class_t clazz = PN_CLASS(pn_io);
   pn_io_t *io = (pn_io_t *) pn_new(sizeof(pn_io_t), &clazz);
   return io;
 }
@@ -100,20 +118,40 @@ pn_error_t *pn_io_error(pn_io_t *io)
   return io->error;
 }
 
+static void ensure_unique(pn_io_t *io, pn_socket_t new_socket)
+{
+  // A brand new socket can have the same HANDLE value as a previous
+  // one after a socketclose.  If the application closes one itself
+  // (i.e. not using pn_close), we don't find out about it until here.
+  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, new_socket);
+  if (iocpd) {
+    if (io->trace)
+      io_log("Stale external socket reference discarded\n");
+    // Re-use means former socket instance was closed
+    assert(iocpd->ops_in_progress == 0);
+    assert(iocpd->external);
+    // Clean up the straggler as best we can
+    pn_socket_t sock = iocpd->socket;
+    iocpd->socket = INVALID_SOCKET;
+    pni_iocpdesc_map_del(io->iocp, sock);  // may free the iocpdesc_t depending on refcount
+  }
+}
+
+
 /*
- * Windows pipes don't work with select(), so a socket based pipe
- * workaround is provided.  They do work with completion ports, so the
- * workaround can be disposed with in future.
+ * This heavyweight surrogate pipe could be replaced with a normal Windows pipe
+ * now that select() is no longer used.  If interrupt semantics are all that is
+ * needed, a simple user space counter and reserved completion status would
+ * probably suffice.
  */
-static int pni_socket_pair(SOCKET sv[2]);
+static int pni_socket_pair(pn_io_t *io, SOCKET sv[2]);
 
 int pn_pipe(pn_io_t *io, pn_socket_t *dest)
 {
-  int n = pni_socket_pair(dest);
+  int n = pni_socket_pair(io, dest);
   if (n) {
-    pni_error_from_wsaerr(io->error, "pipe");
+    pni_win32_error(io->error, "pipe", WSAGetLastError());
   }
-
   return n;
 }
 
@@ -125,9 +163,14 @@ static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
   if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) != 0) {
     perror("setsockopt");
   }
+
+  u_long nonblock = 1;
+  if (ioctlsocket(sock, FIONBIO, &nonblock)) {
+    perror("ioctlsocket");
+  }
 }
 
-static inline pn_socket_t pn_create_socket(void);
+static inline pn_socket_t pni_create_socket();
 
 pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
 {
@@ -138,34 +181,43 @@ pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
     return INVALID_SOCKET;
   }
 
-  pn_socket_t sock = pn_create_socket();
+  pn_socket_t sock = pni_create_socket();
   if (sock == INVALID_SOCKET) {
-    pni_error_from_wsaerr(io->error, "pn_create_socket");
+    pni_win32_error(io->error, "pni_create_socket", WSAGetLastError());
     return INVALID_SOCKET;
   }
+  ensure_unique(io, sock);
 
-  BOOL optval = 1;
-  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval)) == -1) {
-    pni_error_from_wsaerr(io->error, "setsockopt");
+  bool optval = 1;
+  if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char *) &optval,
+                 sizeof(optval)) == -1) {
+    pni_win32_error(io->error, "setsockopt", WSAGetLastError());
     closesocket(sock);
     return INVALID_SOCKET;
   }
 
   if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
-    pni_error_from_wsaerr(io->error, "bind");
+    pni_win32_error(io->error, "bind", WSAGetLastError());
     freeaddrinfo(addr);
     closesocket(sock);
     return INVALID_SOCKET;
   }
-
   freeaddrinfo(addr);
 
   if (listen(sock, 50) == -1) {
-    pni_error_from_wsaerr(io->error, "listen");
+    pni_win32_error(io->error, "listen", WSAGetLastError());
     closesocket(sock);
     return INVALID_SOCKET;
   }
 
+  iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
+  if (!iocpd) {
+    pn_i_error_from_errno(io->error, "register");
+    closesocket(sock);
+    return INVALID_SOCKET;
+  }
+
+  pni_iocpdesc_start(iocpd);
   return sock;
 }
 
@@ -181,66 +233,83 @@ pn_socket_t pn_connect(pn_io_t *io, const char *hostarg, const char *port)
     return INVALID_SOCKET;
   }
 
-  pn_socket_t sock = pn_create_socket();
+  pn_socket_t sock = pni_create_socket();
   if (sock == INVALID_SOCKET) {
-    pni_error_from_wsaerr(io->error, "pn_create_socket");
+    pni_win32_error(io->error, "proton pni_create_socket", WSAGetLastError());
+    freeaddrinfo(addr);
     return INVALID_SOCKET;
   }
 
+  ensure_unique(io, sock);
   pn_configure_sock(io, sock);
-
-  if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
-    if (WSAGetLastError() != WSAEWOULDBLOCK) {
-      pni_error_from_wsaerr(io->error, "connect");
-      freeaddrinfo(addr);
-      closesocket(sock);
-      return INVALID_SOCKET;
-    }
-  }
-
-  freeaddrinfo(addr);
-
-  return sock;
+  return pni_iocp_begin_connect(io->iocp, sock, addr, io->error);
 }
 
-pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size)
+pn_socket_t pn_accept(pn_io_t *io, pn_socket_t listen_sock, char *name, size_t size)
 {
   struct sockaddr_in addr = {0};
   addr.sin_family = AF_INET;
   socklen_t addrlen = sizeof(addr);
-  pn_socket_t sock = accept(socket, (struct sockaddr *) &addr, &addrlen);
-  if (sock == INVALID_SOCKET) {
-    pni_error_from_wsaerr(io->error, "accept");
-    return sock;
+  iocpdesc_t *listend = pni_iocpdesc_map_get(io->iocp, listen_sock);
+  pn_socket_t accept_sock;
+
+  if (listend)
+    accept_sock = pni_iocp_end_accept(listend, (struct sockaddr *) &addr, &addrlen, &io->wouldblock, io->error);
+  else {
+    // User supplied socket
+    accept_sock = accept(listen_sock, (struct sockaddr *) &addr, &addrlen);
+    if (accept_sock == INVALID_SOCKET)
+      pni_win32_error(io->error, "sync accept", WSAGetLastError());
+  }
+
+  if (accept_sock == INVALID_SOCKET)
+    return accept_sock;
+
+  int code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
+                         io->serv, NI_MAXSERV, 0);
+  if (code)
+    code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
+                       io->serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
+  if (code) {
+    pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
+    pn_close(io, accept_sock);
+    return INVALID_SOCKET;
   } else {
-    int code;
-    if ((code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, MAX_HOST, io->serv, MAX_SERV, 0))) {
-      pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
-      if (closesocket(sock) == -1)
-        pni_error_from_wsaerr(io->error, "closesocket");
-      return INVALID_SOCKET;
-    } else {
-      pn_configure_sock(io, sock);
-      snprintf(name, size, "%s:%s", io->host, io->serv);
-      return sock;
+    pn_configure_sock(io, accept_sock);
+    snprintf(name, size, "%s:%s", io->host, io->serv);
+    if (listend) {
+      pni_iocpdesc_start(pni_iocpdesc_map_get(io->iocp, accept_sock));
     }
+    return accept_sock;
   }
 }
 
-static inline pn_socket_t pn_create_socket(void) {
+static inline pn_socket_t pni_create_socket() {
   return socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
 }
 
 ssize_t pn_send(pn_io_t *io, pn_socket_t sockfd, const void *buf, size_t len) {
-  ssize_t count = send(sockfd, (const char *) buf, len, 0);
-  io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
+  ssize_t count;
+  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, sockfd);
+  if (iocpd) {
+    count = pni_iocp_begin_write(iocpd, buf, len, &io->wouldblock, io->error);
+  } else {
+    count = send(sockfd, (const char *) buf, len, 0);
+    io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
+  }
   return count;
 }
 
 ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
 {
-  ssize_t count = recv(socket, (char *) buf, size, 0);
-  io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
+  ssize_t count;
+  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
+  if (iocpd) {
+    count = pni_iocp_recv(iocpd, buf, size, &io->wouldblock, io->error);
+  } else {
+    count = recv(socket, (char *) buf, size, 0);
+    io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
+  }
   return count;
 }
 
@@ -257,7 +326,12 @@ ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
 
 void pn_close(pn_io_t *io, pn_socket_t socket)
 {
-  closesocket(socket);
+  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
+  if (iocpd)
+    pni_iocp_begin_close(iocpd);
+  else {
+    closesocket(socket);
+  }
 }
 
 bool pn_wouldblock(pn_io_t *io)
@@ -265,8 +339,24 @@ bool pn_wouldblock(pn_io_t *io)
   return io->wouldblock;
 }
 
+pn_selector_t *pn_io_selector(pn_io_t *io)
+{
+  if (io->iocp->selector == NULL)
+    io->iocp->selector = pni_selector_create(io->iocp);
+  return io->iocp->selector;
+}
+
+static void configure_pipe_socket(pn_io_t *io, pn_socket_t sock)
+{
+  u_long v = 1;
+  ioctlsocket (sock, FIONBIO, &v);
+  ensure_unique(io, sock);
+  iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
+  pni_iocpdesc_start(iocpd);
+}
 
-static int pni_socket_pair (SOCKET sv[2]) {
+
+static int pni_socket_pair (pn_io_t *io, SOCKET sv[2]) {
   // no socketpair on windows.  provide pipe() semantics using sockets
 
   SOCKET sock = socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
@@ -330,9 +420,9 @@ static int pni_socket_pair (SOCKET sv[2]) {
     }
   }
 
-  u_long v = 1;
-  ioctlsocket (sv[0], FIONBIO, &v);
-  ioctlsocket (sv[1], FIONBIO, &v);
+  configure_pipe_socket(io, sv[0]);
+  configure_pipe_socket(io, sv[1]);
   closesocket(sock);
   return 0;
 }
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/windows/iocp.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/iocp.c b/proton-c/src/windows/iocp.c
new file mode 100644
index 0000000..614b130
--- /dev/null
+++ b/proton-c/src/windows/iocp.c
@@ -0,0 +1,1138 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <Ws2tcpip.h>
+#define PN_WINAPI
+
+#include "../platform.h"
+#include <proton/object.h>
+#include <proton/io.h>
+#include <proton/selector.h>
+#include <proton/error.h>
+#include <proton/transport.h>
+#include "iocp.h"
+#include "util.h"
+#include <assert.h>
+
+/*
+ * Windows IO Completion Port support for Proton.
+ *
+ * Overlapped writes are used to avoid lengthy stalls between write
+ * completion and starting a new write.  Non-overlapped reads are used
+ * since Windows accumulates inbound traffic without stalling and
+ * managing read buffers would not avoid a memory copy at the pn_read
+ * boundary.
+ */
+
+// Max number of overlapped accepts per listener
+#define IOCP_MAX_ACCEPTS 10
+
+// AcceptEx squishes the local and remote addresses and optional data
+// all together when accepting the connection. Reserve enough for
+// IPv6 addresses, even if the socket is IPv4. The 16 bytes padding
+// per address is required by AcceptEx.
+#define IOCP_SOCKADDRMAXLEN (sizeof(sockaddr_in6) + 16)
+#define IOCP_SOCKADDRBUFLEN (2 * IOCP_SOCKADDRMAXLEN)
+
+static void iocp_log(const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fflush(stderr);
+}
+
+static void set_iocp_error_status(pn_error_t *error, int code, HRESULT status)
+{
+  char buf[512];
+  if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
+                    0, status, 0, buf, sizeof(buf), 0))
+    pn_error_set(error, code, buf);
+  else {
+    fprintf(stderr, "pn internal Windows error: %lu\n", GetLastError());
+  }
+}
+
+static void reap_check(iocpdesc_t *);
+static void bind_to_completion_port(iocpdesc_t *iocpd);
+static void iocp_shutdown(iocpdesc_t *iocpd);
+static void start_reading(iocpdesc_t *iocpd);
+static bool is_listener(iocpdesc_t *iocpd);
+static void release_sys_sendbuf(SOCKET s);
+
+static void iocpdesc_fail(iocpdesc_t *iocpd, HRESULT status, const char* text)
+{
+  pni_win32_error(iocpd->error, text, status);
+  if (iocpd->iocp->iocp_trace) {
+    iocp_log("connection terminated: %s\n", pn_error_text(iocpd->error));
+  }
+  if (!is_listener(iocpd) && !iocpd->write_closed && !pni_write_pipeline_size(iocpd->pipeline))
+    iocp_shutdown(iocpd);
+  iocpd->write_closed = true;
+  iocpd->read_closed = true;
+  pni_events_update(iocpd, iocpd->events | PN_READABLE | PN_WRITABLE);
+}
+
+// Helper functions to use specialized IOCP AcceptEx() and ConnectEx()
+static LPFN_ACCEPTEX lookup_accept_ex(SOCKET s)
+{
+  GUID guid = WSAID_ACCEPTEX;
+  DWORD bytes = 0;
+  LPFN_ACCEPTEX fn;
+  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+           &fn, sizeof(fn), &bytes, NULL, NULL);
+  assert(fn);
+  return fn;
+}
+
+static LPFN_CONNECTEX lookup_connect_ex(SOCKET s)
+{
+  GUID guid = WSAID_CONNECTEX;
+  DWORD bytes = 0;
+  LPFN_CONNECTEX fn;
+  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+           &fn, sizeof(fn), &bytes, NULL, NULL);
+  assert(fn);
+  return fn;
+}
+
+static LPFN_GETACCEPTEXSOCKADDRS lookup_get_accept_ex_sockaddrs(SOCKET s)
+{
+  GUID guid = WSAID_GETACCEPTEXSOCKADDRS;
+  DWORD bytes = 0;
+  LPFN_GETACCEPTEXSOCKADDRS fn;
+  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+           &fn, sizeof(fn), &bytes, NULL, NULL);
+  assert(fn);
+  return fn;
+}
+
+// match accept socket to listener socket
+static iocpdesc_t *create_same_type_socket(iocpdesc_t *iocpd)
+{
+  sockaddr_storage sa;
+  socklen_t salen = sizeof(sa);
+  if (getsockname(iocpd->socket, (sockaddr*)&sa, &salen) == -1)
+    return NULL;
+  SOCKET s = socket(sa.ss_family, SOCK_STREAM, 0); // Currently only work with SOCK_STREAM
+  if (s == INVALID_SOCKET)
+    return NULL;
+  return pni_iocpdesc_create(iocpd->iocp, s, false);
+}
+
+static bool is_listener(iocpdesc_t *iocpd)
+{
+  return iocpd && iocpd->acceptor;
+}
+
+// === Async accept processing
+
+typedef struct {
+  iocp_result_t base;
+  iocpdesc_t *new_sock;
+  char address_buffer[IOCP_SOCKADDRBUFLEN];
+  DWORD unused;
+} accept_result_t;
+
+static accept_result_t *accept_result(iocpdesc_t *listen_sock) {
+  accept_result_t *result = (accept_result_t *) pn_new(sizeof(accept_result_t), 0);
+  memset(result, 0, sizeof(accept_result_t));
+  if (result) {
+    result->base.type = IOCP_ACCEPT;
+    result->base.iocpd = listen_sock;
+  }
+  return result;
+}
+
+static void reset_accept_result(accept_result_t *result) {
+  memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
+  memset(&result->address_buffer, 0, IOCP_SOCKADDRBUFLEN);
+}
+
+struct pni_acceptor_t {
+  int accept_queue_size;
+  pn_list_t *accepts;
+  iocpdesc_t *listen_sock;
+  bool signalled;
+  LPFN_ACCEPTEX fn_accept_ex;
+  LPFN_GETACCEPTEXSOCKADDRS fn_get_accept_ex_sockaddrs;
+};
+
+#define pni_acceptor_compare NULL
+#define pni_acceptor_inspect NULL
+#define pni_acceptor_hashcode NULL
+
+static void pni_acceptor_initialize(void *object)
+{
+  pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
+  acceptor->accepts = pn_list(IOCP_MAX_ACCEPTS, 0);
+}
+
+static void pni_acceptor_finalize(void *object)
+{
+  pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
+  size_t len = pn_list_size(acceptor->accepts);
+  for (size_t i = 0; i < len; i++)
+    pn_free(pn_list_get(acceptor->accepts, i));
+  pn_free(acceptor->accepts);
+}
+
+static pni_acceptor_t *pni_acceptor(iocpdesc_t *iocpd)
+{
+  static const pn_class_t clazz = PN_CLASS(pni_acceptor);
+  pni_acceptor_t *acceptor = (pni_acceptor_t *) pn_new(sizeof(pni_acceptor_t), &clazz);
+  acceptor->listen_sock = iocpd;
+  acceptor->accept_queue_size = 0;
+  acceptor->signalled = false;
+  pn_socket_t sock = acceptor->listen_sock->socket;
+  acceptor->fn_accept_ex = lookup_accept_ex(sock);
+  acceptor->fn_get_accept_ex_sockaddrs = lookup_get_accept_ex_sockaddrs(sock);
+  return acceptor;
+}
+
+static void begin_accept(pni_acceptor_t *acceptor, accept_result_t *result)
+{
+  if (acceptor->listen_sock->closing) {
+    if (result) {
+      pn_free(result);
+      acceptor->accept_queue_size--;
+    }
+    if (acceptor->accept_queue_size == 0)
+      acceptor->signalled = true;
+    return;
+  }
+
+  if (result) {
+    reset_accept_result(result);
+  } else {
+    if (acceptor->accept_queue_size < IOCP_MAX_ACCEPTS &&
+        pn_list_size(acceptor->accepts) == acceptor->accept_queue_size ) {
+      result = accept_result(acceptor->listen_sock);
+      acceptor->accept_queue_size++;
+    } else {
+      // an async accept is still pending or max concurrent accepts already hit
+      return;
+    }
+  }
+
+  result->new_sock = create_same_type_socket(acceptor->listen_sock);
+  if (result->new_sock) {
+    // Not yet connected.
+    result->new_sock->read_closed = true;
+    result->new_sock->write_closed = true;
+
+    bool success = acceptor->fn_accept_ex(acceptor->listen_sock->socket, result->new_sock->socket,
+                     result->address_buffer, 0, IOCP_SOCKADDRMAXLEN, IOCP_SOCKADDRMAXLEN,
+                     &result->unused, (LPOVERLAPPED) result);
+    if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
+      result->base.status = WSAGetLastError();
+      pn_list_add(acceptor->accepts, result);
+      pni_events_update(acceptor->listen_sock, acceptor->listen_sock->events | PN_READABLE);
+    } else {
+      acceptor->listen_sock->ops_in_progress++;
+      // This socket is equally involved in the async operation.
+      result->new_sock->ops_in_progress++;
+    }
+  } else {
+    iocpdesc_fail(acceptor->listen_sock, WSAGetLastError(), "create accept socket");
+  }
+}
+
+static void complete_accept(accept_result_t *result, HRESULT status)
+{
+  result->new_sock->ops_in_progress--;
+  iocpdesc_t *ld = result->base.iocpd;
+  if (ld->read_closed) {
+    if (!result->new_sock->closing)
+      pni_iocp_begin_close(result->new_sock);
+    pn_free(result);    // discard
+    reap_check(ld);
+  } else {
+    result->base.status = status;
+    pn_list_add(ld->acceptor->accepts, result);
+    pni_events_update(ld, ld->events | PN_READABLE);
+  }
+}
+
+pn_socket_t pni_iocp_end_accept(iocpdesc_t *ld, sockaddr *addr, socklen_t *addrlen, bool *would_block, pn_error_t *error)
+{
+  if (!is_listener(ld)) {
+    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
+    return INVALID_SOCKET;
+  }
+  if (ld->read_closed) {
+    set_iocp_error_status(error, PN_ERR, WSAENOTSOCK);
+    return INVALID_SOCKET;
+  }
+  if (pn_list_size(ld->acceptor->accepts) == 0) {
+    if (ld->events & PN_READABLE && ld->iocp->iocp_trace)
+      iocp_log("listen socket readable with no available accept completions\n");
+    *would_block = true;
+    return INVALID_SOCKET;
+  }
+
+  accept_result_t *result = (accept_result_t *) pn_list_get(ld->acceptor->accepts, 0);
+  pn_list_del(ld->acceptor->accepts, 0, 1);
+  if (!pn_list_size(ld->acceptor->accepts))
+    pni_events_update(ld, ld->events & ~PN_READABLE);  // No pending accepts
+
+  pn_socket_t accept_sock;
+  if (result->base.status) {
+    accept_sock = INVALID_SOCKET;
+    pni_win32_error(ld->error, "accept failure", result->base.status);
+    if (ld->iocp->iocp_trace)
+      iocp_log("%s\n", pn_error_text(ld->error));
+    // App never sees this socket so close it here.
+    pni_iocp_begin_close(result->new_sock);
+  } else {
+    accept_sock = result->new_sock->socket;
+    // AcceptEx special setsockopt:
+    setsockopt(accept_sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&ld->socket,
+                  sizeof (SOCKET));
+    if (addr && addrlen && *addrlen > 0) {
+      sockaddr_storage *local_addr = NULL;
+      sockaddr_storage *remote_addr = NULL;
+      int local_addrlen, remote_addrlen;
+      LPFN_GETACCEPTEXSOCKADDRS fn = ld->acceptor->fn_get_accept_ex_sockaddrs;
+      fn(result->address_buffer, 0, IOCP_SOCKADDRMAXLEN, IOCP_SOCKADDRMAXLEN,
+         (SOCKADDR **) &local_addr, &local_addrlen, (SOCKADDR **) &remote_addr,
+         &remote_addrlen);
+      *addrlen = pn_min(*addrlen, remote_addrlen);
+      memmove(addr, remote_addr, *addrlen);
+    }
+  }
+
+  if (accept_sock != INVALID_SOCKET) {
+    // Connected.
+    result->new_sock->read_closed = false;
+    result->new_sock->write_closed = false;
+  }
+
+  // Done with the completion result, so reuse it
+  result->new_sock = NULL;
+  begin_accept(ld->acceptor, result);
+  return accept_sock;
+}
+
+
+// === Async connect processing
+
+typedef struct {
+  iocp_result_t base;
+  char address_buffer[IOCP_SOCKADDRBUFLEN];
+  struct addrinfo *addrinfo;
+} connect_result_t;
+
+#define connect_result_initialize NULL
+#define connect_result_compare NULL
+#define connect_result_inspect NULL
+#define connect_result_hashcode NULL
+
+static void connect_result_finalize(void *object)
+{
+  connect_result_t *result = (connect_result_t *) object;
+  // Do not release addrinfo until ConnectEx completes
+  if (result->addrinfo)
+    freeaddrinfo(result->addrinfo);
+}
+
+static connect_result_t *connect_result(iocpdesc_t *iocpd, struct addrinfo *addr) {
+  static const pn_class_t clazz = PN_CLASS(connect_result);
+  connect_result_t *result = (connect_result_t *) pn_new(sizeof(connect_result_t), &clazz);
+  if (result) {
+    memset(result, 0, sizeof(connect_result_t));
+    result->base.type = IOCP_CONNECT;
+    result->base.iocpd = iocpd;
+    result->addrinfo = addr;
+  }
+  return result;
+}
+
+pn_socket_t pni_iocp_begin_connect(iocp_t *iocp, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error)
+{
+  // addr lives for the duration of the async connect.  Caller has passed ownership here.
+  // See connect_result_finalize().
+  // Use of Windows-specific ConnectEx() requires our socket to be "loosely" pre-bound:
+  sockaddr_storage sa;
+  memset(&sa, 0, sizeof(sa));
+  sa.ss_family = addr->ai_family;
+  if (bind(sock, (SOCKADDR *) &sa, addr->ai_addrlen)) {
+    pni_win32_error(error, "begin async connection", WSAGetLastError());
+    if (iocp->iocp_trace)
+      iocp_log("%s\n", pn_error_text(error));
+    closesocket(sock);
+    freeaddrinfo(addr);
+    return INVALID_SOCKET;
+  }
+
+  iocpdesc_t *iocpd = pni_iocpdesc_create(iocp, sock, false);
+  bind_to_completion_port(iocpd);
+  LPFN_CONNECTEX fn_connect_ex = lookup_connect_ex(iocpd->socket);
+  connect_result_t *result = connect_result(iocpd, addr);
+  DWORD unused;
+  bool success = fn_connect_ex(iocpd->socket, result->addrinfo->ai_addr, result->addrinfo->ai_addrlen,
+                               NULL, 0, &unused, (LPOVERLAPPED) result);
+  if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
+    pni_win32_error(error, "ConnectEx failure", WSAGetLastError());
+    pn_free(result);
+    iocpd->write_closed = true;
+    iocpd->read_closed = true;
+    pni_iocp_begin_close(iocpd);
+    sock = INVALID_SOCKET;
+    if (iocp->iocp_trace)
+      iocp_log("%s\n", pn_error_text(error));
+  } else {
+    iocpd->ops_in_progress++;
+  }
+  return sock;
+}
+
+static void complete_connect(connect_result_t *result, HRESULT status)
+{
+  iocpdesc_t *iocpd = result->base.iocpd;
+  if (iocpd->closing) {
+    pn_free(result);
+    reap_check(iocpd);
+    return;
+  }
+
+  if (status) {
+    iocpdesc_fail(iocpd, status, "Connect failure");
+  } else {
+    release_sys_sendbuf(iocpd->socket);
+    if (setsockopt(iocpd->socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT,  NULL, 0)) {
+      iocpdesc_fail(iocpd, WSAGetLastError(), "Connect failure (update context)");
+    } else {
+      pni_events_update(iocpd, PN_WRITABLE);
+      start_reading(iocpd);
+    }
+  }
+  pn_free(result);
+  return;
+}
+
+
+// === Async writes
+
+static bool write_in_progress(iocpdesc_t *iocpd)
+{
+  return pni_write_pipeline_size(iocpd->pipeline) != 0;
+}
+
+write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen)
+{
+  write_result_t *result = (write_result_t *) calloc(sizeof(write_result_t), 1);
+  if (result) {
+    result->base.type = IOCP_WRITE;
+    result->base.iocpd = iocpd;
+    result->buffer.start = buf;
+    result->buffer.size = buflen;
+  }
+  return result;
+}
+
+static int submit_write(write_result_t *result, const void *buf, size_t len)
+{
+  WSABUF wsabuf;
+  wsabuf.buf = (char *) buf;
+  wsabuf.len = len;
+  memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
+  return WSASend(result->base.iocpd->socket, &wsabuf, 1, NULL, 0,
+                 (LPOVERLAPPED) result, 0);
+}
+
+ssize_t pni_iocp_begin_write(iocpdesc_t *iocpd, const void *buf, size_t len, bool *would_block, pn_error_t *error)
+{
+  if (len == 0) return 0;
+  *would_block = false;
+  if (is_listener(iocpd)) {
+    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
+    return INVALID_SOCKET;
+  }
+  if (iocpd->closing) {
+    set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
+    return SOCKET_ERROR;
+  }
+  if (iocpd->write_closed) {
+    assert(pn_error_code(iocpd->error));
+    pn_error_copy(error, iocpd->error);
+    if (iocpd->iocp->iocp_trace)
+      iocp_log("write error: %s\n", pn_error_text(error));
+    return SOCKET_ERROR;
+  }
+  if (len == 0) return 0;
+  if (!(iocpd->events & PN_WRITABLE)) {
+    *would_block = true;
+    return SOCKET_ERROR;
+  }
+
+  size_t written = 0;
+  size_t requested = len;
+  const char *outgoing = (const char *) buf;
+  size_t available = pni_write_pipeline_reserve(iocpd->pipeline, len);
+  if (!available) {
+    *would_block = true;
+    return SOCKET_ERROR;
+  }
+
+  for (size_t wr_count = 0; wr_count < available; wr_count++) {
+    write_result_t *result = pni_write_pipeline_next(iocpd->pipeline);
+    assert(result);
+    result->base.iocpd = iocpd;
+    ssize_t actual_len = pn_min(len, result->buffer.size);
+    result->requested = actual_len;
+    memmove((void *)result->buffer.start, outgoing, actual_len);
+    outgoing += actual_len;
+    written += actual_len;
+    len -= actual_len;
+
+    int werror = submit_write(result, result->buffer.start, actual_len);
+    if (werror && WSAGetLastError() != ERROR_IO_PENDING) {
+      pni_write_pipeline_return(iocpd->pipeline, result);
+      iocpdesc_fail(iocpd, WSAGetLastError(), "overlapped send");
+      return SOCKET_ERROR;
+    }
+    iocpd->ops_in_progress++;
+  }
+
+  if (!pni_write_pipeline_writable(iocpd->pipeline))
+    pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE);
+  return written;
+}
+
+static void complete_write(write_result_t *result, DWORD xfer_count, HRESULT status)
+{
+  iocpdesc_t *iocpd = result->base.iocpd;
+  if (iocpd->closing) {
+    pni_write_pipeline_return(iocpd->pipeline, result);
+    if (!iocpd->write_closed && !write_in_progress(iocpd))
+      iocp_shutdown(iocpd);
+    reap_check(iocpd);
+    return;
+  }
+  if (status == 0 && xfer_count > 0) {
+    if (xfer_count != result->requested) {
+      // Is this recoverable?  How to preserve order if multiple overlapped writes?
+      pni_write_pipeline_return(iocpd->pipeline, result);
+      iocpdesc_fail(iocpd, WSA_OPERATION_ABORTED, "Partial overlapped write on socket");
+      return;
+    } else {
+      // Success.
+      pni_write_pipeline_return(iocpd->pipeline, result);
+      if (pni_write_pipeline_writable(iocpd->pipeline))
+        pni_events_update(iocpd, iocpd->events | PN_WRITABLE);
+      return;
+    }
+  }
+  pni_write_pipeline_return(iocpd->pipeline, result);
+  iocpdesc_fail(iocpd, status, "IOCP async write error");
+}
+
+
+// === Async reads
+
+struct read_result_t {
+  iocp_result_t base;
+  size_t drain_count;
+  char unused_buf[1];
+};
+
+static read_result_t *read_result(iocpdesc_t *iocpd)
+{
+  read_result_t *result = (read_result_t *) calloc(sizeof(read_result_t), 1);
+  if (result) {
+    result->base.type = IOCP_READ;
+    result->base.iocpd = iocpd;
+  }
+  return result;
+}
+
+static void begin_zero_byte_read(iocpdesc_t *iocpd)
+{
+  if (iocpd->read_in_progress) return;
+  if (iocpd->read_closed) {
+    pni_events_update(iocpd, iocpd->events | PN_READABLE);
+    return;
+  }
+
+  read_result_t *result = iocpd->read_result;
+  memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
+  DWORD flags = 0;
+  WSABUF wsabuf;
+  wsabuf.buf = result->unused_buf;
+  wsabuf.len = 0;
+  int rc = WSARecv(iocpd->socket, &wsabuf, 1, NULL, &flags,
+                       &result->base.overlapped, 0);
+  if (rc && WSAGetLastError() != ERROR_IO_PENDING) {
+    iocpdesc_fail(iocpd, WSAGetLastError(), "IOCP read error");
+    return;
+  }
+  iocpd->ops_in_progress++;
+  iocpd->read_in_progress = true;
+}
+
+static void drain_until_closed(iocpdesc_t *iocpd) {
+  int max_drain = 16 * 1024;
+  char buf[512];
+  read_result_t *result = iocpd->read_result;
+  while (result->drain_count < max_drain) {
+    int rv = recv(iocpd->socket, buf, 512, 0);
+    if (rv > 0)
+      result->drain_count += rv;
+    else if (rv == 0) {
+      iocpd->read_closed = true;
+      return;
+    } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
+      // wait a little longer
+      start_reading(iocpd);
+      return;
+    }
+    else
+      break;
+  }
+  // Graceful close indication unlikely, force the issue
+  if (iocpd->iocp->iocp_trace)
+    if (result->drain_count >= max_drain)
+      iocp_log("graceful close on reader abandoned (too many chars)\n");
+    else
+      iocp_log("graceful close on reader abandoned: %d\n", WSAGetLastError());
+  iocpd->read_closed = true;
+  closesocket(iocpd->socket);
+  iocpd->socket = INVALID_SOCKET;
+}
+
+
+static void complete_read(read_result_t *result, DWORD xfer_count, HRESULT status)
+{
+  iocpdesc_t *iocpd = result->base.iocpd;
+  iocpd->read_in_progress = false;
+
+  if (iocpd->closing) {
+    // Application no longer reading, but we are looking for a zero length read
+    if (!iocpd->read_closed)
+      drain_until_closed(iocpd);
+    reap_check(iocpd);
+    return;
+  }
+
+  if (status == 0 && xfer_count == 0) {
+    // Success.
+    pni_events_update(iocpd, iocpd->events | PN_READABLE);
+  } else {
+    iocpdesc_fail(iocpd, status, "IOCP read complete error");
+  }
+}
+
+ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error)
+{
+  if (size == 0) return 0;
+  *would_block = false;
+  if (is_listener(iocpd)) {
+    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
+    return SOCKET_ERROR;
+  }
+  if (iocpd->closing) {
+    // Previous call to pn_close()
+    set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
+    return SOCKET_ERROR;
+  }
+  if (iocpd->read_closed) {
+    if (pn_error_code(iocpd->error))
+      pn_error_copy(error, iocpd->error);
+    else
+      set_iocp_error_status(error, PN_ERR, WSAENOTCONN);
+    return SOCKET_ERROR;
+  }
+
+  size_t count = recv(iocpd->socket, (char *) buf, size, 0);
+  if (count > 0) {
+    pni_events_update(iocpd, iocpd->events & ~PN_READABLE);
+    begin_zero_byte_read(iocpd);
+    return count;
+  } else if (count == 0) {
+    iocpd->read_closed = true;
+    return 0;
+  }
+  if (WSAGetLastError() == WSAEWOULDBLOCK)
+    *would_block = true;
+  else
+    set_iocp_error_status(error, PN_ERR, WSAGetLastError());
+  return SOCKET_ERROR;
+}
+
+static void start_reading(iocpdesc_t *iocpd)
+{
+  begin_zero_byte_read(iocpd);
+}
+
+
+// === The iocp descriptor
+
+static void pni_iocpdesc_initialize(void *object)
+{
+  iocpdesc_t *iocpd = (iocpdesc_t *) object;
+  memset(iocpd, 0, sizeof(iocpdesc_t));
+  iocpd->socket = INVALID_SOCKET;
+}
+
+static void pni_iocpdesc_finalize(void *object)
+{
+  iocpdesc_t *iocpd = (iocpdesc_t *) object;
+  pn_free(iocpd->acceptor);
+  pn_error_free(iocpd->error);
+   if (iocpd->pipeline)
+    if (write_in_progress(iocpd))
+      iocp_log("iocp descriptor write leak\n");
+    else
+      pn_free(iocpd->pipeline);
+  if (iocpd->read_in_progress)
+    iocp_log("iocp descriptor read leak\n");
+  else
+    free(iocpd->read_result);
+}
+
+static uintptr_t pni_iocpdesc_hashcode(void *object)
+{
+  iocpdesc_t *iocpd = (iocpdesc_t *) object;
+  return iocpd->socket;
+}
+
+#define pni_iocpdesc_compare NULL
+#define pni_iocpdesc_inspect NULL
+
+// Reference counted in the iocpdesc map, zombie_list, selector.
+static iocpdesc_t *pni_iocpdesc(pn_socket_t s)
+{
+  static pn_class_t clazz = PN_CLASS(pni_iocpdesc);
+  assert (s != INVALID_SOCKET);
+  iocpdesc_t *iocpd = (iocpdesc_t *) pn_new(sizeof(iocpdesc_t), &clazz);
+  assert(iocpd);
+  iocpd->socket = s;
+  return iocpd;
+}
+
+static bool is_listener_socket(pn_socket_t s)
+{
+  BOOL tval = false;
+  int tvalsz = sizeof(tval);
+  int code = getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char *)&tval, &tvalsz);
+  return code == 0 && tval;
+}
+
+iocpdesc_t *pni_iocpdesc_create(iocp_t *iocp, pn_socket_t s, bool external) {
+  assert(!pni_iocpdesc_map_get(iocp, s));
+  bool listening = is_listener_socket(s);
+  iocpdesc_t *iocpd = pni_iocpdesc(s);
+  iocpd->iocp = iocp;
+  if (iocpd) {
+    iocpd->external = external;
+    iocpd->error = pn_error();
+    if (listening) {
+      iocpd->acceptor = pni_acceptor(iocpd);
+    } else {
+      iocpd->pipeline = pni_write_pipeline(iocpd);
+      iocpd->read_result = read_result(iocpd);
+    }
+    pni_iocpdesc_map_push(iocpd);
+  }
+  return iocpd;
+}
+
+// === Fast lookup of a socket's iocpdesc_t
+
+iocpdesc_t *pni_iocpdesc_map_get(iocp_t *iocp, pn_socket_t s) {
+  iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_get(iocp->iocpdesc_map, s);
+  return iocpd;
+}
+
+void pni_iocpdesc_map_push(iocpdesc_t *iocpd) {
+  pn_hash_put(iocpd->iocp->iocpdesc_map, iocpd->socket, iocpd);
+  pn_decref(iocpd);
+  assert(pn_refcount(iocpd) == 1);
+}
+
+void pni_iocpdesc_map_del(iocp_t *iocp, pn_socket_t s) {
+  pn_hash_del(iocp->iocpdesc_map, (uintptr_t) s);
+}
+
+static void bind_to_completion_port(iocpdesc_t *iocpd)
+{
+  if (iocpd->bound) return;
+  if (!iocpd->iocp->completion_port) {
+    iocpdesc_fail(iocpd, WSAEINVAL, "Incomplete setup, no completion port.");
+    return;
+  }
+
+  if (CreateIoCompletionPort ((HANDLE) iocpd->socket, iocpd->iocp->completion_port, 0, 0))
+    iocpd->bound = true;
+  else {
+    iocpdesc_fail(iocpd, GetLastError(), "IOCP socket setup.");
+  }
+}
+
+static void release_sys_sendbuf(SOCKET s)
+{
+  // Set the socket's send buffer size to zero.
+  int sz = 0;
+  int status = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char *)&sz, sizeof(int));
+  assert(status == 0);
+}
+
+void pni_iocpdesc_start(iocpdesc_t *iocpd)
+{
+  if (iocpd->bound) return;
+  bind_to_completion_port(iocpd);
+  if (is_listener(iocpd)) {
+    begin_accept(iocpd->acceptor, NULL);
+  }
+  else {
+    release_sys_sendbuf(iocpd->socket);
+    pni_events_update(iocpd, PN_WRITABLE);
+    start_reading(iocpd);
+  }
+}
+
+static void complete(iocp_result_t *result, bool success, DWORD num_transferred) {
+  result->iocpd->ops_in_progress--;
+  DWORD status = success ? 0 : GetLastError();
+
+  switch (result->type) {
+  case IOCP_ACCEPT:
+    complete_accept((accept_result_t *) result, status);
+    break;
+  case IOCP_CONNECT:
+    complete_connect((connect_result_t *) result, status);
+    break;
+  case IOCP_WRITE:
+    complete_write((write_result_t *) result, num_transferred, status);
+    break;
+  case IOCP_READ:
+    complete_read((read_result_t *) result, num_transferred, status);
+    break;
+  default:
+    assert(false);
+  }
+}
+
+void pni_iocp_drain_completions(iocp_t *iocp)
+{
+  while (true) {
+    DWORD timeout_ms = 0;
+    DWORD num_transferred = 0;
+    ULONG_PTR completion_key = 0;
+    OVERLAPPED *overlapped = 0;
+
+    bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
+                                               &completion_key, &overlapped, timeout_ms);
+    if (!overlapped)
+      return;  // timed out
+    iocp_result_t *result = (iocp_result_t *) overlapped;
+    complete(result, good_op, num_transferred);
+  }
+}
+
+// returns: -1 on error, 0 on timeout, 1 successful completion
+int pni_iocp_wait_one(iocp_t *iocp, int timeout, pn_error_t *error) {
+  DWORD win_timeout = (timeout < 0) ? INFINITE : (DWORD) timeout;
+  DWORD num_transferred = 0;
+  ULONG_PTR completion_key = 0;
+  OVERLAPPED *overlapped = 0;
+
+  bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
+                                            &completion_key, &overlapped, win_timeout);
+  if (!overlapped)
+    if (GetLastError() == WAIT_TIMEOUT)
+      return 0;
+    else {
+      if (error)
+        pni_win32_error(error, "GetQueuedCompletionStatus", GetLastError());
+      return -1;
+    }
+
+  iocp_result_t *result = (iocp_result_t *) overlapped;
+  complete(result, good_op, num_transferred);
+  return 1;
+}
+
+// === Close (graceful and otherwise)
+
+// zombie_list is for sockets transitioning out of iocp on their way to zero ops_in_progress
+// and fully closed.
+
+static void zombie_list_add(iocpdesc_t *iocpd)
+{
+  assert(iocpd->closing);
+  if (!iocpd->ops_in_progress) {
+    // No need to make a zombie.
+    if (iocpd->socket != INVALID_SOCKET) {
+      closesocket(iocpd->socket);
+      iocpd->socket = INVALID_SOCKET;
+      iocpd->read_closed = true;
+    }
+    return;
+  }
+  // Allow 2 seconds for graceful shutdown before releasing socket resource.
+  iocpd->reap_time = pn_i_now() + 2000;
+  pn_list_add(iocpd->iocp->zombie_list, iocpd);
+}
+
+static void reap_check(iocpdesc_t *iocpd)
+{
+  if (iocpd->closing && !iocpd->ops_in_progress) {
+    if (iocpd->socket != INVALID_SOCKET) {
+      closesocket(iocpd->socket);
+      iocpd->socket = INVALID_SOCKET;
+    }
+    pn_list_remove(iocpd->iocp->zombie_list, iocpd);
+    // iocpd is decref'ed and possibly released
+  }
+}
+
+pn_timestamp_t pni_zombie_deadline(iocp_t *iocp)
+{
+  if (pn_list_size(iocp->zombie_list)) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, 0);
+    return iocpd->reap_time;
+  }
+  return 0;
+}
+
+void pni_zombie_check(iocp_t *iocp, pn_timestamp_t now)
+{
+  pn_list_t *zl = iocp->zombie_list;
+  // Look for stale zombies that should have been reaped by "now"
+  for (size_t idx = 0; idx < pn_list_size(zl); idx++) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(zl, idx);
+    if (iocpd->reap_time > now)
+      return;
+    if (iocpd->socket == INVALID_SOCKET)
+      continue;
+    assert(iocpd->ops_in_progress > 0);
+    if (iocp->iocp_trace)
+      iocp_log("async close: graceful close timeout exceeded\n");
+    closesocket(iocpd->socket);
+    iocpd->socket = INVALID_SOCKET;
+    iocpd->read_closed = true;
+    // outstanding ops should complete immediately now
+  }
+}
+
+static void drain_zombie_completions(iocp_t *iocp)
+{
+  // No more pn_selector_select() from App, but zombies still need care and feeding
+  // until their outstanding async actions complete.
+  pni_iocp_drain_completions(iocp);
+
+  // Discard any that have no pending async IO
+  size_t sz = pn_list_size(iocp->zombie_list);
+  for (size_t idx = 0; idx < sz;) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, idx);
+    if (!iocpd->ops_in_progress) {
+      pn_list_del(iocp->zombie_list, idx, 1);
+      sz--;
+    } else {
+      idx++;
+    }
+  }
+
+  pn_timestamp_t now = pn_i_now();
+  pn_timestamp_t deadline = now + 2000;
+
+  while (pn_list_size(iocp->zombie_list)) {
+    if (now >= deadline)
+      break;
+    int rv = pni_iocp_wait_one(iocp, deadline - now, NULL);
+    if (rv < 0) {
+      iocp_log("unexpected IOCP failure on Proton IO shutdown %d\n", GetLastError());
+      break;
+    }
+    now = pn_i_now();
+  }
+  if (now >= deadline && pn_list_size(iocp->zombie_list))
+    // Should only happen if really slow TCP handshakes, i.e. total network failure
+    iocp_log("network failure on Proton shutdown\n");
+}
+
+static pn_list_t *iocp_map_close_all(iocp_t *iocp)
+{
+  // Zombify stragglers, i.e. no pn_close() from the application.
+  pn_list_t *externals = pn_list(0, PN_REFCOUNT);
+  for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
+       entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
+    // Just listeners first.
+    if (is_listener(iocpd)) {
+      if (iocpd->external) {
+        // Owned by application, just keep a temporary reference to it.
+        // iocp_result_t structs must not be free'd until completed or
+        // the completion port is closed.
+        if (iocpd->ops_in_progress)
+          pn_list_add(externals, iocpd);
+        pni_iocpdesc_map_del(iocp, iocpd->socket);
+      } else {
+        // Make it a zombie.
+        pni_iocp_begin_close(iocpd);
+      }
+    }
+  }
+  pni_iocp_drain_completions(iocp);
+
+  for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
+       entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
+    if (iocpd->external) {
+      iocpd->read_closed = true;   // Do not consume from read side
+      iocpd->write_closed = true;  // Do not shutdown write side
+      if (iocpd->ops_in_progress)
+        pn_list_add(externals, iocpd);
+      pni_iocpdesc_map_del(iocp, iocpd->socket);
+    } else {
+      // Make it a zombie.
+      pni_iocp_begin_close(iocpd);
+    }
+  }
+  return externals;
+}
+
+static void zombie_list_hard_close_all(iocp_t *iocp)
+{
+  pni_iocp_drain_completions(iocp);
+  size_t zs = pn_list_size(iocp->zombie_list);
+  for (size_t i = 0; i < zs; i++) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, i);
+    if (iocpd->socket != INVALID_SOCKET) {
+      closesocket(iocpd->socket);
+      iocpd->socket = INVALID_SOCKET;
+      iocpd->read_closed = true;
+      iocpd->write_closed = true;
+    }
+  }
+  pni_iocp_drain_completions(iocp);
+
+  // Zombies should be all gone.  Do a sanity check.
+  zs = pn_list_size(iocp->zombie_list);
+  int remaining = 0;
+  int ops = 0;
+  for (size_t i = 0; i < zs; i++) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, i);
+    remaining++;
+    ops += iocpd->ops_in_progress;
+  }
+  if (remaining)
+    iocp_log("Proton: %d unfinished close operations (ops count = %d)\n", remaining, ops);
+}
+
+static void iocp_shutdown(iocpdesc_t *iocpd)
+{
+  if (shutdown(iocpd->socket, SD_SEND)) {
+    if (iocpd->iocp->iocp_trace)
+      iocp_log("socket shutdown failed %d\n", WSAGetLastError());
+  }
+  iocpd->write_closed = true;
+  if (iocpd->read_closed) {
+    closesocket(iocpd->socket);
+    iocpd->socket = INVALID_SOCKET;
+  }
+}
+
+void pni_iocp_begin_close(iocpdesc_t *iocpd)
+{
+  assert (!iocpd->closing);
+  if (is_listener(iocpd)) {
+    // Listening socket is easy.  Close the socket which will cancel async ops.
+    pn_socket_t old_sock = iocpd->socket;
+    iocpd->socket = INVALID_SOCKET;
+    iocpd->closing = true;
+    iocpd->read_closed = true;
+    iocpd->write_closed = true;
+    closesocket(old_sock);
+    // Pending accepts will now complete.  Zombie can die when all consumed.
+    zombie_list_add(iocpd);
+    pni_iocpdesc_map_del(iocpd->iocp, old_sock);  // may pn_free *iocpd
+  } else {
+    // Continue async operation looking for graceful close confirmation or timeout.
+    pn_socket_t old_sock = iocpd->socket;
+    iocpd->closing = true;
+    if (!iocpd->write_closed && !write_in_progress(iocpd))
+      iocp_shutdown(iocpd);
+    zombie_list_add(iocpd);
+    pni_iocpdesc_map_del(iocpd->iocp, old_sock);  // may pn_free *iocpd
+  }
+}
+
+
+// === iocp_t
+
+#define pni_iocp_hashcode NULL
+#define pni_iocp_compare NULL
+#define pni_iocp_inspect NULL
+
+void pni_iocp_initialize(void *obj)
+{
+  iocp_t *iocp = (iocp_t *) obj;
+  memset(iocp, 0, sizeof(iocp_t));
+  pni_shared_pool_create(iocp);
+  iocp->completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
+  assert(iocp->completion_port != NULL);
+  iocp->iocpdesc_map = pn_hash(0, 0.75, PN_REFCOUNT);
+  iocp->zombie_list = pn_list(0, PN_REFCOUNT);
+  iocp->iocp_trace = pn_env_bool("PN_TRACE_DRV");
+  iocp->selector = NULL;
+}
+
+void pni_iocp_finalize(void *obj)
+{
+  iocp_t *iocp = (iocp_t *) obj;
+  // Move sockets to closed state, except external sockets.
+  pn_list_t *externals = iocp_map_close_all(iocp);
+  // Now everything with ops_in_progress is in the zombie_list or the externals list.
+  assert(!pn_hash_head(iocp->iocpdesc_map));
+  pn_free(iocp->iocpdesc_map);
+
+  drain_zombie_completions(iocp);    // Last chance for graceful close
+  zombie_list_hard_close_all(iocp);
+  CloseHandle(iocp->completion_port);  // This cancels all our async ops
+  iocp->completion_port = NULL;
+
+  if (pn_list_size(externals) && iocp->iocp_trace)
+    iocp_log("%d external sockets not closed and removed from Proton IOCP control\n", pn_list_size(externals));
+
+  // Now safe to free everything that might be touched by a former async operation.
+  pn_free(externals);
+  pn_free(iocp->zombie_list);
+  pni_shared_pool_free(iocp);
+}
+
+iocp_t *pni_iocp()
+{
+  static const pn_class_t clazz = PN_CLASS(pni_iocp);
+  iocp_t *iocp = (iocp_t *) pn_new(sizeof(iocp_t), &clazz);
+  return iocp;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/windows/iocp.h
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/iocp.h b/proton-c/src/windows/iocp.h
new file mode 100644
index 0000000..bc64dd0
--- /dev/null
+++ b/proton-c/src/windows/iocp.h
@@ -0,0 +1,141 @@
+#ifndef PROTON_SRC_IOCP_H
+#define PROTON_SRC_IOCP_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/import_export.h>
+#include <proton/selectable.h>
+#include <proton/type_compat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pni_acceptor_t pni_acceptor_t;
+typedef struct write_result_t write_result_t;
+typedef struct read_result_t read_result_t;
+typedef struct write_pipeline_t write_pipeline_t;
+typedef struct iocpdesc_t iocpdesc_t;
+
+
+// One per pn_io_t.
+
+struct iocp_t {
+  HANDLE completion_port;
+  pn_hash_t *iocpdesc_map;
+  pn_list_t *zombie_list;
+  int shared_pool_size;
+  char *shared_pool_memory;
+  write_result_t **shared_results;
+  write_result_t **available_results;
+  int shared_available_count;
+  size_t writer_count;
+  int loopback_bufsize;
+  bool iocp_trace;
+  pn_selector_t *selector;
+};
+
+
+// One for each socket.
+// This iocpdesc_t structure is ref counted by the iocpdesc_map, zombie_list,
+// selector->iocp_descriptors list.  It should remain ref counted in the
+// zombie_list until ops_in_progress == 0 or the completion port is closed.
+
+struct iocpdesc_t {
+  pn_socket_t socket;
+  iocp_t *iocp;
+  pni_acceptor_t *acceptor;
+  pn_error_t *error;
+  int ops_in_progress;
+  bool read_in_progress;
+  write_pipeline_t *pipeline;
+  read_result_t *read_result;
+  bool external;       // true if socket set up outside Proton
+  bool bound;          // associted with the completion port
+  bool closing;        // pn_close called
+  bool read_closed;    // EOF or read error
+  bool write_closed;   // shutdown sent or write error
+  pn_selector_t *selector;
+  pn_selectable_t *selectable;
+  int events;
+  int interests;
+  pn_timestamp_t deadline;
+  iocpdesc_t *triggered_list_next;
+  iocpdesc_t *triggered_list_prev;
+  iocpdesc_t *deadlines_next;
+  iocpdesc_t *deadlines_prev;
+  pn_timestamp_t reap_time;;
+};
+
+typedef enum { IOCP_ACCEPT, IOCP_CONNECT, IOCP_READ, IOCP_WRITE } iocp_type_t;
+
+typedef struct {
+  OVERLAPPED overlapped;
+  iocp_type_t type;
+  iocpdesc_t *iocpd;
+  HRESULT status;
+} iocp_result_t;
+
+struct write_result_t {
+  iocp_result_t base;
+  size_t requested;
+  bool in_use;
+  pn_bytes_t buffer;
+};
+
+iocpdesc_t *pni_iocpdesc_create(iocp_t *, pn_socket_t s, bool external);
+iocpdesc_t *pni_iocpdesc_map_get(iocp_t *, pn_socket_t s);
+void pni_iocpdesc_map_del(iocp_t *, pn_socket_t s);
+void pni_iocpdesc_map_push(iocpdesc_t *iocpd);
+void pni_iocpdesc_start(iocpdesc_t *iocpd);
+void pni_iocp_drain_completions(iocp_t *);
+int pni_iocp_wait_one(iocp_t *, int timeout, pn_error_t *);
+void pni_iocp_start_accepting(iocpdesc_t *iocpd);
+pn_socket_t pni_iocp_end_accept(iocpdesc_t *ld, sockaddr *addr, socklen_t *addrlen, bool *would_block, pn_error_t *error);
+pn_socket_t pni_iocp_begin_connect(iocp_t *, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error);
+ssize_t pni_iocp_begin_write(iocpdesc_t *, const void *, size_t, bool *, pn_error_t *);
+ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error);
+void pni_iocp_begin_close(iocpdesc_t *iocpd);
+iocp_t *pni_iocp();
+
+void pni_events_update(iocpdesc_t *iocpd, int events);
+write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen);
+write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd);
+size_t pni_write_pipeline_size(write_pipeline_t *);
+bool pni_write_pipeline_writable(write_pipeline_t *);
+void pni_write_pipeline_return(write_pipeline_t *, write_result_t *);
+size_t pni_write_pipeline_reserve(write_pipeline_t *, size_t);
+write_result_t *pni_write_pipeline_next(write_pipeline_t *);
+void pni_shared_pool_create(iocp_t *);
+void pni_shared_pool_free(iocp_t *);
+void pni_zombie_check(iocp_t *, pn_timestamp_t);
+pn_timestamp_t pni_zombie_deadline(iocp_t *);
+
+pn_selector_t *pni_selector_create(iocp_t *iocp);
+
+int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* iocp.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/windows/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/selector.c b/proton-c/src/windows/selector.c
index 2d1b855..b01c27a 100644
--- a/proton-c/src/windows/selector.c
+++ b/proton-c/src/windows/selector.c
@@ -19,21 +19,6 @@
  *
  */
 
-/*
- * Copy of posix poll-based selector with minimal changes to use
- * select().  TODO: fully native implementaton with I/O completion
- * ports.
- *
- * This implementation comments out the posix max_fds arg to select
- * which has no meaning on windows.  The number of fd_set slots are
- * configured at compile time via FD_SETSIZE, chosen "large enough"
- * for the limited scalability of select() at the expense of
- * 3*N*sizeof(unsigned int) bytes per driver instance.  select (and
- * associated macros like FD_ZERO) are otherwise unaffected
- * performance-wise by increasing FD_SETSIZE.
- */
-
-#define FD_SETSIZE 2048
 #ifndef _WIN32_WINNT
 #define _WIN32_WINNT 0x0501
 #endif
@@ -44,37 +29,53 @@
 #include <Ws2tcpip.h>
 #define PN_WINAPI
 
-#include "../platform.h"
+#include "platform.h"
+#include <proton/object.h>
 #include <proton/io.h>
 #include <proton/selector.h>
 #include <proton/error.h>
 #include <assert.h>
-#include "../selectable.h"
-#include "../util.h"
+#include "selectable.h"
+#include "util.h"
+#include "iocp.h"
+
+static void interests_update(iocpdesc_t *iocpd, int interests);
+static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t t);
 
 struct pn_selector_t {
-  fd_set readfds;
-  fd_set writefds;
-  fd_set exceptfds;
+  iocp_t *iocp;
   pn_timestamp_t *deadlines;
   size_t capacity;
   pn_list_t *selectables;
+  pn_list_t *iocp_descriptors;
   pn_timestamp_t deadline;
   size_t current;
+  iocpdesc_t *current_triggered;
   pn_timestamp_t awoken;
   pn_error_t *error;
+  iocpdesc_t *triggered_list_head;
+  iocpdesc_t *triggered_list_tail;
+  iocpdesc_t *deadlines_head;
+  iocpdesc_t *deadlines_tail;
 };
 
 void pn_selector_initialize(void *obj)
 {
   pn_selector_t *selector = (pn_selector_t *) obj;
+  selector->iocp = NULL;
   selector->deadlines = NULL;
   selector->capacity = 0;
   selector->selectables = pn_list(0, 0);
+  selector->iocp_descriptors = pn_list(0, PN_REFCOUNT);
   selector->deadline = 0;
   selector->current = 0;
+  selector->current_triggered = NULL;
   selector->awoken = 0;
   selector->error = pn_error();
+  selector->triggered_list_head = NULL;
+  selector->triggered_list_tail = NULL;
+  selector->deadlines_head = NULL;
+  selector->deadlines_tail = NULL;
 }
 
 void pn_selector_finalize(void *obj)
@@ -82,28 +83,51 @@ void pn_selector_finalize(void *obj)
   pn_selector_t *selector = (pn_selector_t *) obj;
   free(selector->deadlines);
   pn_free(selector->selectables);
+  pn_free(selector->iocp_descriptors);
   pn_error_free(selector->error);
+  selector->iocp->selector = NULL;
 }
 
 #define pn_selector_hashcode NULL
 #define pn_selector_compare NULL
 #define pn_selector_inspect NULL
 
-pn_selector_t *pn_selector(void)
+pn_selector_t *pni_selector()
 {
-  static pn_class_t clazz = PN_CLASS(pn_selector);
+  static const pn_class_t clazz = PN_CLASS(pn_selector);
   pn_selector_t *selector = (pn_selector_t *) pn_new(sizeof(pn_selector_t), &clazz);
   return selector;
 }
 
+pn_selector_t *pni_selector_create(iocp_t *iocp)
+{
+  pn_selector_t *selector = pni_selector();
+  selector->iocp = iocp;
+  return selector;
+}
+
 void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable)
 {
   assert(selector);
   assert(selectable);
   assert(pni_selectable_get_index(selectable) < 0);
+  pn_socket_t sock = pn_selectable_fd(selectable);
+
+  iocpdesc_t *iocpd = NULL;
+  if (sock != INVALID_SOCKET) {
+    iocpd = pni_iocpdesc_map_get(selector->iocp, sock);
+    if (!iocpd) {
+      // Socket created outside proton.  Hook it up to iocp.
+      iocpd = pni_iocpdesc_create(selector->iocp, sock, true);
+      pni_iocpdesc_start(iocpd);
+    } else {
+      assert(iocpd->iocp == selector->iocp);
+    }
+  }
 
   if (pni_selectable_get_index(selectable) < 0) {
     pn_list_add(selector->selectables, selectable);
+    pn_list_add(selector->iocp_descriptors, iocpd);
     size_t size = pn_list_size(selector->selectables);
 
     if (selector->capacity < size) {
@@ -112,6 +136,10 @@ void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable)
     }
 
     pni_selectable_set_index(selectable, size - 1);
+    if (iocpd) {
+      iocpd->selector = selector;
+      iocpd->selectable = selectable;
+    }
   }
 
   pn_selector_update(selector, selectable);
@@ -121,18 +149,22 @@ void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable)
 {
   int idx = pni_selectable_get_index(selectable);
   assert(idx >= 0);
- /*
-  selector->fds[idx].fd = pn_selectable_fd(selectable);
-  selector->fds[idx].events = 0;
-  selector->fds[idx].revents = 0;
-  if (pn_selectable_capacity(selectable) > 0) {
-    selector->fds[idx].events |= POLLIN;
-  }
-  if (pn_selectable_pending(selectable) > 0) {
-    selector->fds[idx].events |= POLLOUT;
-  }
- */
   selector->deadlines[idx] = pn_selectable_deadline(selectable);
+
+  pn_socket_t sock = pn_selectable_fd(selectable);
+  iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(selector->iocp_descriptors, idx);
+  if (iocpd) {
+    assert(sock == iocpd->socket || iocpd->closing);
+    int interests = 0;
+    if (pn_selectable_capacity(selectable) > 0) {
+      interests |= PN_READABLE;
+    }
+    if (pn_selectable_pending(selectable) > 0) {
+      interests |= PN_WRITABLE;
+    }
+    interests_update(iocpd, interests);
+    deadlines_update(iocpd, selector->deadlines[idx]);
+  }
 }
 
 void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable)
@@ -142,107 +174,94 @@ void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable)
 
   int idx = pni_selectable_get_index(selectable);
   assert(idx >= 0);
+  iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(selector->iocp_descriptors, idx);
+  if (iocpd) {
+    if (selector->current_triggered == iocpd)
+      selector->current_triggered = iocpd->triggered_list_next;
+    interests_update(iocpd, 0);
+    deadlines_update(iocpd, 0);
+    assert(selector->triggered_list_head != iocpd && !iocpd->triggered_list_prev);
+    assert(selector->deadlines_head != iocpd && !iocpd->deadlines_prev);
+    iocpd->selector = NULL;
+    iocpd->selectable = NULL;
+  }
   pn_list_del(selector->selectables, idx, 1);
+  pn_list_del(selector->iocp_descriptors, idx, 1);
   size_t size = pn_list_size(selector->selectables);
   for (size_t i = idx; i < size; i++) {
     pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(selector->selectables, i);
     pni_selectable_set_index(sel, i);
   }
-
   pni_selectable_set_index(selectable, -1);
 }
 
 int pn_selector_select(pn_selector_t *selector, int timeout)
 {
   assert(selector);
-
-  FD_ZERO(&selector->readfds);
-  FD_ZERO(&selector->writefds);
-  FD_ZERO(&selector->exceptfds);
-
-  size_t size = pn_list_size(selector->selectables);
-  if (size > FD_SETSIZE) {
-    // This Windows limitation will go away when switching to completion ports
-    pn_error_set(selector->error, PN_ERR, "maximum sockets exceeded for Windows selector");
-    return PN_ERR;
-  }
+  pn_error_clear(selector->error);
+  pn_timestamp_t deadline = 0;
+  pn_timestamp_t now = pn_i_now();
 
   if (timeout) {
-    pn_timestamp_t deadline = 0;
-    for (size_t i = 0; i < size; i++) {
-      pn_timestamp_t d = selector->deadlines[i];
-      if (d)
-        deadline = (deadline == 0) ? d : pn_min(deadline, d);
-    }
-
-    if (deadline) {
-      pn_timestamp_t now = pn_i_now();
-      int delta = selector->deadline - now;
-      if (delta < 0) {
-        timeout = 0;
-      } else if (delta < timeout) {
-        timeout = delta;
-      }
-    }
+    if (selector->deadlines_head)
+      deadline = selector->deadlines_head->deadline;
   }
+  if (deadline) {
+    int delta = deadline - now;
+    if (delta < 0) {
+      delta = 0;
+    } 
+    if (timeout < 0)
+      timeout = delta;
+    else if (timeout > delta)
+      timeout = delta;
+  }	
+  deadline = (timeout >= 0) ? now + timeout : 0;
 
-  struct timeval to = {0};
-  struct timeval *to_arg = &to;
-  // block only if (timeout == 0) and (closed_count == 0)
-  if (timeout > 0) {
-    // convert millisecs to sec and usec:
-    to.tv_sec = timeout/1000;
-    to.tv_usec = (timeout - (to.tv_sec * 1000)) * 1000;
-  }
-  else if (timeout < 0) {
-    to_arg = NULL;
-  }
+  // Process all currently available completions, even if matched events available
+  pni_iocp_drain_completions(selector->iocp);
+  pni_zombie_check(selector->iocp, now);
+  // Loop until an interested event is matched, or until deadline
+  while (true) {
+    if (selector->triggered_list_head)
+      break;
+    if (deadline && deadline <= now)
+      break;
+    pn_timestamp_t completion_deadline = deadline;
+    pn_timestamp_t zd = pni_zombie_deadline(selector->iocp);
+    if (zd)
+      completion_deadline = completion_deadline ? pn_min(zd, completion_deadline) : zd;
 
-  for (size_t i = 0; i < size; i++) {
-    pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(selector->selectables, i);
-    pn_socket_t fd = pn_selectable_fd(sel);
-    if (pn_selectable_capacity(sel) > 0) {
-      FD_SET(fd, &selector->readfds);
-    }
-    if (pn_selectable_pending(sel) > 0) {
-      FD_SET(fd, &selector->writefds);
+    int completion_timeout = (!completion_deadline) ? -1 : completion_deadline - now;
+    int rv = pni_iocp_wait_one(selector->iocp, completion_timeout, selector->error);
+    if (rv < 0)
+      return pn_error_code(selector->error);
+
+    now = pn_i_now();
+    if (zd && zd <= now) {
+      pni_zombie_check(selector->iocp, now);
     }
   }
 
-  int result = select(0 /* ignored in win32 */, &selector->readfds, &selector->writefds, &selector->exceptfds, to_arg);
-  if (result == -1) {
-    pn_i_error_from_errno(selector->error, "select");
-  } else {
-    selector->current = 0;
-    selector->awoken = pn_i_now();
+  selector->current = 0;
+  selector->awoken = now;
+  selector->current_triggered = selector->triggered_list_head;
+  for (iocpdesc_t *iocpd = selector->deadlines_head; iocpd; iocpd = iocpd->deadlines_next) {
+    if (iocpd->deadline <= now)
+      pni_events_update(iocpd, iocpd->events | PN_EXPIRED);
+    else
+      break;
   }
-
   return pn_error_code(selector->error);
 }
 
 pn_selectable_t *pn_selector_next(pn_selector_t *selector, int *events)
 {
-  pn_list_t *l = selector->selectables;
-  size_t size = pn_list_size(l);
-  while (selector->current < size) {
-    pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(l, selector->current);
-    pn_timestamp_t deadline = selector->deadlines[selector->current];
-    int ev = 0;
-    pn_socket_t fd = pn_selectable_fd(sel);
-    if (FD_ISSET(fd, &selector->readfds)) {
-      ev |= PN_READABLE;
-    }
-    if (FD_ISSET(fd, &selector->writefds)) {
-      ev |= PN_WRITABLE;
-    }
-    if (deadline && selector->awoken >= deadline) {
-      ev |= PN_EXPIRED;
-    }
-    selector->current++;
-    if (ev) {
-      *events = ev;
-      return sel;
-    }
+  if (selector->current_triggered) {
+    iocpdesc_t *iocpd = selector->current_triggered;
+    *events = iocpd->interests & iocpd->events;
+    selector->current_triggered = iocpd->triggered_list_next;
+    return iocpd->selectable;
   }
   return NULL;
 }
@@ -252,3 +271,91 @@ void pn_selector_free(pn_selector_t *selector)
   assert(selector);
   pn_free(selector);
 }
+
+
+static void triggered_list_add(pn_selector_t *selector, iocpdesc_t *iocpd)
+{
+  if (iocpd->triggered_list_prev || selector->triggered_list_head == iocpd)
+    return; // already in list
+  LL_ADD(selector, triggered_list, iocpd);
+}
+
+static void triggered_list_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
+{
+  if (!iocpd->triggered_list_prev && selector->triggered_list_head != iocpd)
+    return; // not in list
+  LL_REMOVE(selector, triggered_list, iocpd);
+  iocpd->triggered_list_prev = NULL;
+  iocpd->triggered_list_next = NULL;
+}
+
+
+void pni_events_update(iocpdesc_t *iocpd, int events)
+{
+  int old_events = iocpd->events;
+  if (old_events == events)
+    return;
+  iocpd->events = events;
+  if (iocpd->selector) {
+    if (iocpd->events & iocpd->interests)
+      triggered_list_add(iocpd->selector, iocpd);
+    else
+      triggered_list_remove(iocpd->selector, iocpd);
+  }
+}
+
+static void interests_update(iocpdesc_t *iocpd, int interests)
+{
+  int old_interests = iocpd->interests;
+  if (old_interests == interests)
+    return;
+  iocpd->interests = interests;
+  if (iocpd->selector) {
+    if (iocpd->events & iocpd->interests)
+      triggered_list_add(iocpd->selector, iocpd);
+    else
+      triggered_list_remove(iocpd->selector, iocpd);
+  }
+}
+
+static void deadlines_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
+{
+  if (!iocpd->deadlines_prev && selector->deadlines_head != iocpd)
+    return; // not in list
+  LL_REMOVE(selector, deadlines, iocpd);
+  iocpd->deadlines_prev = NULL;
+  iocpd->deadlines_next = NULL;
+}
+
+
+static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t deadline)
+{
+  if (deadline == iocpd->deadline)
+    return;
+  iocpd->deadline = deadline;
+  pn_selector_t *selector = iocpd->selector;
+  if (!deadline) {
+    deadlines_remove(selector, iocpd);
+    pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
+    interests_update(iocpd, iocpd->interests & ~PN_EXPIRED);
+  } else {
+    if (iocpd->deadlines_prev || selector->deadlines_head == iocpd) {
+      deadlines_remove(selector, iocpd);
+      pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
+    }
+    interests_update(iocpd, iocpd->interests | PN_EXPIRED);
+    iocpdesc_t *dl_iocpd = LL_HEAD(selector, deadlines);
+    while (dl_iocpd && dl_iocpd->deadline <= deadline)
+      dl_iocpd = dl_iocpd->deadlines_next;
+    if (dl_iocpd) {
+      // insert
+      iocpd->deadlines_prev = dl_iocpd->deadlines_prev;
+      iocpd->deadlines_next = dl_iocpd;
+      dl_iocpd->deadlines_prev = iocpd;
+      if (selector->deadlines_head == dl_iocpd)
+        selector->deadlines_head = iocpd;
+    } else {
+      LL_ADD(selector, deadlines, iocpd);  // append
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/src/windows/write_pipeline.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/write_pipeline.c b/proton-c/src/windows/write_pipeline.c
new file mode 100644
index 0000000..3160fa8
--- /dev/null
+++ b/proton-c/src/windows/write_pipeline.c
@@ -0,0 +1,312 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * A simple write buffer pool.  Each socket has a dedicated "primary"
+ * buffer and can borrow from a shared pool with limited size tuning.
+ * Could enhance e.g. with separate pools per network interface and fancier
+ * memory tuning based on interface speed, system resources, and
+ * number of connections, etc.
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#define PN_WINAPI
+
+#include "platform.h"
+#include <proton/object.h>
+#include <proton/io.h>
+#include <proton/selector.h>
+#include <proton/error.h>
+#include <assert.h>
+#include "selectable.h"
+#include "util.h"
+#include "iocp.h"
+
+// Max overlapped writes per socket
+#define IOCP_MAX_OWRITES 16
+// Write buffer size
+#define IOCP_WBUFSIZE 16384
+
+static void pipeline_log(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fflush(stderr);
+}
+
+void pni_shared_pool_create(iocp_t *iocp)
+{
+  // TODO: more pools (or larger one) when using multiple non-loopback interfaces
+  iocp->shared_pool_size = 16;
+  char *env = getenv("PNI_WRITE_BUFFERS"); // Internal: for debugging
+  if (env) {
+    int sz = atoi(env);
+    if (sz >= 0 && sz < 256) {
+      iocp->shared_pool_size = sz;
+    }
+  }
+  iocp->loopback_bufsize = 0;
+  env = getenv("PNI_LB_BUFSIZE"); // Internal: for debugging
+  if (env) {
+    int sz = atoi(env);
+    if (sz >= 0 && sz <= 128 * 1024) {
+      iocp->loopback_bufsize = sz;
+    }
+  }
+
+  if (iocp->shared_pool_size) {
+    iocp->shared_pool_memory = (char *) VirtualAlloc(NULL, IOCP_WBUFSIZE * iocp->shared_pool_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+    HRESULT status = GetLastError();
+    if (!iocp->shared_pool_memory) {
+      perror("Proton write buffer pool allocation failure\n");
+      iocp->shared_pool_size = 0;
+      iocp->shared_available_count = 0;
+      return;
+    }
+
+    iocp->shared_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
+    iocp->available_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
+    iocp->shared_available_count = iocp->shared_pool_size;
+    char *mem = iocp->shared_pool_memory;
+    for (int i = 0; i < iocp->shared_pool_size; i++) {
+      iocp->shared_results[i] = iocp->available_results[i] = pni_write_result(NULL, mem, IOCP_WBUFSIZE);
+      mem += IOCP_WBUFSIZE;
+    }
+  }
+}
+
+void pni_shared_pool_free(iocp_t *iocp)
+{
+  for (int i = 0; i < iocp->shared_pool_size; i++) {
+    write_result_t *result = iocp->shared_results[i];
+    if (result->in_use)
+      pipeline_log("Proton buffer pool leak\n");
+    else
+      free(result);
+  }
+  if (iocp->shared_pool_size) {
+    free(iocp->shared_results);
+    free(iocp->available_results);
+    if (iocp->shared_pool_memory) {
+      if (!VirtualFree(iocp->shared_pool_memory, 0, MEM_RELEASE)) {
+        perror("write buffers release failed");
+      }
+      iocp->shared_pool_memory = NULL;
+    }
+  }
+}
+
+static void shared_pool_push(write_result_t *result)
+{
+  iocp_t *iocp = result->base.iocpd->iocp;
+  assert(iocp->shared_available_count < iocp->shared_pool_size);
+  iocp->available_results[iocp->shared_available_count++] = result;
+}
+
+static write_result_t *shared_pool_pop(iocp_t *iocp)
+{
+  return iocp->shared_available_count ? iocp->available_results[--iocp->shared_available_count] : NULL;
+}
+
+struct write_pipeline_t {
+  iocpdesc_t *iocpd;
+  size_t pending_count;
+  write_result_t *primary;
+  size_t reserved_count;
+  size_t next_primary_index;
+  size_t depth;
+  bool is_writer;
+};
+
+#define write_pipeline_compare NULL
+#define write_pipeline_inspect NULL
+#define write_pipeline_hashcode NULL
+
+static void write_pipeline_initialize(void *object)
+{
+  write_pipeline_t *pl = (write_pipeline_t *) object;
+  pl->pending_count = 0;
+  const char *pribuf = (const char *) malloc(IOCP_WBUFSIZE);
+  pl->primary = pni_write_result(NULL, pribuf, IOCP_WBUFSIZE);
+  pl->depth = 0;
+  pl->is_writer = false;
+}
+
+static void write_pipeline_finalize(void *object)
+{
+  write_pipeline_t *pl = (write_pipeline_t *) object;
+  free((void *)pl->primary->buffer.start);
+  free(pl->primary);
+}
+
+write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd)
+{
+  static const pn_class_t clazz = PN_CLASS(write_pipeline);
+  write_pipeline_t *pipeline = (write_pipeline_t *) pn_new(sizeof(write_pipeline_t), &clazz);
+  pipeline->iocpd = iocpd;
+  pipeline->primary->base.iocpd = iocpd;
+  return pipeline;
+}
+
+static void confirm_as_writer(write_pipeline_t *pl)
+{
+  if (!pl->is_writer) {
+    iocp_t *iocp = pl->iocpd->iocp;
+    iocp->writer_count++;
+    pl->is_writer = true;
+  }
+}
+
+static void remove_as_writer(write_pipeline_t *pl)
+{
+  if (!pl->is_writer)
+    return;
+  iocp_t *iocp = pl->iocpd->iocp;
+  assert(iocp->writer_count);
+  pl->is_writer = false;
+  iocp->writer_count--;
+}
+
+/*
+ * Optimal depth will depend on properties of the NIC, server, and driver.  For now,
+ * just distinguish between loopback interfaces and the rest.  Optimizations in the
+ * loopback stack allow decent performance with depth 1 and actually cause major
+ * performance hiccups if set to large values.
+ */
+static void set_depth(write_pipeline_t *pl)
+{
+  pl->depth = 1;
+  sockaddr_storage sa;
+  socklen_t salen = sizeof(sa);
+  char buf[INET6_ADDRSTRLEN];
+  DWORD buflen = sizeof(buf);
+
+  if (getsockname(pl->iocpd->socket,(sockaddr*) &sa, &salen) == 0 &&
+      getnameinfo((sockaddr*) &sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0) {
+    if ((sa.ss_family == AF_INET6 && strcmp(buf, "::1")) ||
+        (sa.ss_family == AF_INET && strncmp(buf, "127.", 4))) {
+      // not loopback
+      pl->depth = IOCP_MAX_OWRITES;
+    } else {
+      iocp_t *iocp = pl->iocpd->iocp;
+      if (iocp->loopback_bufsize) {
+        const char *p = (const char *) realloc((void *) pl->primary->buffer.start, iocp->loopback_bufsize);
+        if (p) {
+          pl->primary->buffer.start = p;
+          pl->primary->buffer.size = iocp->loopback_bufsize;
+        }
+      }
+    }
+  }
+}
+
+// Reserve as many buffers as possible for count bytes.
+size_t pni_write_pipeline_reserve(write_pipeline_t *pl, size_t count)
+{
+  if (pl->primary->in_use)
+    return 0;  // I.e. io->wouldblock
+  if (!pl->depth)
+    set_depth(pl);
+  if (pl->depth == 1) {
+    // always use the primary
+    pl->reserved_count = 1;
+    pl->next_primary_index = 0;
+    return 1;
+  }
+
+  iocp_t *iocp = pl->iocpd->iocp;
+  confirm_as_writer(pl);
+  int wanted = (count / IOCP_WBUFSIZE);
+  if (count % IOCP_WBUFSIZE)
+    wanted++;
+  size_t pending = pl->pending_count;
+  assert(pending < pl->depth);
+  int bufs = pn_min(wanted, pl->depth - pending);
+  // Can draw from shared pool or the primary... but share with others.
+  size_t writers = iocp->writer_count;
+  int shared_count = (iocp->shared_available_count + writers - 1) / writers;
+  bufs = pn_min(bufs, shared_count + 1);
+  pl->reserved_count = pending + bufs;
+
+  if (bufs == wanted &&
+      pl->reserved_count < (pl->depth / 2) &&
+      iocp->shared_available_count > (2 * writers + bufs)) {
+    // No shortage: keep the primary as spare for future use
+    pl->next_primary_index = pl->reserved_count;
+  } else if (bufs == 1) {
+    pl->next_primary_index = pending;
+  } else {
+    // let approx 1/3 drain before replenishing
+    pl->next_primary_index = ((pl->reserved_count + 2) / 3) - 1;
+    if (pl->next_primary_index < pending)
+      pl->next_primary_index = pending;
+  }
+  return bufs;
+}
+
+write_result_t *pni_write_pipeline_next(write_pipeline_t *pl)
+{
+  size_t sz = pl->pending_count;
+  if (sz >= pl->reserved_count)
+    return NULL;
+  write_result_t *result;
+  if (sz == pl->next_primary_index) {
+    result = pl->primary;
+  } else {
+    assert(pl->iocpd->iocp->shared_available_count > 0);
+    result = shared_pool_pop(pl->iocpd->iocp);
+  }
+
+  result->in_use = true;
+  pl->pending_count++;
+  return result;
+}
+
+void pni_write_pipeline_return(write_pipeline_t *pl, write_result_t *result)
+{
+  result->in_use = false;
+  pl->pending_count--;
+  pl->reserved_count = 0;
+  if (result != pl->primary)
+    shared_pool_push(result);
+  if (pl->pending_count == 0)
+    remove_as_writer(pl);
+}
+
+bool pni_write_pipeline_writable(write_pipeline_t *pl)
+{
+  // Only writable if not full and we can guarantee a buffer:
+  return pl->pending_count < pl->depth && !pl->primary->in_use;
+}
+
+size_t pni_write_pipeline_size(write_pipeline_t *pl)
+{
+  return pl->pending_count;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/Proton.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/Proton.java b/proton-j/src/main/java/org/apache/qpid/proton/Proton.java
index ceea5a8..39b04e5 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/Proton.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/Proton.java
@@ -30,87 +30,58 @@ import org.apache.qpid.proton.amqp.messaging.Header;
 import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
 import org.apache.qpid.proton.amqp.messaging.Properties;
 import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.codec.Codec;
 import org.apache.qpid.proton.codec.Data;
-import org.apache.qpid.proton.codec.DataFactory;
 import org.apache.qpid.proton.driver.Driver;
-import org.apache.qpid.proton.driver.DriverFactory;
+import org.apache.qpid.proton.engine.Engine;
 import org.apache.qpid.proton.engine.Collector;
 import org.apache.qpid.proton.engine.Connection;
-import org.apache.qpid.proton.engine.EngineFactory;
 import org.apache.qpid.proton.engine.SslDomain;
 import org.apache.qpid.proton.engine.SslPeerDetails;
 import org.apache.qpid.proton.engine.Transport;
 import org.apache.qpid.proton.message.Message;
-import org.apache.qpid.proton.message.MessageFactory;
 import org.apache.qpid.proton.messenger.Messenger;
-import org.apache.qpid.proton.messenger.MessengerFactory;
-
-import org.apache.qpid.proton.engine.impl.CollectorImpl;
 
 public final class Proton
 {
 
-    public static ProtonFactory.ImplementationType ANY = ProtonFactory.ImplementationType.ANY;
-    public static ProtonFactory.ImplementationType PROTON_C = ProtonFactory.ImplementationType.PROTON_C;
-    public static ProtonFactory.ImplementationType PROTON_J = ProtonFactory.ImplementationType.PROTON_J;
-
-
-    private static final MessengerFactory MESSENGER_FACTORY =
-            (new ProtonFactoryLoader<MessengerFactory>(MessengerFactory.class)).loadFactory();
-    private static final DriverFactory DRIVER_FACTORY =
-            (new ProtonFactoryLoader<DriverFactory>(DriverFactory.class)).loadFactory();
-    private static final MessageFactory MESSAGE_FACTORY =
-            (new ProtonFactoryLoader<MessageFactory>(MessageFactory.class)).loadFactory();
-    private static final DataFactory DATA_FACTORY =
-            (new ProtonFactoryLoader<DataFactory>(DataFactory.class)).loadFactory();
-    private static final EngineFactory ENGINE_FACTORY =
-            (new ProtonFactoryLoader<EngineFactory>(EngineFactory.class)).loadFactory();
-
-    private static final ProtonFactory.ImplementationType DEFAULT_IMPLEMENTATION =
-            ProtonFactoryLoader.getImpliedImplementationType();
-
     private Proton()
     {
     }
 
-    public static ProtonFactory.ImplementationType getDefaultImplementationType()
-    {
-        return DEFAULT_IMPLEMENTATION;
-    }
-
     public static Collector collector()
     {
-        return new CollectorImpl();
+        return Engine.collector();
     }
 
     public static Connection connection()
     {
-        return ENGINE_FACTORY.createConnection();
+        return Engine.connection();
     }
 
     public static Transport transport()
     {
-        return ENGINE_FACTORY.createTransport();
+        return Engine.transport();
     }
 
     public static SslDomain sslDomain()
     {
-        return ENGINE_FACTORY.createSslDomain();
+        return Engine.sslDomain();
     }
 
     public static SslPeerDetails sslPeerDetails(String hostname, int port)
     {
-        return ENGINE_FACTORY.createSslPeerDetails(hostname, port);
+        return Engine.sslPeerDetails(hostname, port);
     }
 
     public static Data data(long capacity)
     {
-        return DATA_FACTORY.createData(capacity);
+        return Codec.data(capacity);
     }
 
     public static Message message()
     {
-        return MESSAGE_FACTORY.createMessage();
+        return Message.Factory.create();
     }
 
     public static Message message(Header header,
@@ -118,134 +89,25 @@ public final class Proton
                       Properties properties, ApplicationProperties applicationProperties,
                       Section body, Footer footer)
     {
-        return MESSAGE_FACTORY.createMessage(header, deliveryAnnotations,
-                                             messageAnnotations, properties,
-                                             applicationProperties, body, footer);
+        return Message.Factory.create(header, deliveryAnnotations,
+                                      messageAnnotations, properties,
+                                      applicationProperties, body, footer);
     }
 
 
     public static Messenger messenger()
     {
-        return MESSENGER_FACTORY.createMessenger();
+        return Messenger.Factory.create();
     }
 
     public static Messenger messenger(String name)
     {
-        return MESSENGER_FACTORY.createMessenger(name);
+        return Messenger.Factory.create(name);
     }
 
     public static Driver driver() throws IOException
     {
-        return DRIVER_FACTORY.createDriver();
+        return Driver.Factory.create();
     }
 
-
-
-    public static Connection connection(ProtonFactory.ImplementationType implementation)
-    {
-        return getEngineFactory(implementation).createConnection();
-    }
-
-    public static Transport transport(ProtonFactory.ImplementationType implementation)
-    {
-        return getEngineFactory(implementation).createTransport();
-    }
-
-    public static SslDomain sslDomain(ProtonFactory.ImplementationType implementation)
-    {
-        return getEngineFactory(implementation).createSslDomain();
-    }
-
-    public static SslPeerDetails sslPeerDetails(ProtonFactory.ImplementationType implementation, String hostname, int port)
-    {
-        return getEngineFactory(implementation).createSslPeerDetails(hostname, port);
-    }
-
-    public static Data data(ProtonFactory.ImplementationType implementation, long capacity)
-    {
-        return getDataFactory(implementation).createData(capacity);
-    }
-
-    public static Message message(ProtonFactory.ImplementationType implementation)
-    {
-        return getMessageFactory(implementation).createMessage();
-    }
-
-    public static Message message(ProtonFactory.ImplementationType implementation, Header header,
-                      DeliveryAnnotations deliveryAnnotations, MessageAnnotations messageAnnotations,
-                      Properties properties, ApplicationProperties applicationProperties,
-                      Section body, Footer footer)
-    {
-        return getMessageFactory(implementation).createMessage(header, deliveryAnnotations,
-                                                               messageAnnotations, properties,
-                                                               applicationProperties, body, footer);
-    }
-
-
-    public static Messenger messenger(ProtonFactory.ImplementationType implementation)
-    {
-        return getMessengerFactory(implementation).createMessenger();
-    }
-
-    public static Messenger messenger(ProtonFactory.ImplementationType implementation, String name)
-    {
-        return getMessengerFactory(implementation).createMessenger(name);
-    }
-
-    public static Driver driver(ProtonFactory.ImplementationType implementation) throws IOException
-    {
-        return getDriverFactory(implementation).createDriver();
-    }
-
-
-    private static final ConcurrentMap<ProtonFactory.ImplementationType, EngineFactory> _engineFactories =
-            new ConcurrentHashMap<ProtonFactory.ImplementationType, EngineFactory>();
-    private static final ConcurrentMap<ProtonFactory.ImplementationType, MessageFactory> _messageFactories =
-            new ConcurrentHashMap<ProtonFactory.ImplementationType, MessageFactory>();
-    private static final ConcurrentMap<ProtonFactory.ImplementationType, MessengerFactory> _messengerFactories =
-                new ConcurrentHashMap<ProtonFactory.ImplementationType, MessengerFactory>();
-    private static final ConcurrentMap<ProtonFactory.ImplementationType, DataFactory> _dataFactories =
-                new ConcurrentHashMap<ProtonFactory.ImplementationType, DataFactory>();
-    private static final ConcurrentMap<ProtonFactory.ImplementationType, DriverFactory> _driverFactories =
-                new ConcurrentHashMap<ProtonFactory.ImplementationType, DriverFactory>();
-
-    private static EngineFactory getEngineFactory(ProtonFactory.ImplementationType implementation)
-    {
-        return getFactory(EngineFactory.class, implementation, _engineFactories);
-    }
-
-    private static MessageFactory getMessageFactory(ProtonFactory.ImplementationType implementation)
-    {
-        return getFactory(MessageFactory.class, implementation, _messageFactories);
-    }
-
-    private static MessengerFactory getMessengerFactory(ProtonFactory.ImplementationType implementation)
-    {
-        return getFactory(MessengerFactory.class, implementation, _messengerFactories);
-    }
-
-    private static DriverFactory getDriverFactory(ProtonFactory.ImplementationType implementation)
-    {
-        return getFactory(DriverFactory.class, implementation, _driverFactories);
-    }
-
-    private static DataFactory getDataFactory(ProtonFactory.ImplementationType implementation)
-    {
-        return getFactory(DataFactory.class, implementation, _dataFactories);
-    }
-
-    private static <T extends ProtonFactory>  T getFactory(Class<T> factoryClass, ProtonFactory.ImplementationType implementation,
-                                                           ConcurrentMap<ProtonFactory.ImplementationType, T> factories)
-    {
-        T factory = factories.get(implementation);
-        if(factory == null)
-        {
-            factories.putIfAbsent(implementation, (new ProtonFactoryLoader<T>(factoryClass,implementation)).loadFactory());
-            factory = factories.get(implementation);
-
-        }
-        return factory;
-    }
-
-
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactory.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactory.java b/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactory.java
deleted file mode 100644
index b855b0c..0000000
--- a/proton-j/src/main/java/org/apache/qpid/proton/ProtonFactory.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.proton;
-
-public interface ProtonFactory
-{
-    enum ImplementationType
-    {
-        PROTON_C,
-        PROTON_J,
-        ANY;
-    }
-
-    ImplementationType getImplementationType();
-}


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


[34/51] [abbrv] qpid-proton git commit: Refactor JavaScript binding from a single ludicrously huge binding.js into a set of sub-modules that should hopefully make maintenance much simpler

Posted by rh...@apache.org.
Refactor JavaScript binding from a single ludicrously huge binding.js into a set of sub-modules that should hopefully make maintenance much simpler

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1624873 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/abd646b2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/abd646b2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/abd646b2

Branch: refs/heads/master
Commit: abd646b284ab3debbea3100096ada38c07984a90
Parents: f1fc250
Author: fadams <fa...@unknown>
Authored: Sun Sep 14 16:57:09 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sun Sep 14 16:57:09 2014 +0000

----------------------------------------------------------------------
 proton-c/bindings/javascript/CMakeLists.txt     |   20 +-
 proton-c/bindings/javascript/binding.js         | 4129 ------------------
 proton-c/bindings/javascript/data-array.js      |  100 +
 proton-c/bindings/javascript/data-binary.js     |  181 +
 proton-c/bindings/javascript/data-described.js  |   74 +
 proton-c/bindings/javascript/data-long.js       |  191 +
 proton-c/bindings/javascript/data-symbol.js     |   59 +
 .../bindings/javascript/data-typed-number.js    |  108 +
 proton-c/bindings/javascript/data-uuid.js       |  107 +
 proton-c/bindings/javascript/data.js            | 1577 +++++++
 proton-c/bindings/javascript/error.js           |  145 +
 proton-c/bindings/javascript/message.js         |  848 ++++
 proton-c/bindings/javascript/messenger.js       |  799 ++++
 proton-c/bindings/javascript/module.js          |  150 +
 proton-c/bindings/javascript/subscription.js    |   67 +
 15 files changed, 4421 insertions(+), 4134 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index a92509a..695fbd1 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -96,9 +96,7 @@ add_custom_command(
   DEPENDS ${PN_PATH}/src/protocol.h.py
   )
 
-# TODO put back -Werror once offending warnings get eliminated.
-#set(COMPILE_WARNING_FLAGS "-Werror -Wall -pedantic-errors -Wno-comment -Wno-warn-absolute-paths")
-set(COMPILE_WARNING_FLAGS "-Wall -pedantic-errors -Wno-comment -Wno-warn-absolute-paths")
+set(COMPILE_WARNING_FLAGS "-Werror -Wall -pedantic-errors -Wno-comment -Wno-warn-absolute-paths")
 
 # Explicitly set PLATFORM_DEFINITIONS to Linux ones for emscripten as we don't
 # want to inadvertently use Windows versions if we happen to be cross-compiling
@@ -223,7 +221,7 @@ set_target_properties(
   # fiddly with node.js packages. This behaviour might be reinstated if the
   # packaging mechanism improves.
 
-  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messen
 ger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_rep
 ly_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data
 _put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_
 pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/module.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/error.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/message.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_bytes', '_pn_error_tex
 t', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '
 _pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence'
 , '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put
 _decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
   )
 
 # This command packages up the compiled proton.js into a node.js package called
@@ -259,7 +257,19 @@ if (NODE_JSDOC_FOUND)
     message(STATUS "Documentation Enabled. Using ${JSDOC_EXE} to build JavaScript docs")
     add_custom_target(docs-js COMMAND ${JSDOC_EXE}
                       -d ${CMAKE_CURRENT_BINARY_DIR}/html
-                      ${CMAKE_CURRENT_SOURCE_DIR}/binding.js)
+                      ${CMAKE_CURRENT_SOURCE_DIR}/module.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/error.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/message.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js)
     add_dependencies(docs docs-js)
 
 endif (NODE_JSDOC_FOUND)


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


[13/51] [abbrv] qpid-proton git commit: JavaScript binding now pretty much in a releasable state. Needs a little bit of tidying up, a few more tests and examples, but it now has a more or less complete implementation of qpid-config to test interoperabili

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/javascript/server.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/server.js b/examples/messenger/javascript/server.js
new file mode 100644
index 0000000..cce8aa3
--- /dev/null
+++ b/examples/messenger/javascript/server.js
@@ -0,0 +1,79 @@
+#!/usr/bin/env node
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+// Simple server for use with client.js illustrating request/response
+
+// Check if the environment is Node.js and if so import the required library.
+if (typeof exports !== "undefined" && exports !== null) {
+    proton = require("qpid-proton");
+}
+
+var address = "amqp://~0.0.0.0";
+var message = new proton.Message();
+var reply   = new proton.Message();
+var messenger = new proton.Messenger();
+
+var dispatch = function(request, response) {
+    var subject = request.getSubject();
+    if (subject) {
+        response.setSubject('Re: ' + subject);
+    }
+    response.properties = request.properties
+    console.log("Dispatched " + subject + " " + JSON.stringify(request.properties));
+};
+
+var pumpData = function() {
+    while (messenger.incoming()) {
+        var t = messenger.get(message);
+
+        var replyTo = message.getReplyTo();
+        if (replyTo) {
+            console.log(replyTo);
+            reply.setAddress(replyTo);
+            reply.setCorrelationID(message.getCorrelationID());
+            reply.body = message.body;
+            dispatch(message, reply);
+            messenger.put(reply);
+        }
+
+        messenger.accept(t);
+    }
+};
+
+var args = process.argv.slice(2);
+if (args.length > 0) {
+    if (args[0] === '-h' || args[0] === '--help') {
+        console.log("Usage: node server.js <addr> (default " + address + ")");
+        process.exit(0);
+    }
+
+    address = args[0];
+}
+
+messenger.setIncomingWindow(1024);
+
+messenger.on('error', function(error) {console.log(error);});
+messenger.on('work', pumpData);
+messenger.start();
+
+messenger.subscribe(address);
+messenger.recv(); // Receive as many messages as messenger can buffer.
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/javascript/spout.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/spout.js b/examples/messenger/javascript/spout.js
index cfb9351..1219627 100644
--- a/examples/messenger/javascript/spout.js
+++ b/examples/messenger/javascript/spout.js
@@ -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
@@ -23,102 +24,95 @@ if (typeof exports !== "undefined" && exports !== null) {
     proton = require("qpid-proton");
 }
 
-try {
-    var address = "amqp://0.0.0.0";
-    var subject = "UK.WEATHER";
-    var msgtext = "Hello World!";
-    var tracker = null;
-    var running = true;
+console.log("spout not implemented yet");
+process.exit(0);
 
-    var message = new proton.Message();
-    var messenger = new proton.Messenger();
+var address = "amqp://0.0.0.0";
+var subject = "UK.WEATHER";
+var msgtext = "Hello World!";
+var tracker = null;
+var running = true;
 
-    function _process() {
-//        console.log("                          *** process ***");
+var message = new proton.Message();
+var messenger = new proton.Messenger();
 
-        // Process outgoing messages
-        var status = messenger.status(tracker);
-        if (status != proton.Status.PENDING) {
+function pumpData() {
+    var status = messenger.status(tracker);
+    if (status != proton.Status.PENDING) {
 console.log("status = " + status);
 
-            //messenger.settle(tracker);
-            //tracked--;
-
-            if (running) {
+        if (running) {
 console.log("stopping");
-                messenger.stop();
-                running = false;
-            } 
-        }
+            messenger.stop();
+            running = false;
+        } 
+    }
 
-        if (messenger.isStopped()) {
+    if (messenger.isStopped()) {
 console.log("exiting");
-            message.free();
-            messenger.free();
-            //exit(0);
-        }
-    };
-
-    messenger.setOutgoingWindow(1024);
+        message.free();
+        messenger.free();
+    }
+};
 
-    messenger.setNetworkCallback(_process);
-    messenger.start();
+messenger.on('error', function(error) {console.log(error);});
+messenger.on('work', pumpData);
+messenger.setOutgoingWindow(1024);
+messenger.start();
 
-    message.setAddress(address);
-    message.setSubject(subject);
+message.setAddress(address);
+message.setSubject(subject);
 
-    //message.body = msgtext;
-    //message.body = new proton.Data.Uuid();
-    //message.body = new proton.Data.Symbol("My Symbol");
-    //message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
-    //message.body = new proton.Data.Described("persian", "feline mammals");
+//message.body = msgtext;
+//message.body = new proton.Data.Uuid();
+//message.body = new proton.Data.Symbol("My Symbol");
+message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
+//message.body = new proton.Data.Described("persian", "feline mammals");
 
-    //message.body = new Date();
+//message.body = new Date();
 
-    //message.body = new proton.Data.Array('INT', [1, 3, 5, 7], "odd numbers");
+//message.body = new proton.Data.Array('INT', [1, 3, 5, 7], "odd numbers");
 
-    //message.body = new proton.Data.Array('UINT', [1, 3, 5, 7], "odd");
-    //message.body = new proton.Data.Array('ULONG', [1, 3, 5, 7], "odd");
-    //message.body = new proton.Data.Array('FLOAT', [1, 3, 5, 7], "odd");
-    //message.body = new proton.Data.Array('STRING', ["1", "3", "5", "7"], "odd");
+//message.body = new proton.Data.Array('UINT', [1, 3, 5, 7], "odd");
+//message.body = new proton.Data.Array('ULONG', [1, 3, 5, 7], "odd");
+//message.body = new proton.Data.Array('FLOAT', [1, 3, 5, 7], "odd");
+//message.body = new proton.Data.Array('STRING', ["1", "3", "5", "7"], "odd");
 
-    //message.body = new Uint8Array([1, 3, 5, 7]);
+//message.body = new Uint8Array([1, 3, 5, 7]);
 
-    //message.body = new proton.Data.Array('UINT', new Uint8Array([1, 3, 5, 7]), "odd");
+//message.body = new proton.Data.Array('UINT', new Uint8Array([1, 3, 5, 7]), "odd");
 
-    //message.body = new proton.Data.Array('UUID', [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()], "unique");
+//message.body = new proton.Data.Array('UUID', [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()], "unique");
 
-    /*message.body = new proton.Data.Binary(4);
-    var buffer = message.body.getBuffer();
-    buffer[0] = 65;
-    buffer[1] = 77;
-    buffer[2] = 81;
-    buffer[3] = 80;*/
-    message.body = new proton.Data.Binary([65, 77, 81, 80]);
+/*message.body = new proton.Data.Binary(4);
+var buffer = message.body.getBuffer();
+buffer[0] = 65;
+buffer[1] = 77;
+buffer[2] = 81;
+buffer[3] = 80;*/
+//message.body = new proton.Data.Binary([65, 77, 81, 80]);
+//message.body = new proton.Data.Binary(2485);
+//message.body = new proton.Data.Binary(100000);
 
-    //message.body = null;
-    //message.body = true;
-    //message.body = 66..char();
-    //message.body = "   \"127.0\"  ";
+//message.body = null;
+//message.body = true;
+//message.body = 66..char();
+//message.body = "   \"127.0\"  ";
 
-    //message.body = 2147483647; // int
-    //message.body = -2147483649; // long
-    //message.body = 12147483649; // long
-    //message.body = (12147483649).long(); // long
-    //message.body = (-12147483649).ulong(); // long
-    //message.body = (17223372036854778000).ulong(); // ulong
+//message.body = 2147483647; // int
+//message.body = -2147483649; // long
+//message.body = 12147483649; // long
+//message.body = (12147483649).long(); // long
+//message.body = (-12147483649).ulong(); // long
+//message.body = (17223372036854778000).ulong(); // ulong
 
-    //message.body = (121474.836490).float(); // float TODO check me
-    //message.body = 12147483649.0.float(); // float TODO check me
-    //message.body = (4294967296).uint();
-    //message.body = (255).ubyte();
+//message.body = (121474.836490).float(); // float TODO check me
+//message.body = 12147483649.0.float(); // float TODO check me
+//message.body = (4294967296).uint();
+//message.body = (255).ubyte();
 
-    //message.body = ['Rod', 'Jane', 'Freddy'];
-    //message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
-    //message.body = {cat: true, donkey: 'hee haw'};
+//message.body = ['Rod', 'Jane', 'Freddy'];
+//message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
 
-    tracker = messenger.put(message);
+tracker = messenger.put(message);
 
-} catch(e) {
-    console.log("Caught Exception " + e);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/examples/messenger/javascript/ws2tcp.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/ws2tcp.js b/examples/messenger/javascript/ws2tcp.js
new file mode 100755
index 0000000..abb78f2
--- /dev/null
+++ b/examples/messenger/javascript/ws2tcp.js
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * ws2tcp.js is a simple node.js library that proxies from a WebSocket to a TCP
+ * Socket or vice versa. It has minimal dependencies - the standard node.js net
+ * library and the ws WebSocket library (npm install ws).
+ * <p>
+ * Two fuctions are exported, ws2tcp proxies from a WebSocket to a TCP Socket and
+ * tcp2ws proxies from a TCP Socket to a WebSocket.
+ * @Author Fraser Adams
+ * @file
+ */
+
+var WebSocket = require('ws');
+var net = require('net');
+
+/**
+ * This function is shared by ws2tcp and tcp2ws and takes care of cleaning up
+ * and closing the WebSocket and Socket when things close down or error.
+ * @param sock the TCP Socket instance we're registering cleanup handlers for.
+ * @param ws the WebSocket instance we're registering cleanup handlers for.
+ */
+var registerCleanupCallbacks = function(sock, ws) {
+    var cleanup = function(sock, ws) {
+        sock.removeAllListeners('close');	
+        sock.end();
+        ws.removeAllListeners('close');
+        ws.close();
+    };
+
+    sock.on('close', function() {
+        cleanup(sock, ws);
+    });
+
+    sock.on('error', function (e) {
+        console.log("socket error: " + e.code);
+        cleanup(sock, ws);
+    });
+
+    ws.on('close', function() {
+        cleanup(sock, ws);
+    });
+
+    ws.on('error', function (e) {
+        console.log("websocket error: " + e.code);
+        cleanup(sock, ws);
+    });
+};
+
+/**
+ * This function establishes a proxy that listens on a specified TCP Socket port
+ * and proxies data to a WebSocket on the target host listening on the specified
+ * target port.
+ * @param lport the listen port.
+ * @param thost the target host.
+ * @param tport the target port.
+ * @param subProtocols a string containing a comma separated list of WebSocket sub-protocols.
+ */
+var tcp2ws = function(lport, thost, tport, subProtocols) {
+    var opts = null;
+    if (subProtocols) {
+        // The regex trims the string (removes spaces at the beginning and end,
+        // then splits the string by <any space>,<any space> into an Array.
+        subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+        opts = {'protocol': subProtocols.toString()};
+    }
+
+    var server = net.createServer(function(sock) {
+        var url = 'ws://' + thost + ':' + tport;
+        var ws = new WebSocket(url, opts);
+        var ready = false;
+        var buffer = [];
+
+        registerCleanupCallbacks(sock, ws);
+
+        sock.on('data', function(data) {
+            if (ready) {
+                ws.send(data);
+            } else {
+                buffer.push(data);
+            }
+        });
+
+        ws.on('open', function () {
+            if (buffer.length > 0) {
+                ws.send(Buffer.concat(buffer));
+            }
+            ready = true;
+            buffer = null;
+        });
+
+        ws.on('message', function(m) {
+            sock.write(m);	
+        });
+    });
+    server.listen(lport);
+};
+
+/**
+ * This function establishes a proxy that listens on a specified WebSocket port
+ * and proxies data to a TCP Socket on the target host listening on the specified
+ * target port.
+ * @param lport the listen port.
+ * @param thost the target host.
+ * @param tport the target port.
+ */
+var ws2tcp = function(lport, thost, tport) {
+    var server = new WebSocket.Server({port: lport});
+    server.on('connection', function(ws) {
+        var sock = net.connect(tport, thost);
+        var ready = false;
+        var buffer = [];
+
+        registerCleanupCallbacks(sock, ws);
+
+        ws.on('message', function(m) {
+            if (ready) {
+                sock.write(m);	
+            } else {
+                buffer.push(m);
+            }
+        });
+
+        sock.on('connect', function() {
+            if (buffer.length > 0) {
+                sock.write(Buffer.concat(buffer));
+            }
+            ready = true;
+            buffer = null;
+        });
+
+        sock.on('data', function(data) {
+            ws.send(data);
+        });
+    });
+    server.on('error', function(e) {
+        console.log("websocket server error: " + e.code);
+    });
+};
+
+// Export the two proxy functions.
+module.exports.ws2tcp = ws2tcp;
+module.exports.tcp2ws = tcp2ws;
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index ef6d384..4e4dc0f 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -186,8 +186,6 @@ target_link_libraries(send-async.js qpid-proton-bitcode)
 add_executable(recv-async.js ${PN_PATH}/../examples/messenger/c/recv-async.c)
 target_link_libraries(recv-async.js qpid-proton-bitcode)
 
-# TODO get the patches in my-library.js pushed properly into emscripten ASAP
-#
 set_target_properties(
   send-async.js recv-async.js
   PROPERTIES
@@ -196,16 +194,16 @@ set_target_properties(
   DEPENDS ws
 
   # This build shows socket messages - useful for debugging.
-  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -s SOCKET_DEBUG=1 --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js"
+  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -s SOCKET_DEBUG=1"
 
   # Optimised build - takes somewhat longer to build.
-  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js"
+  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1"
 
   # This build shows up emscripten warnings when building - should be able to remove it.
-  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -s VERBOSE=1 -O2 --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js"
+  #LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -s VERBOSE=1 -O2"
 
   # This build is optimised but not minified
-  LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js"
+  LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2"
   )
 
 
@@ -219,10 +217,16 @@ set_target_properties(
   PROPERTIES
   COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
 
-  # This build is optimised and minified
-  #LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --pre-js
+  # This build is optimised and minified. The --memory-init-file 0 stops emscripten
+  # emitting a separate memory initialization file, if this was enabled it makes
+  # packaging harder as applications would expect proton.js.mem to be served too.
+  # It's even more fiddly with node.js packages. This behaviour might be reinstated
+  # if the packaging mechanism improves.
+
+  # --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js
+  #LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --memory-init-file 0 --pre-js
 
-  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js --js-library ${CMAKE_CURRENT_SOURCE_DIR}/my-library.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_r
 ecv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_free', '_pn_message_get_address', '_pn_message_errno', '_pn_message_error', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array'
 , '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_dec
 imal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -O2 --closure 1 --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_test', '_uuid_generate', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '
 _pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_messa
 ge_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array',
  '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_deci
 mal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
   )
 
 # This command packages up the compiled proton.js into a node.js package called

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/proton-c/bindings/javascript/TODO
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/TODO b/proton-c/bindings/javascript/TODO
index e717410..bd1d158 100644
--- a/proton-c/bindings/javascript/TODO
+++ b/proton-c/bindings/javascript/TODO
@@ -1,31 +1,11 @@
 Qpid Proton JavaScript Language Bindings TODO List
 ==================================================
 
-This is still largely a Proof of Concept, but it builds cleanly from an unmodified proton-c 
-code base, so for the most part it feels like a really neat way to generate JavaScript bindings.
-
-The main TODO is to actually create JavaScript bindings :-)
-
-At the moment the send-async.js and recv-async.js are actually compiled to JavaScript from
-send-async.c and recv-async.c so "real" JavaScript bindings usable from other JavaScript code
-haven't been exported yet. I suspect that one of the most important things to check when that is
-done would be interoperability across different types. This is all easy in the C code because
-the emscripten runtime heap is backed by typed Arrays, but there might be shenanigans to be had
-mapping stuff across the binding - it's definitely do-able just don't know how fiddly.
-
-Other TODO the code base contains some tweaked emscripten library code, this is ultimately going
+The code base contains some tweaked emscripten library code, this is ultimately going
 to get done properly, commited back to emscripten and removed from here.
 
 
-The example send-async and recv-async are both pretty hacky at the moment and *not really asynchronous*!!
-This will be addressed ASAP, I hate the timed loop and although the code is non-blocking it's not
-asynchronous. I'm pretty sure that I know how to get emscripten to call back when data is available
-on a WebSocket so hopefully this should be straightforward.
-
-There's probably a slightly more contentious discussion to be had about a proper asynchronous interface
-in proton-c proper. I suspect that it could do with one in the brave new multicore world pushing out
-data down non-blocking queues to consumer threads tends to scale better than a model of threads locking
-a resource, which is the behaviour I suspect the current API likely steers clients towards.
+The example send-async.c and recv-async.c are both pretty hacky at the moment.
 
 proton-j seems to use hawt-dispatch, which is modelled after Grand Central Dispatch so I need to
 work out what it's using it do do and whether there are parallels in proton-c

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/proton-c/bindings/javascript/binding.c
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.c b/proton-c/bindings/javascript/binding.c
index e91c3c8..425efb4 100644
--- a/proton-c/bindings/javascript/binding.c
+++ b/proton-c/bindings/javascript/binding.c
@@ -1,80 +1,4 @@
 
 #include <stdio.h>
-#include <stdlib.h>
+// Just a stub.
 
-/*
-#include "proton/message.h"
-
-typedef struct {
-  size_t next;
-  size_t prev;
-  size_t down;
-  size_t parent;
-  size_t children;
-  pn_atom_t atom;
-  // for arrays
-  bool described;
-  pn_type_t type;
-  bool data;
-  size_t data_offset;
-  size_t data_size;
-  char *start;
-  bool small;
-} pni_node_t;
-
-pni_node_t* pn_data_add(pn_data_t *data);
-
-int test(pn_data_t *data, int64_t l)
-{
-printf("hello\n");
-
-  pni_node_t *node = pn_data_add(data);
-  node->atom.type = PN_LONG;
-  node->atom.u.as_long = l;
-
-  return 0;
-}
-*/
-
-
-
-
-
-/*
-z_streamp inflateInitialise() {
-    z_streamp stream = malloc(sizeof(z_stream));
-    stream->zalloc = Z_NULL;
-    stream->zfree = Z_NULL;
-    int ret = inflateInit(stream);
-    if (ret != Z_OK) {
-        return Z_NULL;
-    } else {
-        return stream;
-    }
-}
-
-void inflateDestroy(z_streamp stream) {
-    inflateEnd(stream);
-    free(stream);
-}
-
-int zinflate(z_streamp stream,
-             unsigned char* dest, unsigned long* destLen,
-             unsigned char* source, unsigned long sourceLen) {
-    int err;
-    int total = stream->total_out;
-    stream->avail_in = sourceLen;
-    stream->next_in = source;
-
-    stream->avail_out = *destLen;
-    stream->next_out = dest;
-
-    err = inflate(stream, Z_SYNC_FLUSH);
-    *destLen = stream->total_out - total;
-
-    if (err != Z_OK) {
-        inflateEnd(stream);
-    }
-    return err;
-}
-*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index 08aeb3e..eceda54 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -37,7 +37,7 @@
  * from minifying e.g. <pre>Module['Messenger'] = ...</pre>
  * Exported Objects can be used in client code using the appropriate namespace:
  * <pre>
- * proton = require('proton.js');
+ * proton = require('qpid-proton');
  * var messenger = new proton.Messenger();
  * var message = new proton.Message();
  * </pre>
@@ -102,6 +102,81 @@ Module['Error'] = {
 
 /*****************************************************************************/
 /*                                                                           */
+/*                               MessengerError                              */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.MessengerError instance.
+ * @classdesc This class is a subclass of Error.
+ * @constructor proton.MessengerError
+ * @param the error message.
+ */
+Module['MessengerError'] = function(message) { // MessengerError constructor.
+    this.name = "MessengerError";
+    this.message = (message || "");
+};
+
+Module['MessengerError'].prototype = new Error();
+Module['MessengerError'].prototype.constructor = Module['MessengerError'];
+
+Module['MessengerError'].prototype.toString = function() {
+    return this.name + ': ' + this.message
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                MessageError                               */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.MessageError instance.
+ * @classdesc This class is a subclass of Error.
+ * @constructor proton.MessageError
+ * @param the error message.
+ */
+Module['MessageError'] = function(message) { // MessageError constructor.
+    this.name = "MessageError";
+    this.message = (message || "");
+};
+
+Module['MessageError'].prototype = new Error();
+Module['MessageError'].prototype.constructor = Module['MessageError'];
+
+Module['MessageError'].prototype.toString = function() {
+    return this.name + ': ' + this.message
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                  DataError                                */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.DataError instance.
+ * @classdesc This class is a subclass of Error.
+ * @constructor proton.DataError
+ * @param the error message.
+ */
+Module['DataError'] = function(message) { // DataError constructor.
+    this.name = "DataError";
+    this.message = (message || "");
+};
+
+Module['DataError'].prototype = new Error();
+Module['DataError'].prototype.constructor = Module['DataError'];
+
+Module['DataError'].prototype.toString = function() {
+    return this.name + ': ' + this.message
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
 /*                                 Messenger                                 */
 /*                                                                           */
 /*****************************************************************************/
@@ -138,11 +213,37 @@ Module['Messenger'] = function(name) { // Messenger Constructor.
      * fundamentally an asynchronous non-blocking execution environment.
      */
     _pn_messenger_set_blocking(this._messenger, false);
+
+    // Used in the Event registration mechanism (in the 'on' and 'emit' methods).
+    this._callbacks = {};
+
+    /*
+     * The emscripten websocket error event could get triggered by any Messenger
+     * and it's hard to determine which one without knowing which file descriptors
+     * are associated with which instance. As a workaround we set the _checkErrors
+     * flag when we call put or subscribe and reset it when work succeeds.
+     */
+    this._checkErrors = false;
+
+    /**
+     * TODO update to handle multiple Messenger instances
+     * Handle the emscripten websocket error and use it to trigger a MessengerError
+     * Note that the emscripten websocket error passes an array containing the
+     * file descriptor, the errno and the message, we just use the message here.
+     */
+    var that = this;
+    Module['websocket']['on']('error', function(error) {
+console.log("that._checkErrors = " + that._checkErrors);
+console.log("error = " + error);
+        if (that._checkErrors) {
+            that.emit('error', new Module['MessengerError'](error[2]));
+        }
+    });
 };
 
 Module['Messenger'].PN_CUMULATIVE = 0x1; // Protected Class attribute.
 
- // Expose prototype as a variable to make method declarations less verbose.
+// Expose prototype as a variable to make method declarations less verbose.
 var _Messenger_ = Module['Messenger'].prototype;
 
 // ************************* Protected methods ********************************
@@ -167,17 +268,29 @@ _Messenger_._check = function(code) {
         var errno = this['getErrno']();
         var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
 
-        throw { // TODO Improve name and level.
-            name:     'Messenger Error', 
-            level:    'Show Stopper', 
-            message:  message, 
-            toString: function() {return this.name + ': ' + this.message}
-        };
+        if (this._callbacks['error']) {
+            this.emit('error', new Module['MessengerError'](message));
+        } else {
+            throw new Module['MessengerError'](message);
+        }
     } else {
         return code;
     }
 };
 
+/**
+ * Invokes a callback registered for a specified event.
+ * @method emit
+ * @memberof! proton.Messenger#
+ * @param event the event we want to emit.
+ * @param param the parameter we'd like to pass to the event callback.
+ */
+_Messenger_.emit = function(event, param) {
+    if ('function' === typeof this._callbacks[event]) {
+        this._callbacks[event].call(this, param);
+    }
+};
+
 // *************************** Public methods *****************************
 
 /**
@@ -206,6 +319,40 @@ _Messenger_._check = function(code) {
  */
 
 /**
+ * Registers a listener callback for a specified event.
+ * @method on
+ * @memberof! proton.Messenger#
+ * @param event the event we want to listen for.
+ * @param callback the callback function to be registered for the specified event.
+ */
+_Messenger_['on'] = function(event, callback) {
+    if ('function' === typeof callback) {
+        if (event === 'work') {
+            Module.EventDispatch.addListener(this, callback);
+        } else {
+	        this._callbacks[event] = callback;
+        }
+    }
+};
+
+/**
+ * Removes a listener callback for a specified event.
+ * @method removeListener
+ * @memberof! proton.Messenger#
+ * @param event the event we want to detach from.
+ * @param callback the callback function to be remove for the specified event.
+ */
+_Messenger_['removeListener'] = function(event, callback) {
+    if ('function' === typeof callback) {
+        if (event === 'work') {
+            Module.EventDispatch.removeListener(this, callback);
+        } else {
+	        this._callbacks[event] = null;//callback;
+        }
+    }
+};
+
+/**
  * Retrieves the name of a Messenger.
  * @method getName
  * @memberof! proton.Messenger#
@@ -379,9 +526,11 @@ _Messenger_['subscribe'] = function(source) {
         this._check(Module['Error']['ARG_ERR']);
     }
     var sp = Runtime.stackSave();
+    this._checkErrors = true;
     var subscription = _pn_messenger_subscribe(this._messenger,
                                                allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
     Runtime.stackRestore(sp);
+
     if (!subscription) {
         this._check(Module['Error']['ERR']);
     }
@@ -409,6 +558,7 @@ _Messenger_['subscribe'] = function(source) {
  */
 _Messenger_['put'] = function(message) {
     message._preEncode();
+    this._checkErrors = true;
     this._check(_pn_messenger_put(this._messenger, message._message));
 
     // Getting the tracker is a little tricky as it is a 64 bit number. The way
@@ -451,7 +601,6 @@ _Messenger_['isBuffered'] = function(tracker) {
  * @param {proton.Data.Long} tracker the tracker identifying the delivery.
  */
 _Messenger_['settle'] = function(tracker) {
-console.log("settle: not fully tested yet");
     // Getting the tracker is a little tricky as it is a 64 bit number. The way
     // emscripten handles this is to return the low 32 bits directly and pass
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
@@ -469,15 +618,24 @@ console.log("settle: not fully tested yet");
 
 /**
  * Sends or receives any outstanding messages queued for a Messenger.
- * For JavaScript the only timeout that makes sense is 0 == do not block.
+ * For JavaScript the only timeout that makes sense is 0 (do not block).
  * This method may also do I/O work other than sending and receiving messages.
  * For example, closing connections after messenger.stop() has been called.
  * @method work
  * @memberof! proton.Messenger#
- * @returns {number} 0 if no work to do, < 0 if error, or 1 if work was done.
+ * @returns {boolean} true if there is work still to do, false otherwise.
  */
 _Messenger_['work'] = function() {
-    return _pn_messenger_work(this._messenger, 0);
+    var err = _pn_messenger_work(this._messenger, 0);
+    if (err === Module['Error']['TIMEOUT']) {
+console.log("work = false");
+        return false;
+    } else {
+        this._checkErrors = false;
+        this._check(err);
+console.log("work = true");
+        return true;
+    }
 };
 
 /**
@@ -513,9 +671,16 @@ _Messenger_['receiving'] = function() {
  * @memberof! proton.Messenger#
  * @param {proton.Message} message the destination message object. If no Message
  *        object is supplied, the Message popped from the head of the queue is discarded.
+ * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
+ *        objects as strings. This can be useful as the data in Binary objects
+ *        will be overwritten with subsequent calls to get, so they must be
+ *        explicitly copied. Needless to say it is only safe to set this flag if
+ *        you know that the data you are dealing with is actually a string, for
+ *        example C/C++ applications often seem to encode strings as AMQP binary,
+ *        a common cause of interoperability problems.
  * @returns {proton.Data.Long} a tracker for the incoming Message.
  */
-_Messenger_['get'] = function(message) {
+_Messenger_['get'] = function(message, decodeBinaryAsString) {
     var impl = null;
     if (message) {
         impl = message._message;
@@ -524,7 +689,7 @@ _Messenger_['get'] = function(message) {
     this._check(_pn_messenger_get(this._messenger, impl));
 
     if (message) {
-        message._postDecode();
+        message._postDecode(decodeBinaryAsString);
     }
 
     // Getting the tracker is a little tricky as it is a 64 bit number. The way
@@ -533,8 +698,6 @@ _Messenger_['get'] = function(message) {
     // low/high pair around to methods that require a tracker.
     var low = _pn_messenger_incoming_tracker(this._messenger);
     var high = Runtime.getTempRet0();
-console.log("get low = " + low);
-console.log("get high = " + high);
 
     return new Data.Long(low, high);
 };
@@ -548,8 +711,6 @@ console.log("get high = " + high);
  *          for this Messenger.
  */
 _Messenger_['incomingSubscription'] = function() {
-console.log("incomingSubscription: haven't yet proved this works yet");
-
     var subscription = _pn_messenger_incoming_subscription(this._messenger);
     if (subscription) {
         return new Subscription(subscription);
@@ -568,7 +729,6 @@ console.log("incomingSubscription: haven't yet proved this works yet");
  * @param {proton.Data.Long} tracker the tracker identifying the delivery.
  */
 _Messenger_['accept'] = function(tracker) {
-console.log("accept: not fully tested yet");
     // Getting the tracker is a little tricky as it is a 64 bit number. The way
     // emscripten handles this is to return the low 32 bits directly and pass
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
@@ -593,7 +753,6 @@ console.log("accept: not fully tested yet");
  * @param {proton.Data.Long} tracker the tracker identifying the delivery.
  */
 _Messenger_['reject'] = function(tracker) {
-console.log("reject: not fully tested yet");
     // Getting the tracker is a little tricky as it is a 64 bit number. The way
     // emscripten handles this is to return the low 32 bits directly and pass
     // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
@@ -629,17 +788,61 @@ _Messenger_['incoming'] = function() {
     return _pn_messenger_incoming(this._messenger);
 };
 
-
-
 /**
- * 
+ * Adds a routing rule to a Messenger's internal routing table.
+ * <p>
+ * The route method may be used to influence how a messenger will internally treat
+ * a given address or class of addresses. Every call to the route method will
+ * result in messenger appending a routing rule to its internal routing table.
+ * <p>
+ * Whenever a message is presented to a messenger for delivery, it will match the
+ * address of this message against the set of routing rules in order. The first
+ * rule to match will be triggered, and instead of routing based on the address
+ * presented in the message, the messenger will route based on the address supplied
+ * in the rule.
+ * <p>
+ * The pattern matching syntax supports two types of matches, a '' will match any
+ * character except a '/', and a '*' will match any character including a '/'.
+ * <p>
+ * A routing address is specified as a normal AMQP address, however it may
+ * additionally use substitution variables from the pattern match that triggered
+ * the rule.
+ * <p>
+ * Any message sent to "foo" will be routed to "amqp://foo.com":
+ * <pre>
+ * route("foo", "amqp://foo.com");
+ * </pre>
+ * Any message sent to "foobar" will be routed to "amqp://foo.com/bar":
+ * <pre>
+ * route("foobar", "amqp://foo.com/bar");
+ * </pre>
+ * Any message sent to bar/<path> will be routed to the corresponding path within
+ * the amqp://bar.com domain:
+ * <pre>
+ * route("bar/*", "amqp://bar.com/$1");
+ * </pre>
+ * Supply credentials for foo.com:
+ * <pre>
+ * route("amqp://foo.com/*", "amqp://user:password@foo.com/$1");
+ * </pre>
+ * Supply credentials for all domains:
+ * <pre>
+ * route("amqp://*", "amqp://user:password@$1");
+ * </pre>
+ * Route all addresses through a single proxy while preserving the original destination:
+ * <pre>
+ * route("amqp://%/*", "amqp://user:password@proxy/$1/$2");
+ * </pre>
+ * Route any address through a single broker:
+ * <pre>
+ * route("*", "amqp://user:password@broker/$1");
+ * </pre>
  * @method route
  * @memberof! proton.Messenger#
  * @param {string} pattern a glob pattern to select messages.
  * @param {string} address an address indicating outgoing address rewrite.
  */
 _Messenger_['route'] = function(pattern, address) {
-console.log("route: not fully tested yet");
     var sp = Runtime.stackSave();
     this._check(_pn_messenger_route(this._messenger,
                                     allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
@@ -648,6 +851,8 @@ console.log("route: not fully tested yet");
 };
 
 /**
+ * Rewrite message addresses prior to transmission.
+ * <p>
  * Similar to route(), except that the destination of the Message is determined
  * before the message address is rewritten.
  * <p>
@@ -665,7 +870,6 @@ console.log("route: not fully tested yet");
  * @param {string} address an address indicating outgoing address rewrite.
  */
 _Messenger_['rewrite'] = function(pattern, address) {
-console.log("rewrite: not fully tested yet");
     var sp = Runtime.stackSave();
     this._check(_pn_messenger_rewrite(this._messenger,
                                       allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
@@ -674,43 +878,133 @@ console.log("rewrite: not fully tested yet");
 };
 
 
+/*****************************************************************************/
+/*                                                                           */
+/*                               EventDispatch                               */
+/*                                                                           */
+/*****************************************************************************/
 
+/**
+ * EventDispatch is a Singleton class that allows callbacks to be registered that
+ * will get triggered by the emscripten WebSocket network callbacks. Clients of
+ * Messenger will register callbacks by calling:
+ * <pre>
+ * messenger.on('work', <callback function>);
+ * </pre>
+ * EventDispatch supports callback registration from multiple Messenger instances
+ * and supports multiple callbacks being registered for each instance. The client
+ * callbacks will actually be called when a given messenger has work available
+ * or a WebSocket close has been occurred (in which case all registered callbacks
+ * will be called).
+ * <p>
+ * The approach implemented here allows the registered callbacks to follow a
+ * similar pattern to _process_incoming and _process_outgoing in async.py
+ * @memberof proton
+ */
+Module.EventDispatch = new function() { // Note the use of new to create a Singleton.
+    var _firstCall = true; // Flag used to check the first time addListener is called.
+    var _messengers = {};
 
-// TODO This needs tweaking to enable working with multiple Messenger instances.
-_Messenger_['setNetworkCallback'] = function(callback) {
-//console.log("setting network callback");
+    /**
+     * Provides functionality roughly equivalent to the following C code:
+     * while (1) {
+     *     pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
+     *     process();
+     * }
+     * The blocking call isn't viable in JavaScript as it is entirely asynchronous
+     * and we wouldn't want to replace the while(1) with a timed loop either!!
+     * This method gets triggered asynchronously by the emscripten socket events and
+     * we then perform an equivalent loop for each messenger, triggering every
+     * registered callback whilst there is work remaining. If triggered by close
+     * we bypass the _pn_messenger_work test as it will never succeed after closing.
+     */
+    var _pump = function(fd, closing) {
+        for (var i in _messengers) {
+            if (_messengers.hasOwnProperty(i)) {
+                var current = _messengers[i];
+
+                if (closing) {
+                    current.invokeCallbacks();
+                } else {
+                    var messenger = current.messenger;
+                    while (_pn_messenger_work(messenger._messenger, 0) >= 0) {
+                        messenger._checkErrors = false;
+                        current.invokeCallbacks();
+                    }
+                }
+            }
+        }
+    };
 
-    // Expose messenger reference in the scope of Messenger.Messenger so that
-    // the _work function can correctly dereference it.
-    var messenger = this._messenger;
+    /**
+     * Listener for the emscripten socket close event. Delegates to _pump()
+     * passing a flag to indicate that the socket is closing.
+     */
+    var _close = function(fd) {
+        _pump(fd, true);
+    };
 
-    function _work() {
-        //console.log("                          *** internal work ***");
+    /**
+     * Initialises the emscripten network callback functions. This needs to be
+     * done the first time we call addListener rather that when we create the
+     * Singleton because emscripten's socket filesystem has to be mounted before
+     * we can register listeners for any of these events.
+     */
+    var _init = function() {
+        Module['websocket']['on']('open', _pump);
+        Module['websocket']['on']('connection', _pump);
+        Module['websocket']['on']('message', _pump);
+        Module['websocket']['on']('close', _close);
+    };
 
-        var err = _pn_messenger_work(messenger, 0);
-//console.log("err = " + err);
+    /**
+     * Add a listener callback for the specified Messenger. Multiple listeners
+     * are permitted for each Messenger and listeners can be registered for
+     * multiple Messenger instances. The first time this method is called we
+     * initialise the emscripten network callback functions.
+     */
+    this.addListener = function(messenger, callback) {
+        if (_firstCall) {
+            _init();
+            _firstCall = false;
+        }
 
-        if (err >= 0) {
-            callback();
+        var name = messenger.getName();
+        if (!_messengers[name]) {
+            _messengers[name] = {
+                messenger: messenger,
+                callbacks: [],
+                invokeCallbacks: function() {
+                    for (var j = 0; j < this.callbacks.length; j++) {
+                        this.callbacks[j]();
+                    }
+                }
+            };
         }
 
-        err = _pn_messenger_work(messenger, 0);
-//console.log("err = " + err);
+        _messengers[name].callbacks.push(callback);
+    };
 
-        if (err >= 0) {
-            callback();
+    /**
+     * Remove the specified listener callback from the specified Messenger.
+     */
+    this.removeListener = function(messenger, callback) {
+        var name = messenger.getName();
+        if (_messengers[name]) {
+            // If we find the registered Messenger search for the specified callback.
+            var callbacks = _messengers[name].callbacks;
+            for (var j = 0; j < callbacks.length; j++) {
+                if (callback === callbacks[j]) {
+                    // If we find the specified callback delete it and return.
+                    callbacks.splice(j, 1);
+                    return;
+                }
+            }
         }
     };
-
-    // Set the emscripten network callback function.
-    Module['networkCallback'] = _work;
 };
 
 
-
-
-
-
 /*****************************************************************************/
 /*                                                                           */
 /*                               Subscription                                */
@@ -767,41 +1061,43 @@ Subscription.prototype['getAddress'] = function() {
 
 /**
  * Constructs a proton.Message instance.
- * @classdesc This class is
+ * @classdesc This class is a mutable holder of message content that may be used
+ * to generate and encode or decode and access AMQP formatted message data.
  * @constructor proton.Message
+ * @property {object} instructions delivery instructions for the message.
+ * @property {object} annotations infrastructure defined message annotations.
+ * @property {object} properties application defined message properties.
+ * @property {object} body message body as a native JavaScript Object.
+ * @property {object} data message body as a proton.Data Object.
  */
 Module['Message'] = function() { // Message Constructor.
     this._message = _pn_message();
+    this._id = new Data(_pn_message_id(this._message));
+    this._correlationId = new Data(_pn_message_correlation_id(this._message));
 
     // ************************* Public properties ****************************
 
-    /**
-     * Delivery instructions for the Message.
-     * @type map
-     */
     this['instructions'] = null;
-
-    /**
-     * Infrastructure defined Message annotations.
-     * @type map
-     */
     this['annotations'] = null;
 
-    /**
-     * Application defined Message properties.
-     * @type map
-     */
+    // Intitialise with an empty Object so we can set properties in a natural way.
+    // message.properties.prop1 = "foo";
+    // message.properties.prop2 = "bar";
     this['properties'] = {};
 
-    /**
-     * Message body.
-     * @type bytes | unicode | map | list | int | long | float | UUID
-     */
     this['body'] = null;
+    this['data'] = null;
 };
 
+// Expose constructor as package scope variable to make internal calls less verbose.
+var Message = Module['Message'];
+
 // Expose prototype as a variable to make method declarations less verbose.
-var _Message_ = Module['Message'].prototype;
+var _Message_ = Message.prototype;
+
+// ************************** Class properties ********************************
+
+Message['DEFAULT_PRIORITY'] = 4; /** Default priority for messages.*/
 
 // ************************* Protected methods ********************************
 
@@ -821,12 +1117,7 @@ _Message_._check = function(code) {
         var errno = this['getErrno']();
         var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
 
-        throw { // TODO Improve name and level.
-            name:     'Message Error', 
-            level:    'Show Stopper', 
-            message:  message, 
-            toString: function() {return this.name + ': ' + this.message} 
-        };
+        throw new Module['MessageError'](message);
     } else {
         return code;
     }
@@ -845,37 +1136,40 @@ _Message_._preEncode = function() {
 
     inst.clear();
     if (this['instructions']) {
-console.log("Encoding instructions");
         inst['putObject'](this['instructions']);
     }
 
     ann.clear();
     if (this['annotations']) {
-console.log("Encoding annotations");
         ann['putObject'](this['annotations']);
     }
 
     props.clear();
     if (this['properties']) {
-console.log("Encoding properties");
         props['putObject'](this['properties']);
     }
 
     body.clear();
     if (this['body']) {
-console.log("Encoding body");
         body['putObject'](this['body']);
     }
 };
 
 /**
  * Decode the Message after receiving off the wire.
- */
-_Message_._postDecode = function() {
+ * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
+ *        objects as strings. This can be useful as the data in Binary objects
+ *        will be overwritten with subsequent calls to get, so they must be
+ *        explicitly copied. Needless to say it is only safe to set this flag if
+ *        you know that the data you are dealing with is actually a string, for
+ *        example C/C++ applications often seem to encode strings as AMQP binary,
+ *        a common cause of interoperability problems.
+ */
+_Message_._postDecode = function(decodeBinaryAsString) {
     var inst = new Data(_pn_message_instructions(this._message));
     var ann = new Data(_pn_message_annotations(this._message));
     var props = new Data(_pn_message_properties(this._message));
-    var body = new Data(_pn_message_body(this._message));
+    var body = new Data(_pn_message_body(this._message), decodeBinaryAsString);
 
     if (inst.next()) {
         this['instructions'] = inst['getObject']();
@@ -896,8 +1190,10 @@ _Message_._postDecode = function() {
     }
 
     if (body.next()) {
+        this['data'] = body;
         this['body'] = body['getObject']();
     } else {
+        this['data'] = null;
         this['body'] = null;
     }
 };
@@ -935,6 +1231,293 @@ _Message_['getError'] = function() {
 };
 
 /**
+ * Clears the contents of the Message. All fields will be reset to their default values.
+ * @method clear
+ * @memberof! proton.Message#
+ */
+_Message_['clear'] = function() {
+    _pn_message_clear(this._message);
+    this['instructions'] = null;
+    this['annotations'] = null;
+    this['properties'] = {};
+    this['body'] = null;
+    this['data'] = null;
+};
+
+/**
+ * Get the inferred flag for a message.
+ * <p>
+ * The inferred flag for a message indicates how the message content
+ * is encoded into AMQP sections. If inferred is true then binary and
+ * list values in the body of the message will be encoded as AMQP DATA
+ * and AMQP SEQUENCE sections, respectively. If inferred is false,
+ * then all values in the body of the message will be encoded as AMQP
+ * VALUE sections regardless of their type. Use
+ * {@link proton.Message.setInferred} to set the value.
+ * @method isInferred
+ * @memberof! proton.Message#
+ * @returns {boolean} true iff the inferred flag for the message is set.
+ */
+_Message_['isInferred'] = function() {
+    return (_pn_message_is_inferred(this._message) > 0);
+};
+
+/**
+ * Set the inferred flag for a message. See {@link proton.Message.isInferred} 
+ * for a description of what the inferred flag is.
+ * @method setInferred
+ * @memberof! proton.Message#
+ * @param {boolean} inferred the new value of the inferred flag.
+ */
+_Message_['setInferred'] = function(inferred) {
+    this._check(_pn_message_set_inferred(this._message, inferred));
+};
+
+/**
+ * Get the durable flag for a message.
+ * <p>
+ * The durable flag indicates that any parties taking responsibility
+ * for the message must durably store the content. Use
+ * {@link proton.Message.setDurable} to set the value.
+ * @method isDurable
+ * @memberof! proton.Message#
+ * @returns {boolean} true iff the durable flag for the message is set.
+ */
+_Message_['isDurable'] = function() {
+    return (_pn_message_is_durable(this._message) > 0);
+};
+
+/**
+ * Set the durable flag for a message. See {@link proton.Message.isDurable} 
+ * for a description of what the durable flag is.
+ * @method setDurable
+ * @memberof! proton.Message#
+ * @param {boolean} durable the new value of the durable flag.
+ */
+_Message_['setDurable'] = function(durable) {
+    this._check(_pn_message_set_durable(this._message, durable));
+};
+
+/**
+ * Get the priority for a message.
+ * <p>
+ * The priority of a message impacts ordering guarantees. Within a
+ * given ordered context, higher priority messages may jump ahead of
+ * lower priority messages. Priority range is 0..255
+ * @method getPriority
+ * @memberof! proton.Message#
+ * @returns {number} the priority of the Message.
+ */
+_Message_['getPriority'] = function() {
+    return _pn_message_get_priority(this._message) & 0xFF; // & 0xFF converts to unsigned.
+};
+
+/**
+ * Set the priority of the Message. See {@link proton.Message.getPriority}
+ * for details on message priority.
+ * @method setPriority
+ * @memberof! proton.Message#
+ * @param {number} priority the address we want to send the Message to.
+ */
+_Message_['setPriority'] = function(priority) {
+    this._check(_pn_message_set_priority(this._message, priority));
+};
+
+/**
+ * Get the ttl for a message.
+ * <p>
+ * The ttl for a message determines how long a message is considered
+ * live. When a message is held for retransmit, the ttl is
+ * decremented. Once the ttl reaches zero, the message is considered
+ * dead. Once a message is considered dead it may be dropped. Use
+ * {@link proton.Message.setTTL} to set the ttl for a message.
+ * @method getTTL
+ * @memberof! proton.Message#
+ * @returns {number} the ttl in milliseconds.
+ */
+_Message_['getTTL'] = function() {
+    return _pn_message_get_ttl(this._message);
+};
+
+/**
+ * Set the ttl for a message. See {@link proton.Message.getTTL}
+ * for a detailed description of message ttl.
+ * @method setTTL
+ * @memberof! proton.Message#
+ * @param {number} ttl the new value for the message ttl in milliseconds.
+ */
+_Message_['setTTL'] = function(ttl) {
+    this._check(_pn_message_set_ttl(this._message, ttl));
+};
+
+/**
+ * Get the first acquirer flag for a message.
+ * <p>
+ * When set to true, the first acquirer flag for a message indicates
+ * that the recipient of the message is the first recipient to acquire
+ * the message, i.e. there have been no failed delivery attempts to
+ * other acquirers. Note that this does not mean the message has not
+ * been delivered to, but not acquired, by other recipients.
+ * @method isFirstAcquirer
+ * @memberof! proton.Message#
+ * @returns {boolean} true iff the first acquirer flag for the message is set.
+ */
+_Message_['isFirstAcquirer'] = function() {
+    return (_pn_message_is_first_acquirer(this._message) > 0);
+};
+
+/**
+ * Set the first acquirer flag for a message. See {@link proton.Message.isFirstAcquirer} 
+ * for details on the first acquirer flag.
+ * @method setFirstAcquirer
+ * @memberof! proton.Message#
+ * @param {boolean} first the new value of the first acquirer flag.
+ */
+_Message_['setFirstAcquirer'] = function(first) {
+    this._check(_pn_message_set_first_acquirer(this._message, first));
+};
+
+/**
+ * Get the delivery count for a message.
+ * <p>
+ * The delivery count field tracks how many attempts have been made to
+ * deliver a message. Use {@link proton.Message.setDeliveryCount} to set
+ * the delivery count for a message.
+ * @method getDeliveryCount
+ * @memberof! proton.Message#
+ * @returns {number} the delivery count for the message.
+ */
+_Message_['getDeliveryCount'] = function() {
+    return _pn_message_get_delivery_count(this._message);
+};
+
+/**
+ * Set the delivery count for a message. See {@link proton.Message.getDeliveryCount}
+ * for details on what the delivery count means.
+ * @method setDeliveryCount
+ * @memberof! proton.Message#
+ * @param {number} count the new delivery count.
+ */
+_Message_['setDeliveryCount'] = function(count) {
+    this._check(_pn_message_set_delivery_count(this._message, count));
+};
+
+/**
+ * Get the id for a message.
+ * <p>
+ * The message id provides a globally unique identifier for a message.
+ * A message id can be an a string, an unsigned long, a uuid or a binary value.
+ * @method getID
+ * @memberof! proton.Message#
+ * @returns {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} the message id.
+ */
+_Message_['getID'] = function() {
+    return this._id['getObject']();
+};
+
+/**
+ * Set the id for a message. See {@link proton.Message.getID}
+ * for more details on the meaning of the message id. Note that only string,
+ * unsigned long, uuid, or binary values are permitted.
+ * @method setID
+ * @memberof! proton.Message#
+ * @param {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} id the
+ *        new value of the message id.
+ */
+_Message_['setID'] = function(id) {
+    this._id['rewind']();
+    if (Data.isNumber(id)) {
+        this._id['putULONG'](id);
+    } else {
+        this._id['putObject'](id);
+    }
+};
+
+/**
+ * Get the user id of the message creator.
+ * <p>
+ * The underlying raw data of the returned {@link proton.Data.Binary} will be
+ * valid until any one of the following operations occur:
+ * <pre>
+ *  - {@link proton.Message.free}
+ *  - {@link proton.Message.clear}
+ *  - {@link proton.Message.setUserID}
+ * </pre>
+ * @method getUserID
+ * @memberof! proton.Message#
+ * @returns {proton.Data.Binary} the message's user id.
+ */
+_Message_['getUserID'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes_t bytes = pn_message_get_user_id(message);
+
+    // Here's the quirky bit, pn_message_get_user_id actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_message_get_user_id.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_message_get_user_id(bytes, this._message);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a proton.Data.Binary from the pn_bytes_t information.
+    var binary = new Data['Binary'](size, start);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return binary;
+};
+
+/**
+ * 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
+ * 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
+ * @memberof! proton.Message#
+ * @param {(string||proton.Data.Uuid)} id the new user id for the message.
+ */
+_Message_['setUserID'] = function(id) {
+    // If the id parameter is a proton.Data.Binary use it otherwise create a Binary
+    // using the string form of the parameter that was passed.
+    id = (id instanceof Data['Binary']) ? id : new Data['Binary']('' + id);
+
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_message_set_user_id(message, pn_bytes(id.size, id.start));
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, id.size, id.start);
+
+    // The compiled pn_message_set_user_id takes the pn_bytes_t by reference not value.
+    this._check(_pn_message_set_user_id(this._message, bytes));
+
+    // After calling _pn_message_set_user_id the underlying Message object "owns" the
+    // binary data, so we can call free on the proton.Data.Binary instance to
+    // release any storage it has acquired back to the emscripten heap.
+    id['free']();
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the address for a message.
  * @method getAddress
  * @memberof! proton.Message#
  * @returns {string} the address of the Message.
@@ -956,6 +1539,7 @@ _Message_['setAddress'] = function(address) {
 };
 
 /**
+ * Get the subject for a message.
  * @method getSubject
  * @memberof! proton.Message#
  * @returns {string} the subject of the Message.
@@ -976,17 +1560,302 @@ _Message_['setSubject'] = function(subject) {
     Runtime.stackRestore(sp);
 };
 
+/**
+ * Get the reply to for a message.
+ * @method getReplyTo
+ * @memberof! proton.Message#
+ * @returns {string} the reply to of the Message.
+ */
+_Message_['getReplyTo'] = function() {
+    return Pointer_stringify(_pn_message_get_reply_to(this._message));
+};
 
+/**
+ * Set the reply to for a message.
+ * @method setReplyTo
+ * @memberof! proton.Message#
+ * @param {string} reply the reply to we want to set for the Message.
+ */
+_Message_['setReplyTo'] = function(reply) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_reply_to(this._message, allocate(intArrayFromString(reply), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
 
+/**
+ * Get the correlation id for a message.
+ * <p>
+ * A correlation id can be an a string, an unsigned long, a uuid or a binary value.
+ * @method getCorrelationID
+ * @memberof! proton.Message#
+ * @returns {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} the message id.
+ */
+_Message_['getCorrelationID'] = function() {
+    return this._correlationId['getObject']();
+};
 
+/**
+ * Set the correlation id for a message. See {@link proton.Message.getCorrelationID}
+ * for more details on the meaning of the correlation id. Note that only string,
+ * unsigned long, uuid, or binary values are permitted.
+ * @method setCorrelationID
+ * @memberof! proton.Message#
+ * @param {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} id the
+ *        new value of the correlation id.
+ */
+_Message_['setCorrelationID'] = function(id) {
+    this._correlationId['rewind']();
+    if (Data.isNumber(id)) {
+        this._correlationId['putULONG'](id);
+    } else {
+        this._correlationId['putObject'](id);
+    }
+};
 
+/**
+ * Get the content type for a message.
+ * @method getContentType
+ * @memberof! proton.Message#
+ * @returns {string} the content type of the Message.
+ */
+_Message_['getContentType'] = function() {
+    return Pointer_stringify(_pn_message_get_content_type(this._message));
+};
 
+/**
+ * Set the content type for a message.
+ * @method setContentType
+ * @memberof! proton.Message#
+ * @param {string} type the content type we want to set for the Message.
+ */
+_Message_['setContentType'] = function(type) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_content_type(this._message, allocate(intArrayFromString(type), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
 
+/**
+ * Get the content encoding for a message.
+ * @method getContentEncoding
+ * @memberof! proton.Message#
+ * @returns {string} the content encoding of the Message.
+ */
+_Message_['getContentEncoding'] = function() {
+    return Pointer_stringify(_pn_message_get_content_encoding(this._message));
+};
 
+/**
+ * Set the content encoding for a message.
+ * @method setContentEncoding
+ * @memberof! proton.Message#
+ * @param {string} encoding the content encoding we want to set for the Message.
+ */
+_Message_['setContentEncoding'] = function(encoding) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_content_encoding(this._message, allocate(intArrayFromString(encoding), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the expiry time for a message.
+ * A zero value for the expiry time indicates that the message will
+ * never expire. This is the default value.
+ * @method getExpiryTime
+ * @memberof! proton.Message#
+ * @returns {Date} the expiry time for the message.
+ */
+_Message_['getExpiryTime'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_message_get_expiry_time(this._message);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
+};
+
+/**
+ * Set the expiry time for a message.
+ * @method setExpiryTime
+ * @memberof! proton.Message#
+ * @param {(number|Date)} time the new expiry time for the message.
+ */
+_Message_['setExpiryTime'] = function(time) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(time.valueOf());
+    this._check(_pn_message_set_expiry_time(this._message, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
+};
 
+/**
+ * Get the creation time for a message.
+ * A zero value for the creation time indicates that the creation time
+ * has not been set. This is the default value.
+ * @method getCreationTime
+ * @memberof! proton.Message#
+ * @returns {Date} the creation time for the message.
+ */
+_Message_['getCreationTime'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_message_get_creation_time(this._message);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
+};
 
+/**
+ * Set the creation time for a message.
+ * @method setCreationTime
+ * @memberof! proton.Message#
+ * @param {(number|Date)} time the new creation time for the message.
+ */
+_Message_['setCreationTime'] = function(time) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(time.valueOf());
+    this._check(_pn_message_set_creation_time(this._message, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
+};
 
+/**
+ * Get the group id for a message.
+ * @method getGroupID
+ * @memberof! proton.Message#
+ * @returns {string} the group id of the Message.
+ */
+_Message_['getGroupID'] = function() {
+    return Pointer_stringify(_pn_message_get_group_id(this._message));
+};
 
+/**
+ * Set the group id for a message.
+ * @method setGroupID
+ * @memberof! proton.Message#
+ * @param {string} id the group id we want to set for the Message.
+ */
+_Message_['setGroupID'] = function(id) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_group_id(this._message, allocate(intArrayFromString(id), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the group sequence for a message.
+ * <p>
+ * The group sequence of a message identifies the relative ordering of
+ * messages within a group. The default value for the group sequence
+ * of a message is zero.
+ * @method getGroupSequence
+ * @memberof! proton.Message#
+ * @returns {number} the group sequence for the message.
+ */
+_Message_['getGroupSequence'] = function() {
+    return _pn_message_get_group_sequence(this._message);
+};
+
+/**
+ * Set the group sequence for a message. See {@link proton.Message.getGroupSequence}
+ * for details on what the group sequence means.
+ * @method setGroupSequence
+ * @memberof! proton.Message#
+ * @param {number} n the new group sequence for the message.
+ */
+_Message_['setGroupSequence'] = function(n) {
+    this._check(_pn_message_set_group_sequence(this._message, n));
+};
+
+/**
+ * Get the reply to group id for a message.
+ * @method getReplyToGroupID
+ * @memberof! proton.Message#
+ * @returns {string} the reply to group id of the Message.
+ */
+_Message_['getReplyToGroupID'] = function() {
+    return Pointer_stringify(_pn_message_get_reply_to_group_id(this._message));
+};
+
+/**
+ * Set the reply to group id for a message.
+ * @method setReplyToGroupID
+ * @memberof! proton.Message#
+ * @param {string} id the reply to group id we want to set for the Message.
+ */
+_Message_['setReplyToGroupID'] = function(id) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_reply_to_group_id(this._message, allocate(intArrayFromString(id), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * The following methods are marked as deprecated and are not implemented.
+ * pn_message_get_format()
+ * pn_message_set_format()
+ * pn_message_load()
+ * pn_message_load_data()
+ * pn_message_load_text()
+ * pn_message_load_amqp()
+ * pn_message_load_json()
+ * pn_message_save()
+ * pn_message_save_data()
+ * pn_message_save_text()
+ * pn_message_save_amqp()
+ * pn_message_save_json()
+ * pn_message_data()
+ */
+
+/**
+ * Return a Binary representation of the message encoded in AMQP format. N.B. the
+ * returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
+ * responsible for freeing it or passing it to a method that consumes a Binary
+ * such as {@link proton.Message.decode}.
+ * @method encode
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Binary} a representation of the message encoded in AMQP format.
+ */
+_Message_['encode'] = function() {
+    this._preEncode();
+    var size = 1024;
+    while (true) {
+        setValue(size, size, 'i32'); // Set pass by reference variable.
+        var bytes = _malloc(size);   // Allocate storage from emscripten heap.
+        var err = _pn_message_encode(this._message, bytes, size);
+        var size = getValue(size, 'i32'); // Dereference the real size value;
+
+        if (err === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else if (err >= 0) {
+            return new Data['Binary'](size, bytes);
+        } else {
+            _free(bytes);
+            this._check(err);
+            return;
+        }
+    }
+};
+
+/**
+ * Decodes and loads the message content from supplied Binary AMQP data  N.B. 
+ * this method "consumes" data from a {@link proton.Data.Binary} in other words
+ * it takes responsibility for the underlying data and frees the raw data from
+ * the Binary.
+ * @method decode
+ * @memberof! proton.Data#
+ * @param {proton.Data.Binary} encoded the AMQP encoded binary message.
+ */
+_Message_['decode'] = function(encoded) {
+    var err = _pn_message_decode(this._message, encoded.start, encoded.size);
+    encoded['free'](); // Free the original Binary.
+    if (err >= 0) {
+        this._postDecode();
+    }
+    this._check(err);
+};
 
 
 /*****************************************************************************/
@@ -1025,8 +1894,15 @@ _Message_['setSubject'] = function(subject) {
  *        necessary. If no data is supplied then the Data is stand-alone and the
  *        client application is responsible for freeing the underlying data via
  *        a call to free().
- */
-Module['Data'] = function(data) { // Data Constructor.
+ * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
+ *        objects as strings. This can be useful as the data in Binary objects
+ *        will be overwritten with subsequent calls to get, so they must be
+ *        explicitly copied. Needless to say it is only safe to set this flag if
+ *        you know that the data you are dealing with is actually a string, for
+ *        example C/C++ applications often seem to encode strings as AMQP binary,
+ *        a common cause of interoperability problems.
+ */
+Module['Data'] = function(data, decodeBinaryAsString) { // Data Constructor.
     if (!data) {
         this._data = _pn_data(16); // Default capacity is 16
         this['free'] = function() {
@@ -1038,6 +1914,7 @@ Module['Data'] = function(data) { // Data Constructor.
         this._data = data;
         this['free'] = function() {};
     }
+    this._decodeBinaryAsString = decodeBinaryAsString;
 };
 
 // Expose constructor as package scope variable to make internal calls less verbose.
@@ -1821,12 +2698,7 @@ _Data_._check = function(code) {
         var errno = this['getErrno']();
         var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
 
-        throw { // TODO Improve name and level.
-            name:     'Data Error', 
-            level:    'Show Stopper', 
-            message:  message, 
-            toString: function() {return this.name + ': ' + this.message} 
-        };
+        throw new Module['DataError'](message);
     } else {
         return code;
     }
@@ -1966,7 +2838,7 @@ _Data_['type'] = function() {
  * returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
  * responsible for freeing it or passing it to a method that consumes a Binary
  * such as {@link proton.Data.decode} or {@link proton.Data.putBINARY}.
- * @method type
+ * @method encode
  * @memberof! proton.Data#
  * @returns {proton.Data.Binary} a representation of the data encoded in AMQP format.
  */
@@ -2221,7 +3093,7 @@ _Data_['putLONG'] = function(l) {
  * Puts a timestamp.
  * @method putTIMESTAMP
  * @memberof! proton.Data#
- * @param {Date} d a Date value.
+ * @param {(number|Date)} d a Date value.
  */
 _Data_['putTIMESTAMP'] = function(d) {
     // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
@@ -2596,7 +3468,7 @@ _Data_['getULONG'] = function() {
     var high = Runtime.getTempRet0();
     var long = new Data.Long(low, high);
     long = long.toNumber();
-    return (long > 0) ? long : Data.Long.TWO_PWR_64_DBL_ + long;
+    return (long >= 0) ? long : Data.Long.TWO_PWR_64_DBL_ + long;
 };
 
 /**
@@ -2744,7 +3616,12 @@ _Data_['getBINARY'] = function() {
     // Tidy up the memory that we allocated on emscripten's stack.
     Runtime.stackRestore(sp);
 
-    return binary;
+    // If _decodeBinaryAsString is set return the stringified form of the Binary.
+    if (this._decodeBinaryAsString) {
+        return binary.toString();
+    } else {
+        return binary;
+    }
 };
 
 /**
@@ -3101,11 +3978,7 @@ _Data_['getARRAY'] = function() {
  * @param {object} obj the JavaScript Object or primitive to be serialised.
  */
 _Data_['putObject'] = function(obj) {
-console.log("Data.putObject");
-
-console.log("obj = " + obj);
-//console.log("typeof obj = " + (typeof obj));
-//console.log("obj prototype = " + Object.prototype.toString.call(obj));
+//console.log("Data.putObject " + obj);
 
     if (obj == null) { // == Checks for null and undefined.
         this['putNULL']();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/proton-c/bindings/javascript/my-library.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/my-library.js b/proton-c/bindings/javascript/my-library.js
index b35ccd1..af89ef4 100644
--- a/proton-c/bindings/javascript/my-library.js
+++ b/proton-c/bindings/javascript/my-library.js
@@ -27,11 +27,52 @@ mergeInto(LibraryManager.library, {
 // Hacks below
 // -----------------------------------------------------------------------------------------------------------------
 
-
   $SOCKFS__postset: '__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });',
   $SOCKFS__deps: ['$FS'],
   $SOCKFS: {
     mount: function(mount) {
+      // If Module['websocket'] has already been defined (e.g. for configuring
+      // subprotocol/url) use that, if not initialise it to a new object.
+      Module['websocket'] = (Module['websocket'] && 
+                             ('object' === typeof Module['websocket'])) ? Module['websocket'] : {};
+
+      // Add Event registration mechanism to the exported websocket configuration
+      // object so we can register network callbacks from native JavaScript too.
+      Module['websocket']._callbacks = {};
+      Module['websocket'].on = function(event, callback) {
+	    if ('function' === typeof callback) {
+		  this._callbacks[event] = callback;
+        }
+	    return this;
+      };
+
+      Module['websocket'].emit = function(event, param) {
+	    if ('function' === typeof this._callbacks[event]) {
+		  this._callbacks[event].call(this, param);
+        }
+      };
+
+      // Register default null callbacks for each Event
+      Module['websocket'].on("error", function(error) {
+console.log("Websocket error " + error);
+	  });
+
+      Module['websocket'].on("open", function(fd) {
+console.log("Websocket open fd = " + fd);
+	  });
+
+      Module['websocket'].on("connection", function(fd) {
+console.log("Websocket connection fd = " + fd);
+	  });
+
+      Module['websocket'].on("message", function(fd) {
+console.log("Websocket message fd = " + fd);
+	  });
+
+      Module['websocket'].on("close", function(fd) {
+console.log("Websocket close fd = " + fd);
+	  });
+
       return FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
     },
     createSocket: function(family, type, protocol) {
@@ -279,7 +320,7 @@ console.log("handleOpen triggering networkCallback");
             Module['networkCallback']();
           }
 
-
+          Module['websocket'].emit('open', 10);
 
         };
 
@@ -317,6 +358,8 @@ console.log("handleMessage triggering networkCallback");
             Module['networkCallback']();
           }
 
+          Module['websocket'].emit('message', 10);
+
 
         };
 
@@ -328,15 +371,24 @@ console.log("handleMessage triggering networkCallback");
             }
             handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
           });
+          peer.socket.on('close', function() {
+            Module['websocket'].emit('close', 10);
+          });
           peer.socket.on('error', function(error) {
-console.log('error ' + error);
+            Module['websocket'].emit('error', error);
             // don't throw
           });
         } else {
           peer.socket.onopen = handleOpen;
+          peer.socket.onclose = function() {
+            Module['websocket'].emit('close', 10);
+          };
           peer.socket.onmessage = function peer_socket_onmessage(event) {
             handleMessage(event.data);
           };
+          peer.socket.onerror = function(error) {
+            Module['websocket'].emit('error', error);
+          };
         }
       },
 
@@ -504,26 +556,24 @@ console.log('close');
             SOCKFS.websocket_sock_ops.createPeer(sock, ws);
           }
 
-
-
-
-
-
           if (Module['networkCallback']) {
 console.log("On connection triggering networkCallback");
 
             Module['networkCallback']();
           }
 
+          Module['websocket'].emit('connection', 10);
 
 
         });
         sock.server.on('closed', function() {
 console.log('sock.server closed');
+          Module['websocket'].emit('close', 10);
           sock.server = null;
         });
-        sock.server.on('error', function() {
+        sock.server.on('error', function(error) {
 console.log('sock.server error');
+          Module['websocket'].emit('error', error);
           // don't throw
         });
       },

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a61e5f9c/tests/javascript/codec.js
----------------------------------------------------------------------
diff --git a/tests/javascript/codec.js b/tests/javascript/codec.js
index 95e36e4..36156ae 100644
--- a/tests/javascript/codec.js
+++ b/tests/javascript/codec.js
@@ -30,7 +30,7 @@ if (typeof exports !== "undefined" && exports !== null) {
     proton = require("qpid-proton");
 }
 
-// We extend TestCase by creating an instance and adding test methods as properties.
+// Extend TestCase by creating a prototype instance and adding test methods as properties.
 var DataTest = new unittest.TestCase();
 
 DataTest.setUp = function() {


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


[32/51] [abbrv] qpid-proton git commit: Refactor JavaScript binding from a single ludicrously huge binding.js into a set of sub-modules that should hopefully make maintenance much simpler

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/data-array.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-array.js b/proton-c/bindings/javascript/data-array.js
new file mode 100644
index 0000000..6f9776d
--- /dev/null
+++ b/proton-c/bindings/javascript/data-array.js
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Array                             */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * TODO make this behave more like a native JavaScript Array: http://www.bennadel.com/blog/2292-extending-javascript-arrays-while-keeping-native-bracket-notation-functionality.htm
+ * Create a proton.Data.Array.
+ * @classdesc
+ * This class represents an AMQP Array.
+ * @constructor proton.Data.Array
+ * @param {string|number} type the type of the Number either as a string or number.
+ *        Stored internally as a string corresponding to one of the TypeNames.       
+ * @param {Array|TypedArray} elements the Native JavaScript Array or TypedArray that we wish to serialise.
+ * @param {object} descriptor an optional object describing the type.
+ */
+Data['Array'] = function(type, elements, descriptor) { // Data.Array Constructor.
+    // This block caters for an empty Array or a Described empty Array.
+    if (arguments.length < 2) {
+        descriptor = type;
+        type = 'NULL';
+        elements = [];
+    }
+
+    this['type']  = (typeof type === 'number') ? Data['TypeNames'][type] : type;
+    this['elements'] = elements;
+    this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Array#
+ * @returns {string} the String form of a {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.toString = function() {
+    var descriptor = (this['descriptor'] == null) ? '' : ':' + this['descriptor'];
+    return this['type'] + 'Array' + descriptor + '[' + this['elements'] + ']';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Array#
+ * @returns {Array} the elements of the {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.valueOf = function() {
+    return this['elements'];
+};
+
+/**
+ * Compare two instances of proton.Data.Array for equality. N.B. this method
+ * compares the value of every Array element so its performance is O(n).
+ * @method equals
+ * @memberof! proton.Data.Array#
+ * @param {proton.Data.Array} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Array'].prototype['equals'] = function(rhs) {
+    if (rhs instanceof Data['Array'] &&
+        // Check the string value of the descriptors.
+        (('' + this['descriptor']) === ('' + rhs['descriptor'])) &&
+        (this['type'] === rhs['type'])) {
+        var elements = this['elements'];
+        var relements = rhs['elements'];
+        var length = elements.length;
+        if (length === relements.length) {
+            for (var i = 0; i < length; i++) {
+                if (elements[i].valueOf() !== relements[i].valueOf()) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    } else {
+        return false;
+    }
+};
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/data-binary.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-binary.js b/proton-c/bindings/javascript/data-binary.js
new file mode 100644
index 0000000..27bac59
--- /dev/null
+++ b/proton-c/bindings/javascript/data-binary.js
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Binary                            */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Binary. This constructor takes one or two parameters.
+ * The first parameter may serve different purposes depending on its type;
+ * If value is a number then it represents the size of the Binary data buffer,
+ * if it is a string then we copy the string to the buffer, if it is an Array
+ * or a TypedArray then we copy the data to the buffer. The optional second
+ * parameter is a pointer to the data in an internal data store. If start is
+ * not specified then the number of bytes specified in the first parameter
+ * will be allocated in the internal data store and start will point to the
+ * start of that block of data.
+ * @classdesc
+ * This class represents an AMQP Binary type. This class allows us to create and
+ * use raw binary data and map it efficiently between JavaScript client code and
+ * the underlying implementation, where all data is managed on a "virtual heap".
+ * <p>
+ * Client applications should generally not have to care about memory management
+ * as, for most common use cases, client applications would "transfer ownership"
+ * to a "container" which would then "own" the underlying data and free the data
+ * held by the {@link proton.Data.Binary}.
+ * <p>
+ * As an example one common use-case would be where client application creates a
+ * {@link proton.Data.Binary} specifying the required size. It would usually then
+ * call getBuffer() to access the underlying Uint8Array. At this point the client
+ * "owns" the data and so would have to call free() if it did nothing more with
+ * the Binary, however when {@link proton.Data.putBINARY} is called the ownership
+ * of the raw data on the virtual heap transfers from the Binary to the Data and
+ * the client no longer needs to call free() itself. In this case the putBINARY()
+ * call transfers ownership and can then safely call free() on the Binary.
+ * <p>
+ * Conversely a common use-case when receiving data is where a Binary may be
+ * created by {@link proton.Data#getBINARY}. In this case the Binary is simply a
+ * "view" onto the bytes owned by the Data instance. A client application can
+ * safely access the bytes from the view, but if it wishes to use the bytes beyond
+ * the scope of the Data instance (e.g. after the next {@link proton.Messenger#get}
+ * call then the client must explicitly *copy* the bytes into a new buffer, for
+ * example via copyBuffer().
+ * <p>
+ * Most of the {@link proton.Data} methods that take {@link proton.Data.Binary}
+ * as a parameter "consume" the underlying data and take responsibility for
+ * freeing it from the heap e.g. {@link proton.Data#putBINARY}, {@link proton.Data#decode}.
+ * For the methods that return a {@link proton.Data.Binary} the call to
+ * {@link proton.Data#getBINARY}, which is the most common case, returns a Binary
+ * that has a "view" of the underlying data that is actually owned by the Data
+ * instance and thus doesn't need to be explicitly freed on the Binary. The call
+ * to {@link proton.Data#encode} however returns a Binary that represents a *copy*
+ * of the underlying data, in this case (like a client calling new proton.Data.Binary)
+ * the client takes responsibility for freeing the data, unless of course it is
+ * subsequently passed to a method that will consume the data (putBINARY/decode).
+ * @constructor proton.Data.Binary
+ * @param {(number|string|Array|TypedArray)} value If value is a number then it 
+ *        represents the size of the Binary data buffer, if it is a string then
+ *        we copy the string to the buffer, if it is an Array or a TypedArray
+ *        then we copy the data to the buffer. N.B. although convenient do bear
+ *        in mind that using a mechanism other than constructing with a simple
+ *        size will result in some form of additional data copy.
+ * @param {number} start an optional pointer to the start of the Binary data buffer.
+ */
+Data['Binary'] = function(value, start) { // Data.Binary Constructor.
+    /**
+     * If the start pointer is specified then the underlying binary data is owned
+     * by another object, so we set the call to free to be a null function. If
+     * the start pointer is not passed then we allocate storage of the specified
+     * size on the emscripten heap and set the call to free to free the data from
+     * the emscripten heap.
+     */
+    var size = value;
+    if (start) {
+        this['free'] = function() {};
+    } else { // Create Binary from Array, ArrayBuffer or TypedArray.
+        var hasArrayBuffer = (typeof ArrayBuffer === 'function');
+        if (Data.isArray(value) ||
+            (hasArrayBuffer && value instanceof ArrayBuffer) || 
+            (value.buffer && hasArrayBuffer && value.buffer instanceof ArrayBuffer)) {
+            value = new Uint8Array(value);
+            size = value.length;
+            start = _malloc(size); // Allocate storage from emscripten heap.
+            Module['HEAPU8'].set(value, start); // Copy the data to the emscripten heap.
+        } else if (Data.isString(value)) { // Create Binary from native string
+            value = unescape(encodeURIComponent(value)); // Create a C-like UTF representation.
+            size = value.length;
+            start = _malloc(size); // Allocate storage from emscripten heap.
+            for (var i = 0; i < size; i++) {
+                setValue(start + i, value.charCodeAt(i), 'i8', 1);
+            }
+        } else { // Create unpopulated Binary of specified size.
+            // If the type is not a number by this point then an unrecognised data
+            // type has been passed so we create a zero length Binary.
+            size = Data.isNumber(size) ? size : 0;
+            start = _malloc(size); // Allocate storage from emscripten heap.
+        }
+        this['free'] = function() {
+            _free(this.start);
+            this.size = 0;
+            this.start = 0;
+            // Set free to a null function to prevent possibility of a "double free".
+            this['free'] = function() {};
+        };
+    }
+
+    this.size = size;
+    this.start = start;
+};
+
+/**
+ * Get a Uint8Array view of the data. N.B. this is just a *view* of the data,
+ * which will go out of scope on the next call to {@link proton.Messenger.get}. If
+ * a client wants to retain the data then copy should be used to explicitly
+ * create a copy of the data which the client then owns to do with as it wishes.
+ * @method getBuffer
+ * @returns {Uint8Array} a new Uint8Array view of the data.
+ * @memberof! proton.Data.Binary#
+ */
+Data['Binary'].prototype['getBuffer'] = function() {
+    return new Uint8Array(HEAPU8.buffer, this.start, this.size);
+};
+
+/**
+ * Explicitly create a *copy* of the Binary, copying the underlying binary data too.
+ * @method copy
+ * @param {number} offset an optional offset into the underlying buffer from
+ *        where we want to copy the data, default is zero.
+ * @param {number} n an optional number of bytes to copy, default is this.size - offset.
+ * @returns {proton.Data.Binary} a new {@link proton.Data.Binary} created by copying the underlying binary data.
+ * @memberof! proton.Data.Binary#
+ */
+Data['Binary'].prototype['copy'] = function(offset, n) {
+    offset = offset | 0;
+    n = n ? n : (this.size - offset);
+
+    if (offset >= this.size) {
+        offset = 0;
+        n = 0;
+    } else if ((offset + n) > this.size) {
+        n = this.size - offset; // Clamp length
+    }
+
+    var start = _malloc(n); // Allocate storage from emscripten heap.
+    _memcpy(start, this.start + offset, n); // Copy the raw data to new buffer.
+
+    return new Data['Binary'](n, start);
+};
+
+/**
+ * Converts the {@link proton.Data.Binary} to a string. This is clearly most
+ * useful when the binary data is actually a binary representation of a string
+ * such as a C style ASCII string.
+ * @method toString
+ * @memberof! proton.Data.Binary#
+ * @returns {string} the String form of a {@link proton.Data.Binary}.
+ */
+Data['Binary'].prototype.toString = Data['Binary'].prototype.valueOf = function() {
+    // Create a native JavaScript String from the start/size information.
+    return Pointer_stringify(this.start, this.size);
+};
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/data-described.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-described.js b/proton-c/bindings/javascript/data-described.js
new file mode 100644
index 0000000..e1f9d84
--- /dev/null
+++ b/proton-c/bindings/javascript/data-described.js
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Described                         */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Described.
+ * @classdesc
+ * This class represents an AMQP Described.
+ * @constructor proton.Data.Described
+ * @param {object} value the value of the described type.
+ * @param {string} descriptor an optional string describing the type.
+ * @property {object} value the actual value of the described type.
+ * @property {string} descriptor a string describing the type.
+ */
+Data['Described'] = function(value, descriptor) { // Data.Described Constructor.
+    this['value'] = value;
+    this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Described#
+ * @returns {string} the String form of a {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.toString = function() {
+    return 'Described(' + this['value'] + ', ' + this['descriptor'] + ')';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Described#
+ * @returns {object} the value of the {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.valueOf = function() {
+    return this['value'];
+};
+
+/**
+ * Compare two instances of proton.Data.Described for equality.
+ * @method equals
+ * @memberof! proton.Data.Described#
+ * @param {proton.Data.Described} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Described'].prototype['equals'] = function(rhs) {
+    if (rhs instanceof Data['Described']) {
+        return ((this['descriptor'] === rhs['descriptor']) && (this['value'] === rhs['value']));
+    } else {
+        return false;
+    }
+};
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/data-long.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-long.js b/proton-c/bindings/javascript/data-long.js
new file mode 100644
index 0000000..38fb6c8
--- /dev/null
+++ b/proton-c/bindings/javascript/data-long.js
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Long                              */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Long.
+ * @classdesc
+ * This class represents a 64 bit Integer value. It is used primarily to pass and
+ * return 64 bit Integer values to and from the emscripten compiled proton-c library.
+ * This class is needed because JavaScript cannot natively represent 64 bit
+ * Integers with sufficient accuracy.
+ * @constructor proton.Data.Long
+ * @param {number} low the least significant word.
+ * @param {number} high the most significant word.
+ */
+// Use dot notation as it is a "protected" inner class not exported from the closure.
+Data.Long = function(low, high) { // Data.Long Constructor.
+    this.low  = low  | 0;  // force into 32 signed bits.
+    this.high = high | 0;  // force into 32 signed bits.
+};
+
+// proton.Data.Long constants.
+Data.Long.TWO_PWR_16_DBL_ = 1 << 16;
+Data.Long.TWO_PWR_32_DBL_ = Data.Long.TWO_PWR_16_DBL_ * Data.Long.TWO_PWR_16_DBL_;
+Data.Long.TWO_PWR_64_DBL_ = Data.Long.TWO_PWR_32_DBL_ * Data.Long.TWO_PWR_32_DBL_;
+Data.Long.TWO_PWR_63_DBL_ = Data.Long.TWO_PWR_64_DBL_ / 2;
+Data.Long.MAX_VALUE = new Data.Long(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
+Data.Long.MIN_VALUE = new Data.Long(0, 0x80000000 | 0);
+Data.Long.ZERO = new Data.Long(0, 0);
+Data.Long.ONE  = new Data.Long(1, 0);
+
+/**
+ * @method fromNumber
+ * @memberof! proton.Data.Long#
+ * @returns {proton.Data.Long} an instance of {@link proton.Data.Long} created
+ *          using a native JavaScript number.
+ */
+Data.Long.fromNumber = function(value) {
+    if (isNaN(value) || !isFinite(value)) {
+        return Data.Long.ZERO;
+    } else if (value <= -Data.Long.TWO_PWR_63_DBL_) {
+        return Data.Long.MIN_VALUE;
+    } else if (value + 1 >= Data.Long.TWO_PWR_63_DBL_) {
+        return Data.Long.MAX_VALUE;
+    } else if (value < 0) {
+        return Data.Long.fromNumber(-value).negate();
+    } else {
+      return new Data.Long(
+          (value % Data.Long.TWO_PWR_32_DBL_) | 0,
+          (value / Data.Long.TWO_PWR_32_DBL_) | 0);
+    }
+};
+
+/**
+ * Return the twos complement of this instance.
+ * @method negate
+ * @memberof! proton.Data.Long#
+ * @returns {proton.Data.Long} the twos complement of this instance.
+ */
+Data.Long.prototype.negate = function() {
+    if (this.equals(Data.Long.MIN_VALUE)) {
+        return Data.Long.MIN_VALUE;
+    } else {
+        return this.not().add(Data.Long.ONE);
+    }
+};
+
+/**
+ * Add two instances of {@link proton.Data.Long}.
+ * @method add
+ * @memberof! proton.Data.Long#
+ * @param {proton.Data.Long} rhs the instance we wish to add to this instance.
+ * @returns {proton.Data.Long} the sum of this value and the rhs.
+ */
+Data.Long.prototype.add = function(rhs) {
+    // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
+
+    var a48 = this.high >>> 16;
+    var a32 = this.high & 0xFFFF;
+    var a16 = this.low >>> 16;
+    var a00 = this.low & 0xFFFF;
+
+    var b48 = rhs.high >>> 16;
+    var b32 = rhs.high & 0xFFFF;
+    var b16 = rhs.low >>> 16;
+    var b00 = rhs.low & 0xFFFF;
+
+    var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+    c00 += a00 + b00;
+    c16 += c00 >>> 16;
+    c00 &= 0xFFFF;
+    c16 += a16 + b16;
+    c32 += c16 >>> 16;
+    c16 &= 0xFFFF;
+    c32 += a32 + b32;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c48 += a48 + b48;
+    c48 &= 0xFFFF;
+    return new Data.Long((c16 << 16) | c00, (c48 << 16) | c32);
+};
+
+/**
+ * Return the complement of this instance.
+ * @method not
+ * @memberof! proton.Data.Long#
+ * @returns {proton.Data.Long} the complement of this instance.
+ */
+Data.Long.prototype.not = function() {
+    return new Data.Long(~this.low, ~this.high);
+};
+
+/**
+ * Compare two instances of {@link proton.Data.Long} for equality.
+ * @method equals
+ * @memberof! proton.Data.Long#
+ * @param {proton.Data.Long} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data.Long.prototype.equals = function(other) {
+    return (this.high == other.high) && (this.low == other.low);
+};
+
+/**
+ * @method getHighBits
+ * @memberof! proton.Data.Long#
+ * @returns {number} the most significant word of a {@link proton.Data.Long}.
+ */
+Data.Long.prototype.getHighBits = function() {
+    return this.high;
+};
+
+/**
+ * @method getLowBits
+ * @memberof! proton.Data.Long#
+ * @returns {number} the least significant word of a {@link proton.Data.Long}.
+ */
+Data.Long.prototype.getLowBits = function() {
+    return this.low;
+};
+
+/**
+ * @method getLowBitsUnsigned
+ * @memberof! proton.Data.Long#
+ * @returns {number} the least significant word of a {@link proton.Data.Long}
+ *          as an unsigned value.
+ */
+Data.Long.prototype.getLowBitsUnsigned = function() {
+    return (this.low >= 0) ? this.low : Data.Long.TWO_PWR_32_DBL_ + this.low;
+};
+
+/**
+ * @method toNumber
+ * @memberof! proton.Data.Long#
+ * @returns {number} a native JavaScript number (with possible loss of precision).
+ */
+Data.Long.prototype.toNumber = function() {
+    return (this.high * Data.Long.TWO_PWR_32_DBL_) + this.getLowBitsUnsigned();
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Long#
+ * @returns {string} the String form of a {@link proton.Data.Long}.
+ */
+Data.Long.prototype.toString = function() {
+    return this.high + ':' + this.getLowBitsUnsigned();
+};
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/data-symbol.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-symbol.js b/proton-c/bindings/javascript/data-symbol.js
new file mode 100644
index 0000000..c742acb
--- /dev/null
+++ b/proton-c/bindings/javascript/data-symbol.js
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Symbol                            */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Symbol.
+ * @classdesc
+ * This class represents an AMQP Symbol. This class is necessary primarily as a
+ * way to enable us to distinguish between a native String and a Symbol in the
+ * JavaScript type system.
+ * @constructor proton.Data.Symbol
+ * @param {string} s a symbol.
+ */
+Data['Symbol'] = function(s) { // Data.Symbol Constructor.
+    this.value = s;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Symbol#
+ * @returns {string} the String form of a {@link proton.Data.Symbol}.
+ */
+Data['Symbol'].prototype.toString = Data['Symbol'].prototype.valueOf = function() {
+    return this.value;
+};
+
+/**
+ * Compare two instances of proton.Data.Symbol for equality.
+ * @method equals
+ * @memberof! proton.Data.Symbol#
+ * @param {proton.Data.Symbol} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Symbol'].prototype['equals'] = function(rhs) {
+    return this.toString() === rhs.toString();
+};
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/data-typed-number.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-typed-number.js b/proton-c/bindings/javascript/data-typed-number.js
new file mode 100644
index 0000000..034d4ec
--- /dev/null
+++ b/proton-c/bindings/javascript/data-typed-number.js
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.TypedNumber                       */
+/*                                                                           */
+/*****************************************************************************/
+
+// ---------------------- JavaScript Number Extensions ------------------------ 
+
+Number.prototype['ubyte'] = function() {
+    return new Data.TypedNumber('UBYTE', this);
+};
+
+Number.prototype['byte'] = function() {
+    return new Data.TypedNumber('BYTE', this);
+};
+
+Number.prototype['ushort'] = function() {
+    return new Data.TypedNumber('USHORT', this);
+};
+
+Number.prototype['short'] = function() {
+    return new Data.TypedNumber('SHORT', this);
+};
+
+Number.prototype['uint'] = function() {
+    return new Data.TypedNumber('UINT', this);
+};
+
+Number.prototype['int'] = function() {
+    return new Data.TypedNumber('INT', this);
+};
+
+Number.prototype['ulong'] = function() {
+    return new Data.TypedNumber('ULONG', this);
+};
+
+Number.prototype['long'] = function() {
+    return new Data.TypedNumber('LONG', this);
+};
+
+Number.prototype['float'] = function() {
+    return new Data.TypedNumber('FLOAT', this);
+};
+
+Number.prototype['double'] = function() {
+    return new Data.TypedNumber('DOUBLE', this);
+};
+
+Number.prototype['char'] = function() {
+    return new Data.TypedNumber('CHAR', this);
+};
+
+String.prototype['char'] = function() {
+    return new Data.TypedNumber('CHAR', this.charCodeAt(0));
+};
+
+// ------------------------- proton.Data.TypedNumber -------------------------- 
+/**
+ * Create a proton.Data.TypedNumber.
+ * @classdesc
+ * This class is a simple wrapper class that allows a "type" to be recorded for
+ * a number. The idea is that the JavaScript Number class is extended with extra
+ * methods to allow numbers to be "modified" to TypedNumbers, so for example
+ * 1.0.float() would modify 1.0 by returning a TypedNumber with type = FLOAT
+ * and value = 1. The strings used for type correspond to the names of the Data
+ * put* methods e.g. UBYTE, BYTE, USHORT, SHORT, UINT, INT, ULONG, LONG, FLOAT,
+ * DOUBLE, CHAR so that the correct method to call can be derived from the type.
+ * @constructor proton.Data.TypedNumber
+ * @param {(string|number)} type the type of the Number either as a string or number.
+ *        Stored internally as a string corresponding to one of the TypeNames.
+ * @param {number} value the value of the Number.
+ */
+// Use dot notation as it is a "protected" inner class not exported from the closure.
+Data.TypedNumber = function(type, value) { // Data.TypedNumber Constructor.
+    this.type  = (typeof type === 'number') ? Data['TypeNames'][type] : type;
+    this.value = value;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.TypedNumber#
+ * @returns {string} the String form of a {@link proton.Data.TypedNumber}.
+ */
+Data.TypedNumber.prototype.toString = Data.TypedNumber.prototype.valueOf = function() {
+    return +this.value;
+};
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/abd646b2/proton-c/bindings/javascript/data-uuid.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-uuid.js b/proton-c/bindings/javascript/data-uuid.js
new file mode 100644
index 0000000..4fee84a
--- /dev/null
+++ b/proton-c/bindings/javascript/data-uuid.js
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Uuid                              */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Uuid which is a type 4 UUID.
+ * @classdesc
+ * This class represents a type 4 UUID, wich may use crypto libraries to generate
+ * the UUID if supported by the platform (e.g. node.js or a modern browser)
+ * @constructor proton.Data.Uuid
+ * @param {number|Array|string} u a UUID. If null a type 4 UUID is generated wich may use crypto if
+ *        supported by the platform. If u is an emscripten "pointer" we copy the
+ *        data from that. If u is a JavaScript Array we use it as-is. If u is a
+ *        String then we try to parse that as a UUID.
+ * @property {Array} uuid is the compact array form of the UUID.
+ */
+Data['Uuid'] = function(u) { // Data.Uuid Constructor.
+    // Helper to copy from emscriptem allocated storage into JavaScript Array.
+    function _p2a(p) {
+        var uuid = new Array(16);
+        for (var i = 0; i < 16; i++) {
+            uuid[i] = getValue(p + i, 'i8') & 0xFF; // & 0xFF converts to unsigned.
+        }
+        return uuid;
+    };
+
+    if (!u) { // Generate UUID using emscriptem's uuid_generate implementation.
+        var sp = Runtime.stackSave();
+        var p = allocate(16, 'i8', ALLOC_STACK); // Create temporary pointer storage.
+        _uuid_generate(p);      // Generate UUID into allocated pointer.
+        this['uuid'] = _p2a(p); // Copy from allocated storage into JavaScript Array.
+        Runtime.stackRestore(sp);
+    } else if (Data.isNumber(u)) { // Use pointer that has been passed in.
+        this['uuid'] = _p2a(u);    // Copy from allocated storage into JavaScript Array.
+    } else if (Data.isArray(u)) { // Use array that has been passed in.
+        this['uuid'] = u; // Just use the JavaScript Array.
+    } else if (Data.isString(u)) { // Parse String form UUID.
+        if (u.length === 36) {
+            var i = 0;
+            var uuid = new Array(16);
+            u.toLowerCase().replace(/[0-9a-f]{2}/g, function(byte) {
+                if (i < 16) {
+                    uuid[i++] = parseInt(byte, 16);
+                }
+            });
+            this['uuid'] = uuid;
+        }
+    }
+    this.string = null;
+};
+
+/**
+ * Returns the string representation of the proton.Data.Uuid.
+ * @method toString
+ * @memberof! proton.Data.Uuid#
+ * @returns {string} the String
+ *          /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
+ *          form of a {@link proton.Data.Uuid}.
+ */
+Data['Uuid'].prototype.toString = Data['Uuid'].prototype.valueOf = function() {
+    if (!this.string) { // Check if we've cached the string version.
+        var i = 0;
+        var uu = this['uuid'];
+        var uuid = 'xxxx-xx-xx-xx-xxxxxx'.replace(/[x]/g, function(c) {
+            var r = uu[i].toString(16);
+            r = (r.length === 1) ? '0' + r : r; // Zero pad single digit hex values
+            i++;
+            return r;
+        });
+        this.string = uuid;
+    }
+    return this.string;
+};
+
+/**
+ * Compare two instances of proton.Data.Uuid for equality.
+ * @method equals
+ * @memberof! proton.Data.Uuid#
+ * @param {proton.Data.Uuid} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Uuid'].prototype['equals'] = function(rhs) {
+    return this.toString() === rhs.toString();
+};
+


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


[38/51] [abbrv] qpid-proton git commit: Improve check for node.js in examples. Add mechanism for clients to increase stack as well as total memory - NB this feature requires emscripten fix only recently applied to incoming so may not be available in SDK

Posted by rh...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/examples/messenger/javascript/recv.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/recv.js b/examples/messenger/javascript/recv.js
index f4fe5c0..ab5fcf1 100644
--- a/examples/messenger/javascript/recv.js
+++ b/examples/messenger/javascript/recv.js
@@ -20,51 +20,50 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("recv.js should be run in Node.js");
-    return;
-}
-
-var proton = require("qpid-proton");
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
 
-var address = "amqp://~0.0.0.0";
-var message = new proton.Message();
-var messenger = new proton.Messenger();
+    var address = "amqp://~0.0.0.0";
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
 
-var pumpData = function() {
-    while (messenger.incoming()) {
-        var t = messenger.get(message);
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            var t = messenger.get(message);
 
-        console.log("Address: " + message.getAddress());
-        console.log("Subject: " + message.getSubject());
+            console.log("Address: " + message.getAddress());
+            console.log("Subject: " + message.getSubject());
+    
+            // body is the body as a native JavaScript Object, useful for most real cases.
+            //console.log("Content: " + message.body);
+    
+            // data is the body as a proton.Data Object, used in this case because
+            // format() returns exactly the same representation as recv.c
+            console.log("Content: " + message.data.format());
+    
+            messenger.accept(t);
+        }
+    };
 
-        // body is the body as a native JavaScript Object, useful for most real cases.
-        //console.log("Content: " + message.body);
-
-        // data is the body as a proton.Data Object, used in this case because
-        // format() returns exactly the same representation as recv.c
-        console.log("Content: " + message.data.format());
-
-        messenger.accept(t);
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node recv.js <addr> (default " + address + ")");
+            process.exit(0);
+        }
+    
+        address = args[0];
     }
-};
+    
+    messenger.setIncomingWindow(1024);
+    
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
 
-var args = process.argv.slice(2);
-if (args.length > 0) {
-    if (args[0] === '-h' || args[0] === '--help') {
-        console.log("Usage: node recv.js <addr> (default " + address + ")");
-        process.exit(0);
-    }
-
-    address = args[0];
+    messenger.subscribe(address);
+} else {
+    console.error("recv.js should be run in Node.js");
 }
 
-messenger.setIncomingWindow(1024);
-
-messenger.on('error', function(error) {console.log(error);});
-messenger.on('work', pumpData);
-messenger.start();
-
-messenger.subscribe(address);
-messenger.recv(); // Receive as many messages as messenger can buffer.
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/examples/messenger/javascript/send.html
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html
index dc8b448..f9aae90 100644
--- a/examples/messenger/javascript/send.html
+++ b/examples/messenger/javascript/send.html
@@ -28,19 +28,20 @@
 <!--
   Import the Messenger Binding proton.js. Note that this simple example pulls
   it from the node_modules/qpid-proton/lib, which is created by the build process
-  so that the node.js based examples "just work", in a real Web App you would need
-  to copy the proton.js to your own server.
+  so that the node.js based examples "just work", in a real Web App you would
+  clearly need to copy the proton.js to your own server.
 
   In actual fact the CMake build actually builds proton.js into the directory:
   <build>/proton-c/bindings/javascript
-  where <build> is the build directory created to run cmake from.
+  where <build> is the build directory created to run cmake from, it is then
+  copied to the node_modules/qpid-proton/lib directory.
 
-  In this example we also set the global variable PROTON_HEAP_SIZE in order to
+  In this example we also set the global variable PROTON_TOTAL_MEMORY in order to
   increase the virtual heap available to the emscripten compiled C runtime. It
   is not really necessary to do this for this application as the default value
   of 16777216 is fine, it is simply done here to illustrate how to do it.
 -->
-<script type="text/javascript">PROTON_HEAP_SIZE = 50000000;</script>
+<script type="text/javascript">PROTON_TOTAL_MEMORY = 50000000;</script>
 <script type="text/javascript" src="../../../node_modules/qpid-proton/lib/proton.js"></script>
 
 <script type="text/javascript">

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/examples/messenger/javascript/send.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.js b/examples/messenger/javascript/send.js
index 0ca3a7e..39d40bd 100644
--- a/examples/messenger/javascript/send.js
+++ b/examples/messenger/javascript/send.js
@@ -20,81 +20,86 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (typeof process !== 'object' || typeof require !== 'function') {
-    console.error("send.js should be run in Node.js");
-    return;
-}
-
-PROTON_HEAP_SIZE = 50000000;
-var proton = require("qpid-proton");
+if (typeof process === 'object' && typeof require === 'function') {
+    // In this example we also set the global variable PROTON_TOTAL_MEMORY in order
+    // to increase the virtual heap available to the emscripten compiled C runtime.
+    // It is not really necessary to do this for this application as the default
+    // value of 16777216 is fine, it is simply done here to illustrate how to do it.
+    PROTON_TOTAL_MEMORY = 50000000;
+    var proton = require("qpid-proton");
 
-var address = "amqp://0.0.0.0";
-var subject = "UK.WEATHER";
-var msgtext = "Hello World!";
-var tracker = null;
-var running = true;
+    var address = "amqp://0.0.0.0";
+    var subject = "UK.WEATHER";
+    var msgtext = "Hello World!";
+    var tracker = null;
+    var running = true;
 
-var message = new proton.Message();
-var messenger = new proton.Messenger();
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
 
-// Because this is an asynchronous send we can't simply call messenger.put(message)
-// then exit. The following callback function (and messenger.setOutgoingWindow())
-// gives us a means to wait until the consumer has received the message before
-// exiting. The recv.js example explicitly accepts messages it receives.
-var pumpData = function() {
-    var status = messenger.status(tracker);
-    if (status != proton.Status.PENDING) {
-        if (running) {
-            messenger.stop();
-            running = false;
-        } 
-    }
+    // This is an asynchronous send, so we can't simply call messenger.put(message)
+    // at the end of the application as we would with a synchronous/blocking
+    // version, as the application would simply exit without actually sending.
+    // The following callback function (and messenger.setOutgoingWindow())
+    // gives us a means to wait until the consumer has received the message before
+    // exiting. The recv.js example explicitly accepts messages it receives.
+    var pumpData = function() {
+        var status = messenger.status(tracker);
+        if (status != proton.Status.PENDING) {
+            if (running) {
+                messenger.stop();
+                running = false;
+            } 
+        }
 
-    if (messenger.isStopped()) {
-        message.free();
-        messenger.free();
-    }
-};
+        if (messenger.isStopped()) {
+            message.free();
+            messenger.free();
+        }
+    };
 
-var args = process.argv.slice(2);
-if (args.length > 0) {
-    if (args[0] === '-h' || args[0] === '--help') {
-        console.log("Usage: node send.js [options] [message]");
-        console.log("Options:");
-        console.log("  -a <addr> The target address [amqp[s]://domain[/name]] (default " + address + ")");
-        console.log("  -s <subject> The message subject (default " + subject + ")");
-        console.log("message A text string to send.");
-        process.exit(0);
-    }
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node send.js [options] [message]");
+            console.log("Options:");
+            console.log("  -a <addr> The target address [amqp[s]://domain[/name]] (default " + address + ")");
+            console.log("  -s <subject> The message subject (default " + subject + ")");
+            console.log("message A text string to send.");
+            process.exit(0);
+        }
 
-    for (var i = 0; i < args.length; i++) {
-        var arg = args[i];
-        if (arg.charAt(0) === '-') {
-            i++;
-            var val = args[i];
-            if (arg === '-a') {
-                address = val;
-            } else if (arg === '-s') {
-                subject = val;
+        for (var i = 0; i < args.length; i++) {
+            var arg = args[i];
+            if (arg.charAt(0) === '-') {
+                i++;
+                var val = args[i];
+                if (arg === '-a') {
+                    address = val;
+                } else if (arg === '-s') {
+                    subject = val;
+                }
+            } else {
+                msgtext = arg;
             }
-        } else {
-            msgtext = arg;
         }
     }
-}
 
-console.log("Address: " + address);
-console.log("Subject: " + subject);
-console.log("Content: " + msgtext);
+    console.log("Address: " + address);
+    console.log("Subject: " + subject);
+    console.log("Content: " + msgtext);
 
-messenger.on('error', function(error) {console.log(error);});
-messenger.on('work', pumpData);
-messenger.setOutgoingWindow(1024); // So we can track status of send message.
-messenger.start();
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.setOutgoingWindow(1024); // So we can track status of send message.
+    messenger.start();
 
-message.setAddress(address);
-message.setSubject(subject);
-message.body = msgtext;
+    message.setAddress(address);
+    message.setSubject(subject);
+    message.body = msgtext;
 
-tracker = messenger.put(message);
+    tracker = messenger.put(message);
+} else {
+    console.error("send.js should be run in Node.js");
+}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/examples/messenger/javascript/server.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/server.js b/examples/messenger/javascript/server.js
index 483e49d..1a9eabb 100644
--- a/examples/messenger/javascript/server.js
+++ b/examples/messenger/javascript/server.js
@@ -22,61 +22,60 @@
 // Simple server for use with client.js illustrating request/response
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("server.js should be run in Node.js");
-    return;
-}
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
 
-var proton = require("qpid-proton");
+    var address = "amqp://~0.0.0.0";
+    var message = new proton.Message();
+    var reply   = new proton.Message();
+    var messenger = new proton.Messenger();
 
-var address = "amqp://~0.0.0.0";
-var message = new proton.Message();
-var reply   = new proton.Message();
-var messenger = new proton.Messenger();
-
-var dispatch = function(request, response) {
-    var subject = request.getSubject();
-    if (subject) {
-        response.setSubject('Re: ' + subject);
-    }
-    response.properties = request.properties
-    console.log("Dispatched " + subject + " " + JSON.stringify(request.properties));
-};
-
-var pumpData = function() {
-    while (messenger.incoming()) {
-        var t = messenger.get(message);
-
-        var replyTo = message.getReplyTo();
-        if (replyTo) {
-            console.log(replyTo);
-            reply.setAddress(replyTo);
-            reply.setCorrelationID(message.getCorrelationID());
-            reply.body = message.body;
-            dispatch(message, reply);
-            messenger.put(reply);
+    var dispatch = function(request, response) {
+        var subject = request.getSubject();
+        if (subject) {
+            response.setSubject('Re: ' + subject);
         }
+        response.properties = request.properties
+        console.log("Dispatched " + subject + " " + JSON.stringify(request.properties));
+    };
 
-        messenger.accept(t);
-    }
-};
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            var t = messenger.get(message);
+    
+            var replyTo = message.getReplyTo();
+            if (replyTo) {
+                console.log(replyTo);
+                reply.setAddress(replyTo);
+                reply.setCorrelationID(message.getCorrelationID());
+                reply.body = message.body;
+                dispatch(message, reply);
+                messenger.put(reply);
+            }
+    
+            messenger.accept(t);
+        }
+    };
 
-var args = process.argv.slice(2);
-if (args.length > 0) {
-    if (args[0] === '-h' || args[0] === '--help') {
-        console.log("Usage: node server.js <addr> (default " + address + ")");
-        process.exit(0);
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node server.js <addr> (default " + address + ")");
+            process.exit(0);
+        }
+    
+        address = args[0];
     }
-
-    address = args[0];
+    
+    messenger.setIncomingWindow(1024);
+    
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
+    
+    messenger.subscribe(address);
+} else {
+    console.error("server.js should be run in Node.js");
 }
 
-messenger.setIncomingWindow(1024);
-
-messenger.on('error', function(error) {console.log(error);});
-messenger.on('work', pumpData);
-messenger.start();
-
-messenger.subscribe(address);
-messenger.recv(); // Receive as many messages as messenger can buffer.
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/examples/messenger/javascript/spout.js
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/spout.js b/examples/messenger/javascript/spout.js
index ad5b376..16faa8e 100644
--- a/examples/messenger/javascript/spout.js
+++ b/examples/messenger/javascript/spout.js
@@ -20,102 +20,52 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("spout.js should be run in Node.js");
-    return;
-}
-
-var proton = require("qpid-proton");
-
-console.log("spout not implemented yet");
-process.exit(0);
-
-var address = "amqp://0.0.0.0";
-var subject = "UK.WEATHER";
-var msgtext = "Hello World!";
-var tracker = null;
-var running = true;
-
-var message = new proton.Message();
-var messenger = new proton.Messenger();
-
-function pumpData() {
-    var status = messenger.status(tracker);
-    if (status != proton.Status.PENDING) {
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
+
+    console.log("spout not implemented yet");
+    process.exit(0);
+    
+    var address = "amqp://0.0.0.0";
+    var subject = "UK.WEATHER";
+    var msgtext = "Hello World!";
+    var tracker = null;
+    var running = true;
+    
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    function pumpData() {
+        var status = messenger.status(tracker);
+        if (status != proton.Status.PENDING) {
 console.log("status = " + status);
 
-        if (running) {
+            if (running) {
 console.log("stopping");
-            messenger.stop();
-            running = false;
-        } 
-    }
-
-    if (messenger.isStopped()) {
+                messenger.stop();
+                running = false;
+            } 
+        }
+    
+        if (messenger.isStopped()) {
 console.log("exiting");
-        message.free();
-        messenger.free();
-    }
-};
-
-messenger.on('error', function(error) {console.log(error);});
-messenger.on('work', pumpData);
-messenger.setOutgoingWindow(1024);
-messenger.start();
-
-message.setAddress(address);
-message.setSubject(subject);
-
-//message.body = msgtext;
-//message.body = new proton.Data.Uuid();
-//message.body = new proton.Data.Symbol("My Symbol");
-message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
-//message.body = new proton.Data.Described("persian", "feline mammals");
+            message.free();
+            messenger.free();
+        }
+    };
 
-//message.body = new Date();
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.setOutgoingWindow(1024);
+    messenger.start();
 
-//message.body = new proton.Data.Array('INT', [1, 3, 5, 7], "odd numbers");
+    message.setAddress(address);
+    message.setSubject(subject);
 
-//message.body = new proton.Data.Array('UINT', [1, 3, 5, 7], "odd");
-//message.body = new proton.Data.Array('ULONG', [1, 3, 5, 7], "odd");
-//message.body = new proton.Data.Array('FLOAT', [1, 3, 5, 7], "odd");
-//message.body = new proton.Data.Array('STRING', ["1", "3", "5", "7"], "odd");
+    message.body = msgtext;
 
-//message.body = new Uint8Array([1, 3, 5, 7]);
-
-//message.body = new proton.Data.Array('UINT', new Uint8Array([1, 3, 5, 7]), "odd");
-
-//message.body = new proton.Data.Array('UUID', [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()], "unique");
-
-/*message.body = new proton.Data.Binary(4);
-var buffer = message.body.getBuffer();
-buffer[0] = 65;
-buffer[1] = 77;
-buffer[2] = 81;
-buffer[3] = 80;*/
-//message.body = new proton.Data.Binary([65, 77, 81, 80]);
-//message.body = new proton.Data.Binary(2485);
-//message.body = new proton.Data.Binary(100000);
-
-//message.body = null;
-//message.body = true;
-//message.body = 66..char();
-//message.body = "   \"127.0\"  ";
-
-//message.body = 2147483647; // int
-//message.body = -2147483649; // long
-//message.body = 12147483649; // long
-//message.body = (12147483649).long(); // long
-//message.body = (-12147483649).ulong(); // long
-//message.body = (17223372036854778000).ulong(); // ulong
-
-//message.body = (121474.836490).float(); // float TODO check me
-//message.body = 12147483649.0.float(); // float TODO check me
-//message.body = (4294967296).uint();
-//message.body = (255).ubyte();
-
-//message.body = ['Rod', 'Jane', 'Freddy'];
-//message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
-
-tracker = messenger.put(message);
+    tracker = messenger.put(message);
+} else {
+    console.error("spout.js should be run in Node.js");
+}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/proton-c/bindings/javascript/README
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/README b/proton-c/bindings/javascript/README
index a29352d..8bfde56 100644
--- a/proton-c/bindings/javascript/README
+++ b/proton-c/bindings/javascript/README
@@ -7,7 +7,7 @@ with the Qpid Proton AMQP 1.0 protocol engine and messenger library.
 Important Note - Modern Browser Needed
 ======================================
 
-The JavaScript binding requires ArrayBuffer/TypeArray and WebSocket support.
+The JavaScript binding requires ArrayBuffer/TypedArray and WebSocket support.
 Both of these are available in most "modern" browser versions. The author has
 only tried running on FireFox and Chrome, though recent Safari, Opera and IE10+
 *should* work too - YMMV. It might be possible to polyfill for older browsers
@@ -21,11 +21,10 @@ bindings to Proton are somewhat different to the bindings for other languages
 because of the restrictions of the execution environment. In particular it is
 very important to note that the JavaScript bindings by default use a WebSocket
 transport and not a TCP transport, so whilst it's possible to create Server style
-applications that clients can connect to (e.g. recv.js and send.js) it is very
-important to note that:
+applications that clients can connect to (e.g. recv.js and send.js) note that:
 
 JavaScript clients cannot *directly* talk to "normal" AMQP applications such as
-qpidd or the Java Broker because they use the traditional TCP transport.
+qpidd or (by default) the Java Broker because they use a standard TCP transport.
 
 This is a slightly irksome issue, but there's no getting away from it because
 it's a security restriction imposed by the browser environment.
@@ -38,14 +37,14 @@ also be possible to use native TCP for Chrome "packaged apps", but again this is
 only on the TODO list so if you want to talk to a "normal" AMQP application you
 must live with the WebSocket constraints.
 
-Option 1. proxy from WebSockets to TCP sockets
+Option 1. proxy from WebSockets to TCP sockets. The application
 <proton>/examples/messenger/javascript/proxy.js
-is a simple Node.js WebSocket<->TCP Socket proxy, simple doing:
+is a simple Node.js WebSocket<->TCP Socket proxy, simply doing:
 
 node proxy.js
 
 will stand up a proxy listening by default on WebSocket port 5673 and forwarding
-to TCP port 5672 (this is configurable for options do: node proxy.js -h)
+to TCP port 5672 (this is configurable, for options do: node proxy.js -h)
 
 Rather than using a stand-alone proxy it is possible to have applications stand
 up their own proxy (where lport = listen port, thost = target host and
@@ -124,7 +123,7 @@ emscripten itself depends upon.
 
 http://kripken.github.io/emscripten-site/docs/building_from_source/index.html#installing-from-source
 http://kripken.github.io/emscripten-site/docs/building_from_source/toolchain_what_is_needed.html
-provides instructions for installing emscripten and the "fastcomp" LLVM backend.
+provide instructions for installing emscripten and the "fastcomp" LLVM backend.
 This approach lets users use the "bleeding edge" version of emscripten on the
 "incoming" branch (pretty much analogous to building qpid/proton off svn trunk).
 This is the approach that the author of the JavaScript Bindings tends to use.
@@ -182,7 +181,7 @@ point for doing so.
 Documentation
 =============
 
-When you've successfully got a successful build do:
+When you've successfully got a working build do:
 
   make docs
 
@@ -208,12 +207,12 @@ It's important to realise that most of the library code is compiled C code and
 the runtime uses a "virtual heap" to support the underlying malloc/free. This is
 implemented internally as an ArrayBuffer with a default size of 16777216.
 
-To allocate a larger heap an application must set the PROTON_HEAP_SIZE global.
+To allocate a larger heap an application must set the PROTON_TOTAL_MEMORY global.
 In Node.js this would look like (see send.js):
-PROTON_HEAP_SIZE = 50000000; // Note no var - it needs to be global.
+PROTON_TOTAL_MEMORY = 50000000; // Note no var - it needs to be global.
 
 In a browser it would look like (see send.html):
-<script type="text/javascript">PROTON_HEAP_SIZE = 50000000;</script>
+<script type="text/javascript">PROTON_TOTAL_MEMORY = 50000000;</script>
 
 2. Load the library and create a message and messenger.
 In Node.js this would look like (see send.js):
@@ -235,6 +234,7 @@ messenger.on('error', <error callback>);
 messenger.on('work', <work callback>);
 messenger.on('subscription', <subscription callback>);
 
+
 The work callback is triggered on WebSocket events, so in general you would use
 this to send and receive messages, for example in recv.js we have:
 
@@ -282,7 +282,7 @@ message.setSubject('UK.NEWS');
 message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
 
 
-The main things to bear in mind is that (particularly for sending messages) we
+The main thing to bear in mind is that (particularly for sending messages) we
 may need to use "adapters" to make sure values are correctly interpreted and
 encoded to the correct type in the AMQP type system. This is especially important
 when interoperating with a peer written in a strongly typed language (C/C++/Java).
@@ -295,7 +295,7 @@ message.body = new proton.Data.Uuid();
 // AMQP Symbol
 message.body = new proton.Data.Symbol("My Symbol");
 
-// Binary data (created from a String in this case).
+// Binary data (created from a gibberish String in this case).
 message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
 
 // Binary data (Get a Uint8Array view of the data and directly access that).
@@ -313,7 +313,7 @@ message.body = new proton.Data.Binary([65, 77, 81, 80]);
 Note that the implementation of proton.Data.Binary tries to minimise copying so
 it accesses the internal emscripten heap *directly* this requires memory management
 which is mostly handled transparently, but users need to be aware that the
-underlying memory is "owned" by the Message Object so if Binary data needs to
+underlying memory is "owned" by the Message Object, so if Binary data needs to
 be maintained after the next call to messenger.get(message); it must be
 *explicitly* copied. For more detail do "make docs" and see:
 <proton>/build/proton-c/bindings/javascript/html/proton.Data.Binary.html
@@ -356,14 +356,14 @@ message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
 // primitives it is necessary to either use braces or use a "double dot" so that
 // the interpreter can disambiguate from a simple decimal point. The binding will
 // attempt to use the correct type such that message.body = 2147483647; would be
-// sent as an AMQP integer but because of the way JavaScript coerces integers
+// sent as an AMQP integer, but because of the way JavaScript coerces integers
 // message.body = 2147483647.0; would also be sent as an AMQP integer because
-// 2147483647.0 gets transparently conveted to 2147483647 by the interpreter so
+// 2147483647.0 gets transparently conveted to 2147483647 by the interpreter, so
 // to explicitly send this as an AMQP float we'd need to do:
 // message.body = 2147483647.0.float();
 
 // Some more number examples:
-message.body = 66..char();  // char
+message.body = 66..char();  // char - note double dot. (66).char(); works too.
 message.body = 2147483647;  // int
 message.body = -2147483649; // long
 message.body = 12147483649; // long

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/proton-c/bindings/javascript/messenger.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/messenger.js b/proton-c/bindings/javascript/messenger.js
index 993670f..8ab4e00 100644
--- a/proton-c/bindings/javascript/messenger.js
+++ b/proton-c/bindings/javascript/messenger.js
@@ -431,8 +431,15 @@ _Messenger_['subscribe'] = function(source) {
         this._check(Module['Error']['ERR']);
     }
 
-    subscription = new Subscription(subscription)
-    this._pendingSubscriptions.push(subscription);
+    // For peer subscriptions to this Messenger emit a subscription event
+    // immediately otherwise defer until the address is resolved remotely.
+    if (source.indexOf('~') !== -1) {
+        subscription = new Subscription(subscription, source);
+        this._emit('subscription', subscription);
+    } else {
+        subscription = new Subscription(subscription)
+        this._pendingSubscriptions.push(subscription);
+    }
     return subscription;
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/proton-c/bindings/javascript/module.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/module.js b/proton-c/bindings/javascript/module.js
index cf64700..e0e8373 100644
--- a/proton-c/bindings/javascript/module.js
+++ b/proton-c/bindings/javascript/module.js
@@ -56,29 +56,43 @@
  * changed subsequently (the default size is 16*1024*1024 = 16777216).
  * <p>
  * Applications can specify the size of virtual heap that they require via the
- * global variable PROTON_HEAP_SIZE, this must be set <b>before</b> the library is
+ * global variable PROTON_TOTAL_MEMORY, this must be set <b>before</b> the library is
  * loaded e.g. in Node.js an application would do:
  * <pre>
- * PROTON_HEAP_SIZE = 50000000; // Note no var - it needs to be global.
+ * PROTON_TOTAL_MEMORY = 50000000; // Note no var - it needs to be global.
  * var proton = require('qpid-proton');
  * ...
  * </pre>
  * A browser based application would do:
  * <pre>
- * &lt;script type="text/javascript"&gt;PROTON_HEAP_SIZE = 50000000;&lt;/script&gt;
+ * &lt;script type="text/javascript"&gt;PROTON_TOTAL_MEMORY = 50000000;&lt;/script&gt;
  * &lt;script type="text/javascript" src="proton.js">&lt;/script&gt;
  * </pre>
+ * The global variable PROTON_TOTAL_STACK may be used in a similar way to increase
+ * the stack size from its default of 5*1024*1024 = 5242880. It is worth noting
+ * that Strings are allocated on the stack, so you may need this if you end up
+ * wanting to send very large strings.
  * @namespace proton
  */
 var Module = {};
 
-// If the global variable PROTON_HEAP_SIZE has been set by the application this
+// If the global variable PROTON_TOTAL_MEMORY has been set by the application this
 // will result in the emscripten heap getting set to the next multiple of
-// 16777216 above PROTON_HEAP_SIZE.
-if (typeof process === 'object' && typeof require === 'function' && global['PROTON_HEAP_SIZE']) {
-    Module['TOTAL_MEMORY'] = global['PROTON_HEAP_SIZE'];
-} else if (typeof window === 'object' && window['PROTON_HEAP_SIZE']) {
-    Module['TOTAL_MEMORY'] = window['PROTON_HEAP_SIZE'];
+// 16777216 above PROTON_TOTAL_MEMORY.
+if (typeof process === 'object' && typeof require === 'function') {
+    if (global['PROTON_TOTAL_MEMORY']) {
+        Module['TOTAL_MEMORY'] = global['PROTON_TOTAL_MEMORY'];
+    }
+    if (global['PROTON_TOTAL_STACK']) {
+        Module['TOTAL_STACK'] = global['PROTON_TOTAL_STACK'];
+    }
+} else if (typeof window === 'object') {
+    if (window['PROTON_TOTAL_MEMORY']) {
+        Module['TOTAL_MEMORY'] = window['PROTON_TOTAL_MEMORY'];
+    }
+    if (window['PROTON_TOTAL_STACK']) {
+        Module['TOTAL_STACK'] = window['PROTON_TOTAL_STACK'];
+    }
 }
 
 /*****************************************************************************/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/proton-c/bindings/javascript/subscription.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/subscription.js b/proton-c/bindings/javascript/subscription.js
index 83ede80..602a741 100644
--- a/proton-c/bindings/javascript/subscription.js
+++ b/proton-c/bindings/javascript/subscription.js
@@ -30,10 +30,13 @@
  * Subscriptions should never be *directly* instantiated by client code only via
  * Messenger.subscribe() or Messenger.incomingSubscription(), so we declare the
  * constructor in the scope of the package and don't export it via Module.
- * @constructor Subscription                                                              
+ * @constructor Subscription
+ * @param {number} subscription a pointer to the underlying subscription object.
+ * @param {string} address if the address is already known it can be (optionally) specified.
  */
-var Subscription = function(subscription) { // Subscription Constructor.
+var Subscription = function(subscription, address) { // Subscription Constructor.
     this._subscription = subscription;
+    this._address = address;
 };
 
 /**
@@ -62,6 +65,9 @@ Subscription.prototype['setContext'] = function(context) {
  * @returns the Subscription's Address.
  */
 Subscription.prototype['getAddress'] = function() {
+    if (this._address) {
+        return this._address;
+    }
     return Pointer_stringify(_pn_subscription_address(this._subscription));
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d8ebc7f4/tests/javascript/codec.js
----------------------------------------------------------------------
diff --git a/tests/javascript/codec.js b/tests/javascript/codec.js
index 2ebc390..ce4890d 100644
--- a/tests/javascript/codec.js
+++ b/tests/javascript/codec.js
@@ -28,524 +28,542 @@
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
-if (!exports) {
-    console.error("codec.js should be run in Node.js");
-    return;
-}
-
-var unittest = require("./unittest.js");
-var assert = require("assert");
-var proton = require("qpid-proton");
-
-// Extend TestCase by creating a prototype instance and adding test methods as properties.
-var DataTest = new unittest.TestCase();
-
-DataTest.setUp = function() {
-    this.data = new proton.Data();
-};
-
-DataTest.tearDown = function() {
-    this.data.free();
-    this.data = null;
-};
-
-DataTest.testTopLevelNext = function() {
-    console.log("testTopLevelNext");
-    assert(this.data.next() === null);
-    this.data.putNULL();
-    this.data.putBOOL(false);
-    this.data.putINT(0);
-    assert(this.data.next() === null);
-    this.data.rewind();
-    assert(this.data.next() === proton.Data.NULL);
-    assert(this.data.next() === proton.Data.BOOL);
-    assert(this.data.next() === proton.Data.INT);
-    assert(this.data.next() === null);
-    console.log("OK\n");
-};
-
-DataTest.testNestedNext = function() {
-    console.log("testNestedNext");
-    assert(this.data.next() === null);
-    this.data.putNULL();
-    assert(this.data.next() === null);
-    this.data.putLISTNODE();
-    assert(this.data.next() === null);
-    this.data.putBOOL(false);
-    assert(this.data.next() === null);
-    this.data.rewind();
-    assert(this.data.next() === proton.Data.NULL);
-    assert(this.data.next() === proton.Data.LIST);
-    this.data.enter();
-    assert(this.data.next() === null);
-    this.data.putUBYTE(0);
-    assert(this.data.next() === null);
-    this.data.putUINT(0);
-    assert(this.data.next() === null);
-    this.data.putINT(0);
-    assert(this.data.next() === null);
-    this.data.exit();
-    assert(this.data.next() === proton.Data.BOOL);
-    assert(this.data.next() === null);
-
-    this.data.rewind();
-    assert(this.data.next() === proton.Data.NULL);
-    assert(this.data.next() === proton.Data.LIST);
-    assert(this.data.enter());
-    assert(this.data.next() === proton.Data.UBYTE);
-    assert(this.data.next() === proton.Data.UINT);
-    assert(this.data.next() === proton.Data.INT);
-    assert(this.data.next() === null);
-    assert(this.data.exit());
-    assert(this.data.next() === proton.Data.BOOL);
-    assert(this.data.next() === null);
-    console.log("OK\n");
-};
-
-DataTest.testEnterExit = function() {
-    console.log("testEnterExit");
-    assert(this.data.next() === null);
-    assert(!this.data.enter());
-    this.data.putLISTNODE();
-    assert(this.data.enter());
-    assert(this.data.next() === null);
-    this.data.putLISTNODE();
-    assert(this.data.enter());
-    this.data.putLISTNODE();
-    assert(this.data.enter());
-    assert(this.data.exit());
-    assert(this.data.getLISTNODE() === 0);
-    assert(this.data.exit());
-    assert(this.data.getLISTNODE() === 1);
-    assert(this.data.exit());
-    assert(this.data.getLISTNODE() === 1);
-    assert(!this.data.exit());
-    assert(this.data.getLISTNODE() === 1);
-    assert(this.data.next() === null);
-
-    this.data.rewind();
-    assert(this.data.next() === proton.Data.LIST);
-    assert(this.data.getLISTNODE() === 1);
-    assert(this.data.enter());
-    assert(this.data.next() === proton.Data.LIST);
-    assert(this.data.getLISTNODE() === 1);
-    assert(this.data.enter());
-    assert(this.data.next() === proton.Data.LIST);
-    assert(this.data.getLISTNODE() === 0);
-    assert(this.data.enter());
-    assert(this.data.next() === null);
-    assert(this.data.exit());
-    assert(this.data.getLISTNODE() === 0);
-    assert(this.data.exit());
-    assert(this.data.getLISTNODE() === 1);
-    assert(this.data.exit());
-    assert(this.data.getLISTNODE() === 1);
-    assert(!this.data.exit());
-    console.log("OK\n");
-};
-
-/**
- * This tests the "low level" putARRAYNODE/getARRAYNODE methods.
- * In general though applications would create a proton.Data.Array and use the
- * higher level putARRAY/getARRAY
- */
-DataTest._testArray = function(dtype, descriptor, atype, values) {
-    var values = Array.prototype.slice.apply(arguments, [3]);
-    dtype = (dtype == null) ? null : dtype.toUpperCase();
-    atype = atype.toUpperCase();
-
-    // Create an array node, enter it and put the descriptor (if present) and values.
-    this.data.putARRAYNODE(dtype != null, proton.Data[atype]);
-    this.data.enter();
-    if (dtype != null) {
+if (typeof process === 'object' && typeof require === 'function') {
+    var unittest = require("./unittest.js");
+    var assert = require("assert");
+
+    // Increase the virtual heap available to the emscripten compiled C runtime.
+    // This allows us to test a really big string.
+    PROTON_TOTAL_MEMORY = 140000000;
+    PROTON_TOTAL_STACK = 25000000; // Needs to be bigger than the biggest string.
+    var proton = require("qpid-proton");
+
+    // Extend TestCase by creating a prototype instance and adding test methods as properties.
+    var DataTest = new unittest.TestCase();
+
+    DataTest.setUp = function() {
+        this.data = new proton.Data();
+    };
+
+    DataTest.tearDown = function() {
+        this.data.free();
+        this.data = null;
+    };
+    
+    DataTest.testTopLevelNext = function() {
+        console.log("testTopLevelNext");
+        assert(this.data.next() === null);
+        this.data.putNULL();
+        this.data.putBOOL(false);
+        this.data.putINT(0);
+        assert(this.data.next() === null);
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.NULL);
+        assert(this.data.next() === proton.Data.BOOL);
+        assert(this.data.next() === proton.Data.INT);
+        assert(this.data.next() === null);
+        console.log("OK\n");
+    };
+    
+    DataTest.testNestedNext = function() {
+        console.log("testNestedNext");
+        assert(this.data.next() === null);
+        this.data.putNULL();
+        assert(this.data.next() === null);
+        this.data.putLISTNODE();
+        assert(this.data.next() === null);
+        this.data.putBOOL(false);
+        assert(this.data.next() === null);
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.NULL);
+        assert(this.data.next() === proton.Data.LIST);
+        this.data.enter();
+        assert(this.data.next() === null);
+        this.data.putUBYTE(0);
+        assert(this.data.next() === null);
+        this.data.putUINT(0);
+        assert(this.data.next() === null);
+        this.data.putINT(0);
+        assert(this.data.next() === null);
+        this.data.exit();
+        assert(this.data.next() === proton.Data.BOOL);
+        assert(this.data.next() === null);
+    
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.NULL);
+        assert(this.data.next() === proton.Data.LIST);
+        assert(this.data.enter());
+        assert(this.data.next() === proton.Data.UBYTE);
+        assert(this.data.next() === proton.Data.UINT);
+        assert(this.data.next() === proton.Data.INT);
+        assert(this.data.next() === null);
+        assert(this.data.exit());
+        assert(this.data.next() === proton.Data.BOOL);
+        assert(this.data.next() === null);
+        console.log("OK\n");
+    };
+    
+    DataTest.testEnterExit = function() {
+        console.log("testEnterExit");
+        assert(this.data.next() === null);
+        assert(!this.data.enter());
+        this.data.putLISTNODE();
+        assert(this.data.enter());
+        assert(this.data.next() === null);
+        this.data.putLISTNODE();
+        assert(this.data.enter());
+        this.data.putLISTNODE();
+        assert(this.data.enter());
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 0);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(!this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.next() === null);
+    
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.LIST);
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.enter());
+        assert(this.data.next() === proton.Data.LIST);
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.enter());
+        assert(this.data.next() === proton.Data.LIST);
+        assert(this.data.getLISTNODE() === 0);
+        assert(this.data.enter());
+        assert(this.data.next() === null);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 0);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(!this.data.exit());
+        console.log("OK\n");
+    };
+    
+    /**
+     * This tests the "low level" putARRAYNODE/getARRAYNODE methods.
+     * In general though applications would create a proton.Data.Array and use the
+     * higher level putARRAY/getARRAY
+     */
+    DataTest._testArray = function(dtype, descriptor, atype, values) {
+        var values = Array.prototype.slice.apply(arguments, [3]);
+        dtype = (dtype == null) ? null : dtype.toUpperCase();
+        atype = atype.toUpperCase();
+    
+        // Create an array node, enter it and put the descriptor (if present) and values.
+        this.data.putARRAYNODE(dtype != null, proton.Data[atype]);
+        this.data.enter();
+        if (dtype != null) {
+            var putter = 'put' + dtype;
+            this.data[putter](descriptor);
+        }
+        var putter = 'put' + atype;
+        for (var i = 0; i < values.length; i++) {
+            this.data[putter](values[i]);
+        }
+        this.data.exit();
+    
+        // Check that we did indeed add an Array node
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.ARRAY);
+    
+        // Get the count, described and type metadata from the array node and compare
+        // with the values we passed to putARRAYNODE.
+        var metadata = this.data.getARRAYNODE();
+        var count = metadata.count;
+        var described = metadata.described;
+        var type = metadata.type;
+    
+        assert(count === values.length);
+        if (dtype == null) {
+            assert(described === false);
+        } else {
+            assert(described === true);
+        }
+        assert(type === proton.Data[atype]);
+    
+        // Enter the array node and compare the descriptor and values with those that
+        // we put into the array.
+        assert(this.data.enter());
+        if (described) {
+            assert(this.data.next() === proton.Data[dtype]);
+            var getter = 'get' + dtype;
+            var gotten = this.data[getter]();
+            assert(gotten.toString() === descriptor.toString());
+        }
+        var getter = 'get' + atype;
+        for (var i = 0; i < values.length; i++) {
+            assert(this.data.next() === proton.Data[atype]);
+            var gotten = this.data[getter]();
+            assert(gotten.toString() === values[i].toString());
+        }
+        assert(this.data.next() === null);
+        assert(this.data.exit());
+    };
+    
+    DataTest.testStringArray = function() {
+        console.log("testStringArray");
+        this._testArray(null, null, "string", "one", "two", "three");
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array("STRING", ["four", "five", "six"]);
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+    
+    DataTest.testDescribedStringArray = function() {
+        console.log("testDescribedStringArray");
+        this._testArray("symbol", "url", "string", "one", "two", "three");
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array("STRING", ["four", "five", "six"], new proton.Data.Symbol("url"));
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+    
+    DataTest.testIntArray = function() {
+        console.log("testIntArray");
+        this._testArray(null, null, "int", 1, 2, 3);
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array("INT", [4, 5, 6]);
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+    
+    DataTest.testUUIDArray = function() {
+        console.log("testUUIDArray");
+        this._testArray(null, null, "uuid", new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid());
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array("UUID", [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()]);
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+
+    DataTest.testEmptyArray = function() {
+        console.log("testEmptyArray");
+        this._testArray(null, null, "null");
+
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array();
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+
+    DataTest.testDescribedEmptyArray = function() {
+        console.log("testDescribedEmptyArray");
+        this._testArray("long", 0, "null");
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array((0).long());
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };  
+
+    DataTest._test = function(dtype, values) {
+        var values = Array.prototype.slice.apply(arguments, [1]);
+        var lastValue = values[values.length - 1];
+
+        // Default equality function. Note that we use valueOf because some of the
+        // types we are trying to compare (Symbol, Timestamp, Uuid etc.) are object
+        // types and we want to compare their value not whether they are the same object.
+        var eq = function(x, y) {return x.valueOf() === y.valueOf();};
+    
+        if (typeof lastValue === 'function') {
+            eq = values.pop();
+        }
+    
+        dtype = dtype.toUpperCase();
+        var ntype = proton.Data[dtype];
         var putter = 'put' + dtype;
-        this.data[putter](descriptor);
-    }
-    var putter = 'put' + atype;
-    for (var i = 0; i < values.length; i++) {
-        this.data[putter](values[i]);
-    }
-    this.data.exit();
-
-    // Check that we did indeed add an Array node
-    this.data.rewind();
-    assert(this.data.next() === proton.Data.ARRAY);
-
-    // Get the count, described and type metadata from the array node and compare
-    // with the values we passed to putARRAYNODE.
-    var metadata = this.data.getARRAYNODE();
-    var count = metadata.count;
-    var described = metadata.described;
-    var type = metadata.type;
-
-    assert(count === values.length);
-    if (dtype == null) {
-        assert(described === false);
-    } else {
-        assert(described === true);
-    }
-    assert(type === proton.Data[atype]);
-
-    // Enter the array node and compare the descriptor and values with those that
-    // we put into the array.
-    assert(this.data.enter());
-    if (described) {
-        assert(this.data.next() === proton.Data[dtype]);
         var getter = 'get' + dtype;
-        var gotten = this.data[getter]();
-        assert(gotten.toString() === descriptor.toString());
-    }
-    var getter = 'get' + atype;
-    for (var i = 0; i < values.length; i++) {
-        assert(this.data.next() === proton.Data[atype]);
-        var gotten = this.data[getter]();
-        assert(gotten.toString() === values[i].toString());
-    }
-    assert(this.data.next() === null);
-    assert(this.data.exit());
-};
-
-DataTest.testStringArray = function() {
-    console.log("testStringArray");
-    this._testArray(null, null, "string", "one", "two", "three");
-
-    // Now try using the proton.Data.Array class.
-    this.data.clear();
-    var put = new proton.Data.Array("STRING", ["four", "five", "six"]);
-    this.data.putARRAY(put);
-    var get = this.data.getARRAY();
-    assert(get.equals(put));
-    console.log("OK\n");
-};
-
-DataTest.testDescribedStringArray = function() {
-    console.log("testDescribedStringArray");
-    this._testArray("symbol", "url", "string", "one", "two", "three");
-
-    // Now try using the proton.Data.Array class.
-    this.data.clear();
-    var put = new proton.Data.Array("STRING", ["four", "five", "six"], new proton.Data.Symbol("url"));
-    this.data.putARRAY(put);
-    var get = this.data.getARRAY();
-    assert(get.equals(put));
-    console.log("OK\n");
-};
-
-DataTest.testIntArray = function() {
-    console.log("testIntArray");
-    this._testArray(null, null, "int", 1, 2, 3);
-
-    // Now try using the proton.Data.Array class.
-    this.data.clear();
-    var put = new proton.Data.Array("INT", [4, 5, 6]);
-    this.data.putARRAY(put);
-    var get = this.data.getARRAY();
-    assert(get.equals(put));
-    console.log("OK\n");
-};
-
-DataTest.testUUIDArray = function() {
-    console.log("testUUIDArray");
-    this._testArray(null, null, "uuid", new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid());
-
-    // Now try using the proton.Data.Array class.
-    this.data.clear();
-    var put = new proton.Data.Array("UUID", [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()]);
-    this.data.putARRAY(put);
-    var get = this.data.getARRAY();
-    assert(get.equals(put));
-    console.log("OK\n");
-};
-
-DataTest.testEmptyArray = function() {
-    console.log("testEmptyArray");
-    this._testArray(null, null, "null");
-
-    // Now try using the proton.Data.Array class.
-    this.data.clear();
-    var put = new proton.Data.Array();
-    this.data.putARRAY(put);
-    var get = this.data.getARRAY();
-    assert(get.equals(put));
-    console.log("OK\n");
-};
-
-DataTest.testDescribedEmptyArray = function() {
-    console.log("testDescribedEmptyArray");
-    this._testArray("long", 0, "null");
-
-    // Now try using the proton.Data.Array class.
-    this.data.clear();
-    var put = new proton.Data.Array((0).long());
-    this.data.putARRAY(put);
-    var get = this.data.getARRAY();
-    assert(get.equals(put));
-    console.log("OK\n");
-};
-
-DataTest._test = function(dtype, values) {
-    var values = Array.prototype.slice.apply(arguments, [1]);
-    var lastValue = values[values.length - 1];
-
-    // Default equality function. Note that we use valueOf because some of the
-    // types we are trying to compare (Symbol, Timestamp, Uuid etc.) are object
-    // types and we want to compare their value not whether they are the same object.
-    var eq = function(x, y) {return x.valueOf() === y.valueOf();};
-
-    if (typeof lastValue === 'function') {
-        eq = values.pop();
-    }
-
-    dtype = dtype.toUpperCase();
-    var ntype = proton.Data[dtype];
-    var putter = 'put' + dtype;
-    var getter = 'get' + dtype;
-
-    for (var i = 0; i < values.length; i++) {
-        var v = values[i];
-        /*
-         * Replace the array element with its value. We do this to make testing
-         * simpler for Binary elements. In the case of Binary putBINARY "consumes"
-         * the data, in other words ownership of the underlying raw data transfers
-         * to the Data object so the v object becomes "empty" after calling the
-         * putter. Calling its valueOf() happens to call its toString() which
-         * provides a stringified version of the Binary whilst also working for
-         * the other data types we want to test too.
-         */
-        values[i] = v.valueOf();
-        this.data[putter](v);
-        var gotten = this.data[getter]();
-        assert(eq(gotten, values[i]));
-    }
-
-    this.data.rewind();
-
-    for (var i = 0; i < values.length; i++) {
-        var v = values[i];
-        var vtype = this.data.next();
-        assert(vtype === ntype);
-        var gotten = this.data[getter]();
-        assert(eq(gotten, v));
-    }
-
-    // Test encode and decode methods.
-    var encoded = this.data.encode();
-    var copy = new proton.Data();
-    while (encoded) {
-        encoded = copy.decode(encoded);
-    }
-    copy.rewind();
-
-    for (var i = 0; i < values.length; i++) {
-        var v = values[i];
-        var vtype = copy.next();
-        assert(vtype === ntype);
-        var gotten = copy[getter]();
-        assert(eq(gotten, v));
-    }
-    copy.free();
-};
-
-DataTest.testInt = function() {
-    console.log("testInt");
-    this._test("int", 1, 2, 3, -1, -2, -3);
-    console.log("OK\n");
-
-};
-
-DataTest.testString = function() {
-    console.log("testString");
-    this._test("string", "one", "two", "three", "this is a test", "");
-    console.log("OK\n");
-};
-
-DataTest.testBigString = function() {
-    // Try a 2MB string, this is about as big as we can cope with using the default
-    // emscripten heap size. TODO add run-time mechanism to increase heap size.
-    console.log("testBigString");
-    var data = "";
-    for (var i = 0; i < 2000000; i++) {
-        data += "*";
-    }
-    var string = "start\n" + data + "\nfinish\n";
-    this._test("string", string);
-    console.log("OK\n");
-};
-
-DataTest.testFloat = function() {
-    console.log("testFloat");
-    // We have to use a special comparison here because JavaScript internally
-    // only uses doubles and converting between floats and doubles is imprecise.
-    this._test("float", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3,
-               function(x, y) {return (x - y < 0.000001);});
-    console.log("OK\n");
-};
-
-DataTest.testDouble = function() {
-    console.log("testDouble");
-    this._test("double", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3);
-    console.log("OK\n");
-};
-
-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("двоичные данные"));
-    console.log("OK\n");
-};
-
-DataTest.testSymbol = function() {
-    console.log("testSymbol");
-    this._test("symbol", new proton.Data.Symbol("this is a symbol test"),
-                         new proton.Data.Symbol("bleh"), new proton.Data.Symbol("blah"));
-    console.log("OK\n");
-};
-
-DataTest.testTimestamp = function() {
-    console.log("testTimestamp");
-    this._test("timestamp", new Date(0), new Date(12345), new Date(1000000));
-    console.log("OK\n");
-};
-
-DataTest.testChar = function() {
-    console.log("testChar");
-    this._test("char", 'a', 'b', 'c', '\u1234');
-    console.log("OK\n");
-};
-
-DataTest.testUUID = function() {
-    console.log("testUUID");
-    this._test("uuid", new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid());
-    console.log("OK\n");
-};
-
-/* TODO
-DataTest.testDecimal32 = function() {
-    console.log("testDecimal32");
-    //this._test("decimal32", 0, 1, 2, 3, 4, Math.pow(2, 30));
-};
-
-DataTest.testDecimal64 = function() {
-    console.log("testDecimal64");
-    //this._test("decimal64", 0, 1, 2, 3, 4, Math.pow(2, 60));
-};
-
-DataTest.testDecimal128 = function() {
-    console.log("testDecimal128");
-    // TODO
-};
+    
+        for (var i = 0; i < values.length; i++) {
+            var v = values[i];
+            /*
+             * Replace the array element with its value. We do this to make testing
+             * simpler for Binary elements. In the case of Binary putBINARY "consumes"
+             * the data, in other words ownership of the underlying raw data transfers
+             * to the Data object so the v object becomes "empty" after calling the
+             * putter. Calling its valueOf() happens to call its toString() which
+             * provides a stringified version of the Binary whilst also working for
+             * the other data types we want to test too.
+             */
+            values[i] = v.valueOf();
+            this.data[putter](v);
+            var gotten = this.data[getter]();
+            assert(eq(gotten, values[i]));
+        }
+    
+        this.data.rewind();
+    
+        for (var i = 0; i < values.length; i++) {
+            var v = values[i];
+            var vtype = this.data.next();
+            assert(vtype === ntype);
+            var gotten = this.data[getter]();
+            assert(eq(gotten, v));
+        }
+    
+        // Test encode and decode methods.
+        var encoded = this.data.encode();
+        var copy = new proton.Data();
+        while (encoded) {
+            encoded = copy.decode(encoded);
+        }
+        copy.rewind();
+    
+        for (var i = 0; i < values.length; i++) {
+            var v = values[i];
+            var vtype = copy.next();
+            assert(vtype === ntype);
+            var gotten = copy[getter]();
+            assert(eq(gotten, v));
+        }
+        copy.free();
+    };  
+    
+    DataTest.testInt = function() {
+        console.log("testInt");
+        this._test("int", 1, 2, 3, -1, -2, -3);
+        console.log("OK\n");
+    
+    };  
+
+    DataTest.testString = function() {
+        console.log("testString");
+        this._test("string", "one", "two", "three", "this is a test", "");
+        console.log("OK\n");
+    };  
+
+    DataTest.testBigString = function() {
+        // Try a 2MB string, this is about as big as we can cope with using the default
+        // emscripten heap size.
+        console.log("testBigString");
+        var data = "";
+        for (var i = 0; i < 2000000; i++) {
+            data += "*";
+        }
+        var string = "start\n" + data + "\nfinish\n";
+        this._test("string", string);
+        console.log("OK\n");
+    };  
+
+/* TODO - currently emscripten isn't respecting Module['TOTAL_STACK'] so setting PROTON_TOTAL_STACK doesn't actually increase the stack size.
+    DataTest.testReallyBigString = function() {
+        // Try a 20MB string, this needs a bigger emscripten heap size and more stack
+        // as the default stack is 5MB and strings are allocated on the stack.
+        console.log("testReallyBigString");
+        var data = "";
+        for (var i = 0; i < 20000000; i++) {
+            data += "*";
+        }
+        var string = "start\n" + data + "\nfinish\n";
+        this._test("string", string);
+        console.log("OK\n");
+    };
 */
 
-DataTest.testCopy = function() {
-    console.log("testCopy");
-    this.data.putDESCRIBEDNODE();
-    this.data.enter();
-    this.data.putULONG(123);
-    this.data.putMAPNODE();
-    this.data.enter();
-    this.data.putSTRING("pi");
-    this.data.putDOUBLE(3.14159265359);
-    this.data.exit();
-    this.data.exit();
-
-    var dst = this.data.copy();
-    var copy = dst.format();
-    var orig = this.data.format();
-    assert(copy === orig);
-    dst.free();
-    console.log("OK\n");
-};
-
-DataTest.testCopyNested = function() {
-    console.log("testCopyNested");
-    var nested = [1, 2, 3, [4, 5, 6], 7, 8, 9];
-    this.data.putObject(nested);
-    var dst = this.data.copy();
-    assert(dst.format() === this.data.format());
-    dst.free();
-    console.log("OK\n");
-};
-
-DataTest.testCopyNestedArray = function() {
-    console.log("testCopyNestedArray");
-    var nested = [new proton.Data.Array("LIST", [
-                    ["first",  [new proton.Data.Array("INT", [1, 2, 3]), "this"]],
-                    ["second", [new proton.Data.Array("INT", [1, 2, 3]), "is"]],
-                    ["third",  [new proton.Data.Array("INT", [1, 2, 3]), "fun"]]
-                    ]),
-                "end"];
-    this.data.putObject(nested);
-    var dst = this.data.copy();
-    assert(dst.format() === this.data.format());
-    dst.free();
-    console.log("OK\n");
-};
-
-DataTest.testRoundTrip = function() {
-    console.log("testRoundTrip");
-    var obj = {key: new Date(1234),
-               123: "blah",
-               c: "bleh",
-               desc: new proton.Data.Described("http://example.org", new proton.Data.Symbol("url")),
-               array: new proton.Data.Array("INT", [1, 2, 3]),
-               list: [1, 2, 3, null, 4],
-               boolean: true};
-    // Serialise obj into this.data.
-    this.data.putObject(obj);
-
-    // Encode this.data into a Binary representation.
-    var enc = this.data.encode();
-
-    // Create a new Data instance and decode from the Binary representation
-    // consuming the Binary contents in the process.
-    var data = new proton.Data();
-    data.decode(enc);
-
-    assert(data.format() === this.data.format());
-
-    // Deserialise from the copied Data instance into a new JavaScript Object.
-    data.rewind();
-    assert(data.next());
-    var copy = data.getObject();
-
-    // Create yet another Data instance and serialise the new Object into that.
-    var data1 = new proton.Data();
-    data1.putObject(copy);
-
-    // Compare the round tripped Data with the original one.
-    assert(data1.format() === this.data.format());
-
-    data.free();
-    data1.free();
-    console.log("OK\n");
-};
-
-DataTest.testLookup = function() {
-    console.log("testLookup");
-    var obj = {key: "value",
-               pi: 3.14159,
-               list: [1, 2, 3, 4]};
-    // Serialise obj into this.data.
-    this.data.putObject(obj);
-    this.data.rewind();
-    this.data.next();
-    this.data.enter();
-    this.data.narrow();
-    assert(this.data.lookup("pi"));
-    assert(this.data.getObject() === 3.14159);
-    this.data.rewind();
-    assert(this.data.lookup("key"));
-    assert(this.data.getObject() === "value");
-    this.data.rewind();
-    assert(this.data.lookup("list"));
-    assert(this.data.getObject().toString() === "1,2,3,4");
-    this.data.widen();
-    this.data.rewind();
-    assert(!this.data.lookup("pi"));
-    console.log("OK\n");
-};
-
-DataTest.run();
-
+    DataTest.testFloat = function() {
+        console.log("testFloat");
+        // We have to use a special comparison here because JavaScript internally
+        // only uses doubles and converting between floats and doubles is imprecise.
+        this._test("float", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3,
+                   function(x, y) {return (x - y < 0.000001);});
+        console.log("OK\n");
+    };  
+
+    DataTest.testDouble = function() {
+        console.log("testDouble");
+        this._test("double", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3);
+        console.log("OK\n");
+    };  
+
+    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("двоичные данные"));
+        console.log("OK\n");
+    };  
+
+    DataTest.testSymbol = function() {
+        console.log("testSymbol");
+        this._test("symbol", new proton.Data.Symbol("this is a symbol test"),
+                             new proton.Data.Symbol("bleh"), new proton.Data.Symbol("blah"));
+        console.log("OK\n");
+    };
+
+    DataTest.testTimestamp = function() {
+        console.log("testTimestamp");
+        this._test("timestamp", new Date(0), new Date(12345), new Date(1000000));
+        console.log("OK\n");
+    };  
+
+    DataTest.testChar = function() {
+        console.log("testChar");
+        this._test("char", 'a', 'b', 'c', '\u1234');
+        console.log("OK\n");
+    };  
+
+    DataTest.testUUID = function() {
+        console.log("testUUID");
+        this._test("uuid", new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid());
+        console.log("OK\n");
+    };
+
+    /* TODO
+    DataTest.testDecimal32 = function() {
+        console.log("testDecimal32");
+        //this._test("decimal32", 0, 1, 2, 3, 4, Math.pow(2, 30));
+    };
+
+    DataTest.testDecimal64 = function() {
+        console.log("testDecimal64");
+        //this._test("decimal64", 0, 1, 2, 3, 4, Math.pow(2, 60));
+    };  
+
+    DataTest.testDecimal128 = function() {
+        console.log("testDecimal128");
+        // TODO
+    };
+    */
+
+    DataTest.testCopy = function() {
+        console.log("testCopy");
+        this.data.putDESCRIBEDNODE();
+        this.data.enter();
+        this.data.putULONG(123);
+        this.data.putMAPNODE();
+        this.data.enter();
+        this.data.putSTRING("pi");
+        this.data.putDOUBLE(3.14159265359);
+        this.data.exit();
+        this.data.exit();
+    
+        var dst = this.data.copy();
+        var copy = dst.format();
+        var orig = this.data.format();
+        assert(copy === orig);
+        dst.free();
+        console.log("OK\n");
+    };  
+
+    DataTest.testCopyNested = function() {
+        console.log("testCopyNested");
+        var nested = [1, 2, 3, [4, 5, 6], 7, 8, 9];
+        this.data.putObject(nested);
+        var dst = this.data.copy();
+        assert(dst.format() === this.data.format());
+        dst.free();
+        console.log("OK\n");
+    };  
+
+    DataTest.testCopyNestedArray = function() {
+        console.log("testCopyNestedArray");
+        var nested = [new proton.Data.Array("LIST", [
+                        ["first",  [new proton.Data.Array("INT", [1, 2, 3]), "this"]],
+                        ["second", [new proton.Data.Array("INT", [1, 2, 3]), "is"]],
+                        ["third",  [new proton.Data.Array("INT", [1, 2, 3]), "fun"]]
+                        ]),
+                    "end"];
+        this.data.putObject(nested);
+        var dst = this.data.copy();
+        assert(dst.format() === this.data.format());
+        dst.free();
+        console.log("OK\n");
+    };
+
+    DataTest.testRoundTrip = function() {
+        console.log("testRoundTrip");
+        var obj = {key: new Date(1234),
+                   123: "blah",
+                   c: "bleh",
+                   desc: new proton.Data.Described("http://example.org", new proton.Data.Symbol("url")),
+                   array: new proton.Data.Array("INT", [1, 2, 3]),
+                   list: [1, 2, 3, null, 4],
+                   boolean: true};
+        // Serialise obj into this.data.
+        this.data.putObject(obj);
+    
+        // Encode this.data into a Binary representation.
+        var enc = this.data.encode();
+    
+        // Create a new Data instance and decode from the Binary representation
+        // consuming the Binary contents in the process.
+        var data = new proton.Data();
+        data.decode(enc);
+    
+        assert(data.format() === this.data.format());
+    
+        // Deserialise from the copied Data instance into a new JavaScript Object.
+        data.rewind();
+        assert(data.next());
+        var copy = data.getObject();
+    
+        // Create yet another Data instance and serialise the new Object into that.
+        var data1 = new proton.Data();
+        data1.putObject(copy);
+    
+        // Compare the round tripped Data with the original one.
+        assert(data1.format() === this.data.format());
+    
+        data.free();
+        data1.free();
+        console.log("OK\n");
+    };
+
+    DataTest.testLookup = function() {
+        console.log("testLookup");
+        var obj = {key: "value",
+                   pi: 3.14159,
+                   list: [1, 2, 3, 4]};
+        // Serialise obj into this.data.
+        this.data.putObject(obj);
+        this.data.rewind();
+        this.data.next();
+        this.data.enter();
+        this.data.narrow();
+        assert(this.data.lookup("pi"));
+        assert(this.data.getObject() === 3.14159);
+        this.data.rewind();
+        assert(this.data.lookup("key"));
+        assert(this.data.getObject() === "value");
+        this.data.rewind();
+        assert(this.data.lookup("list"));
+        assert(this.data.getObject().toString() === "1,2,3,4");
+        this.data.widen();
+        this.data.rewind();
+        assert(!this.data.lookup("pi"));
+        console.log("OK\n");
+    };  
+
+    DataTest.run();
+} else {
+    console.error("codec.js should be run in Node.js");
+}
 


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


[26/51] [abbrv] qpid-proton git commit: Updated with two proton fixes that enable Clang to compile cleanly

Posted by rh...@apache.org.
Updated with two proton fixes that enable Clang to compile cleanly

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1622877 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/a8566983
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/a8566983
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/a8566983

Branch: refs/heads/master
Commit: a8566983a073c64311fad2369c89125c1f97b5c5
Parents: 1c2f489
Author: fadams <fa...@unknown>
Authored: Sat Sep 6 15:49:04 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sat Sep 6 15:49:04 2014 +0000

----------------------------------------------------------------------
 proton-c/src/codec/codec.c   | 2 +-
 proton-c/src/codec/decoder.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a8566983/proton-c/src/codec/codec.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/codec.c b/proton-c/src/codec/codec.c
index 0660032..87d7df7 100644
--- a/proton-c/src/codec/codec.c
+++ b/proton-c/src/codec/codec.c
@@ -141,7 +141,7 @@ int pni_inspect_atom(pn_atom_t *atom, pn_string_t *str)
   case PN_INT:
     return pn_string_addf(str, "%" PRIi32, atom->u.as_int);
   case PN_CHAR:
-    return pn_string_addf(str, "%lc",  atom->u.as_char);
+    return pn_string_addf(str, "%c",  atom->u.as_char);
   case PN_ULONG:
     return pn_string_addf(str, "%" PRIu64, atom->u.as_ulong);
   case PN_LONG:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a8566983/proton-c/src/codec/decoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/decoder.c b/proton-c/src/codec/decoder.c
index 28e8ae1..7a01388 100644
--- a/proton-c/src/codec/decoder.c
+++ b/proton-c/src/codec/decoder.c
@@ -395,7 +395,7 @@ int pn_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code
         int e = pn_decoder_decode_type(decoder, data, &acode);
         if (e) return e;
         pn_type_t type = pn_code2type(acode);
-        if (type < 0) return type;
+        if ((int)type < 0) return (int)type;
         for (size_t i = 0; i < count; i++)
         {
           e = pn_decoder_decode_value(decoder, data, acode);


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


[51/51] [abbrv] qpid-proton git commit: Merge branch 'javascript'

Posted by rh...@apache.org.
Merge branch 'javascript'


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/e8029597
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/e8029597
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/e8029597

Branch: refs/heads/master
Commit: e8029597b825e49ee5ab2b7c8bd5d042e57321bb
Parents: db437cf a5cb27e
Author: Rafael Schloming <rh...@alum.mit.edu>
Authored: Fri Nov 28 08:43:03 2014 -0500
Committer: Rafael Schloming <rh...@alum.mit.edu>
Committed: Fri Nov 28 08:43:03 2014 -0500

----------------------------------------------------------------------
 examples/messenger/c/CMakeLists.txt             |    4 +
 examples/messenger/c/recv-async.c               |  193 +++
 examples/messenger/c/send-async.c               |  167 ++
 examples/messenger/javascript/client.js         |  104 ++
 examples/messenger/javascript/drain.js          |   70 +
 examples/messenger/javascript/proxy.js          |  105 ++
 examples/messenger/javascript/qpid-config.js    | 1511 +++++++++++++++++
 examples/messenger/javascript/recv.js           |   69 +
 examples/messenger/javascript/send.html         |  121 ++
 examples/messenger/javascript/send.js           |  105 ++
 examples/messenger/javascript/server.js         |   81 +
 examples/messenger/javascript/spout.js          |   71 +
 examples/messenger/javascript/ws2tcp.js         |  162 ++
 proton-c/CMakeLists.txt                         |   18 +
 proton-c/bindings/javascript/CMakeLists.txt     |  272 +++
 proton-c/bindings/javascript/LICENSE            |  203 +++
 proton-c/bindings/javascript/README             |  426 +++++
 proton-c/bindings/javascript/TODO               |   49 +
 proton-c/bindings/javascript/binding-close.js   |   33 +
 proton-c/bindings/javascript/binding-open.js    |   21 +
 proton-c/bindings/javascript/binding.c          |   34 +
 proton-c/bindings/javascript/data-array.js      |  100 ++
 proton-c/bindings/javascript/data-binary.js     |  181 ++
 proton-c/bindings/javascript/data-described.js  |   74 +
 proton-c/bindings/javascript/data-long.js       |  191 +++
 proton-c/bindings/javascript/data-symbol.js     |   59 +
 .../bindings/javascript/data-typed-number.js    |  108 ++
 proton-c/bindings/javascript/data-uuid.js       |  107 ++
 proton-c/bindings/javascript/data.js            | 1577 ++++++++++++++++++
 proton-c/bindings/javascript/error.js           |  172 ++
 proton-c/bindings/javascript/message.js         |  848 ++++++++++
 proton-c/bindings/javascript/messenger.js       |  810 +++++++++
 proton-c/bindings/javascript/module.js          |  426 +++++
 .../bindings/javascript/qpid-proton/LICENSE     |  203 +++
 .../bindings/javascript/qpid-proton/README.md   |    4 +
 .../javascript/qpid-proton/lib/.gitignore       |   21 +
 .../javascript/qpid-proton/package.json         |   11 +
 proton-c/bindings/javascript/subscription.js    |   81 +
 tests/javascript/codec.js                       |  569 +++++++
 tests/javascript/message.js                     |  359 ++++
 tests/javascript/soak.js                        |   93 ++
 tests/javascript/unittest.js                    |   45 +
 tools/cmake/Modules/FindEmscripten.cmake        |   40 +
 tools/cmake/Modules/FindNodePackages.cmake      |   69 +
 44 files changed, 9967 insertions(+)
----------------------------------------------------------------------



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


[48/51] [abbrv] qpid-proton git commit: Replace pn_messenger_work based event handling with selectable based implementation in order to have more control. This greatly improves error handling and allows much cleaner tidying up of resources when errors oc

Posted by rh...@apache.org.
Replace pn_messenger_work based event handling with selectable based implementation in order to have more control. This greatly improves error handling and allows much cleaner tidying up of resources when errors occur

git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/fadams-javascript-binding@1631208 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/e8faa57e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/e8faa57e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/e8faa57e

Branch: refs/heads/master
Commit: e8faa57eafcb567d3447d817bd500d1a4e9cc41a
Parents: 0d44f57
Author: fadams <fa...@unknown>
Authored: Sun Oct 12 16:45:29 2014 +0000
Committer: fadams <fa...@unknown>
Committed: Sun Oct 12 16:45:29 2014 +0000

----------------------------------------------------------------------
 examples/messenger/javascript/send.html      |   9 -
 proton-c/bindings/javascript/CMakeLists.txt  |   2 +-
 proton-c/bindings/javascript/error.js        |  33 +-
 proton-c/bindings/javascript/messenger.js    |  57 +---
 proton-c/bindings/javascript/module.js       | 370 ++++++++++++++++------
 proton-c/bindings/javascript/subscription.js |  18 +-
 proton-c/src/codec/data.h                    |   2 +-
 7 files changed, 339 insertions(+), 152 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e8faa57e/examples/messenger/javascript/send.html
----------------------------------------------------------------------
diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html
index f38a78e..c61e3f2 100644
--- a/examples/messenger/javascript/send.html
+++ b/examples/messenger/javascript/send.html
@@ -67,15 +67,6 @@ console.log("body = " + body);
 
 var errorHandler = function(error) {
     console.log("Received error " + error);
-
-    // Error recovery seems to require a new Messenger instance.
-    messenger.stop();
-    messenger.free();
-    messenger = new proton.Messenger();
-
-    messenger.on('error', errorHandler);
-    messenger.start();
-    console.log("Restarted");
 };
 
 messenger.on('error', errorHandler);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e8faa57e/proton-c/bindings/javascript/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
index 316dbe4..ee1241f 100644
--- a/proton-c/bindings/javascript/CMakeLists.txt
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -216,7 +216,7 @@ set_target_properties(
   # fiddly with node.js packages. This behaviour might be reinstated if the
   # packaging mechanism improves.
 
-  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/module.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/error.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/message.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_get_version_major', '_
 pn_get_version_minor', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message',
  '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_messa
 ge_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_d
 ecimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump']\""
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/module.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/error.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/message.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_get_version_major', '_
 pn_get_version_minor', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_messenger_set_passive', '_pn_messenger_selectable', '_pn_subscription_get_context', '_pn_subscription
 _set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_s
 et_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_p
 n_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump', '_pn_selectable_readable', '_pn_selectable_capacity', '_pn_selectable_writable', '_pn_selectable_pending', '_pn_s
 electable_is_terminal', '_pn_selectable_fd', '_pn_selectable_free']\""
   )
 
 # This command packages up the compiled proton.js into a node.js package called

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e8faa57e/proton-c/bindings/javascript/error.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/error.js b/proton-c/bindings/javascript/error.js
index a1553b0..4069bef 100644
--- a/proton-c/bindings/javascript/error.js
+++ b/proton-c/bindings/javascript/error.js
@@ -90,7 +90,34 @@ Module['MessengerError'].prototype = new Error();
 Module['MessengerError'].prototype.constructor = Module['MessengerError'];
 
 Module['MessengerError'].prototype.toString = function() {
-    return this.name + ': ' + this.message
+    return this.name + ': ' + this.message;
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                              SubscriptionError                            */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.SubscriptionError instance.
+ * @classdesc This class is a subclass of MessengerError.
+ * @constructor proton.SubscriptionError
+ * @param {string} source the address that we want to subscribe to.
+ * @param {string} message the error message.
+ */
+Module['SubscriptionError'] = function(source, message) { // SubscriptionError constructor.
+    this.name = "SubscriptionError";
+    this.source = source;
+    this.message = (message || "");
+};
+
+Module['SubscriptionError'].prototype = new Module['MessengerError']();
+Module['SubscriptionError'].prototype.constructor = Module['SubscriptionError'];
+
+Module['SubscriptionError'].prototype.toString = function() {
+    return this.name + ': ' + this.source + ': ' + this.message;
 };
 
 
@@ -115,7 +142,7 @@ Module['MessageError'].prototype = new Error();
 Module['MessageError'].prototype.constructor = Module['MessageError'];
 
 Module['MessageError'].prototype.toString = function() {
-    return this.name + ': ' + this.message
+    return this.name + ': ' + this.message;
 };
 
 
@@ -140,6 +167,6 @@ Module['DataError'].prototype = new Error();
 Module['DataError'].prototype.constructor = Module['DataError'];
 
 Module['DataError'].prototype.toString = function() {
-    return this.name + ': ' + this.message
+    return this.name + ': ' + this.message;
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e8faa57e/proton-c/bindings/javascript/messenger.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/messenger.js b/proton-c/bindings/javascript/messenger.js
index 80eec5b..e2f4418 100644
--- a/proton-c/bindings/javascript/messenger.js
+++ b/proton-c/bindings/javascript/messenger.js
@@ -269,14 +269,14 @@ _Messenger_['removeListener'] = function(event, callback) {
             // Search for the specified callback.
             for (var i = 0; i < callbacks.length; i++) {
                 if (callback === callbacks[i]) {
-                    // If we find the specified callback delete it and return.
+                    // If we find the specified callback, delete it and return.
                     callbacks.splice(i, 1);
                     return;
                 }
             }
         }
     } else {
-        // If we call remove with no callback we remove all callbacks.
+        // If we call remove with no callback specified we remove all callbacks.
         delete this._callbacks[event];
     }
 };
@@ -368,7 +368,7 @@ _Messenger_['getOutgoingWindow'] = function() {
  * @param {number} window the size of the tracking window in messages.
  */
 _Messenger_['setOutgoingWindow'] = function(window) {
-    this._check(_pn_messenger_set_outgoing_window(this._messenger, window));
+    _pn_messenger_set_outgoing_window(this._messenger, window);
 };
 
 /**
@@ -397,7 +397,7 @@ _Messenger_['getIncomingWindow'] = function() {
  * @param {number} window the size of the tracking window in messages.
  */
 _Messenger_['setIncomingWindow'] = function(window) {
-    this._check(_pn_messenger_set_incoming_window(this._messenger, window));
+    _pn_messenger_set_incoming_window(this._messenger, window);
 };
 
 /**
@@ -421,10 +421,9 @@ _Messenger_['start'] = function() {
  * to see if it has fully stopped.
  * @method stop
  * @memberof! proton.Messenger#
- * @returns {@link proton.Error.INPROGRESS} if still busy.
  */
 _Messenger_['stop'] = function() {
-    return this._check(_pn_messenger_stop(this._messenger));
+    _pn_messenger_stop(this._messenger);
 };
 
 /**
@@ -454,29 +453,10 @@ _Messenger_['isStopped'] = function() {
  */
 _Messenger_['subscribe'] = function(source) {
     if (!source) {
-        this._check(Module['Error']['ARG_ERR']);
-    }
-    var sp = Runtime.stackSave();
-    Module.EventDispatch.setCurrentMessenger(this);
-    var subscription = _pn_messenger_subscribe(this._messenger,
-                                               allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
-    Module.EventDispatch.setCurrentMessenger(null);
-    Runtime.stackRestore(sp);
-
-    if (!subscription) {
-        this._check(Module['Error']['ERR']);
-    }
-
-    // For peer subscriptions to this Messenger emit a subscription event
-    // immediately otherwise defer until the address is resolved remotely.
-    if (source.indexOf('~') !== -1) {
-        subscription = new Subscription(subscription, source);
-        this._emit('subscription', subscription);
+        this._emit('error', new Module['SubscriptionError'](source, 'CONNECTION ERROR: Address not specified'));
     } else {
-        subscription = new Subscription(subscription)
-        this._pendingSubscriptions.push(subscription);
+        return Module.EventDispatch.subscribe(this, source);
     }
-    return subscription;
 };
 
 /**
@@ -504,13 +484,10 @@ _Messenger_['subscribe'] = function(source) {
 _Messenger_['put'] = function(message, flush) {
     flush = flush === false ? false : true; // Defaults to true if not explicitly specified.
     message._preEncode();
-    Module.EventDispatch.setCurrentMessenger(this);
     this._check(_pn_messenger_put(this._messenger, message._message));
-    Module.EventDispatch.setCurrentMessenger(null);
 
-    // If flush is set invoke pn_messenger_work.
     if (flush) {
-        this._check(_pn_messenger_work(this._messenger, 0));
+        Module.EventDispatch.flush();
     }
 
     // Getting the tracker is a little tricky as it is a 64 bit number. The way
@@ -577,7 +554,7 @@ _Messenger_['settle'] = function(tracker) {
         flags = Module['Messenger'].PN_CUMULATIVE;
     }
 
-    this._check(_pn_messenger_settle(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
+    _pn_messenger_settle(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags);
 };
 
 /**
@@ -602,7 +579,7 @@ _Messenger_['work'] = function() {
  *        as many messages as it can buffer internally.
  */
 _Messenger_['recv'] = function(limit) {
-    this._check(_pn_messenger_recv(this._messenger, (limit ? limit : -1)));
+    _pn_messenger_recv(this._messenger, (limit ? limit : -1));
 };
 
 /**
@@ -641,7 +618,7 @@ _Messenger_['get'] = function(message, decodeBinaryAsString) {
         impl = message._message;
     }
 
-    this._check(_pn_messenger_get(this._messenger, impl));
+    _pn_messenger_get(this._messenger, impl);
 
     if (message) {
         message._postDecode(decodeBinaryAsString);
@@ -798,9 +775,9 @@ _Messenger_['incoming'] = function() {
  */
 _Messenger_['route'] = function(pattern, address) {
     var sp = Runtime.stackSave();
-    this._check(_pn_messenger_route(this._messenger,
-                                    allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
-                                    allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
+    _pn_messenger_route(this._messenger,
+                        allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
+                        allocate(intArrayFromString(address), 'i8', ALLOC_STACK));
     Runtime.stackRestore(sp);
 };
 
@@ -825,9 +802,9 @@ _Messenger_['route'] = function(pattern, address) {
  */
 _Messenger_['rewrite'] = function(pattern, address) {
     var sp = Runtime.stackSave();
-    this._check(_pn_messenger_rewrite(this._messenger,
-                                      allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
-                                      allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
+    _pn_messenger_rewrite(this._messenger,
+                          allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
+                          allocate(intArrayFromString(address), 'i8', ALLOC_STACK));
     Runtime.stackRestore(sp);
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e8faa57e/proton-c/bindings/javascript/module.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/module.js b/proton-c/bindings/javascript/module.js
index aefceca..b755f59 100644
--- a/proton-c/bindings/javascript/module.js
+++ b/proton-c/bindings/javascript/module.js
@@ -68,6 +68,10 @@
  * &lt;script type="text/javascript"&gt;PROTON_TOTAL_MEMORY = 50000000;&lt;/script&gt;
  * &lt;script type="text/javascript" src="proton.js">&lt;/script&gt;
  * </pre>
+ * If the global variable PROTON_TOTAL_MEMORY has been set by the application this
+ * will result in the emscripten heap getting set to the next multiple of
+ * 16777216 above PROTON_TOTAL_MEMORY.
+ * <p>
  * The global variable PROTON_TOTAL_STACK may be used in a similar way to increase
  * the stack size from its default of 5*1024*1024 = 5242880. It is worth noting
  * that Strings are allocated on the stack, so you may need this if you end up
@@ -76,17 +80,14 @@
  */
 var Module = {};
 
-// If the global variable PROTON_TOTAL_MEMORY has been set by the application this
-// will result in the emscripten heap getting set to the next multiple of
-// 16777216 above PROTON_TOTAL_MEMORY.
-if (typeof process === 'object' && typeof require === 'function') {
+if (typeof global === 'object') { // If Node.js
     if (global['PROTON_TOTAL_MEMORY']) {
         Module['TOTAL_MEMORY'] = global['PROTON_TOTAL_MEMORY'];
     }
     if (global['PROTON_TOTAL_STACK']) {
         Module['TOTAL_STACK'] = global['PROTON_TOTAL_STACK'];
     }
-} else if (typeof window === 'object') {
+} else if (typeof window === 'object') { // If browser
     if (window['PROTON_TOTAL_MEMORY']) {
         Module['TOTAL_MEMORY'] = window['PROTON_TOTAL_MEMORY'];
     }
@@ -102,140 +103,323 @@ if (typeof process === 'object' && typeof require === 'function') {
 /*****************************************************************************/
 
 /**
- * EventDispatch is a Singleton class that allows callbacks to be registered which
- * will get triggered by the emscripten WebSocket network callbacks. Clients of
- * Messenger will register callbacks by calling:
+ * EventDispatch is a Singleton class that allows callbacks to be registered,
+ * which will get triggered by the emscripten WebSocket network callbacks.
+ * Clients of Messenger will register callbacks by calling:
  * <pre>
+ * messenger.on('error', &lt;callback function&gt;);
  * messenger.on('work', &lt;callback function&gt;);
+ * messenger.on('subscription', &lt;callback function&gt;);
  * </pre>
  * EventDispatch supports callback registration from multiple Messenger instances.
  * The client callbacks will actually be called when a given messenger has work
- * available or a WebSocket close has been occurred (in which case all registered
- * callbacks will be called).
+ * available or a WebSocket close has been occurred.
  * <p>
  * The approach implemented here allows the registered callbacks to follow a
  * similar pattern to _process_incoming and _process_outgoing in async.py
- * @memberof proton
+ * @constructor proton.EventDispatch
  */
 Module.EventDispatch = new function() { // Note the use of new to create a Singleton.
-    var _firstCall = true; // Flag used to check the first time registerMessenger is called.
+    var POLLIN  = 0x001;
+    var POLLOUT = 0x004;
+    var _error = null;
+    var _messengers = {};  // Keyed by name.
+    var _selectables = {}; // Keyed by file descriptor.
+
+    var _initialise = function() {
+        /**
+         * Initialises the emscripten network callback functions. This needs
+         * to be done the first time we call registerMessenger rather than
+         * when we create the Singleton because emscripten's socket filesystem
+         * has to be mounted before can listen for any of these events.
+         */
+        Module['websocket']['on']('open', _pump);
+        Module['websocket']['on']('connection', _pump);
+        Module['websocket']['on']('message', _pump);
+        Module['websocket']['on']('close', _closeHandler);
+        Module['websocket']['on']('error', _errorHandler);
+
+        /**
+         * For Node.js the network code uses the ws WebSocket library, see
+         * https://github.com/einaros/ws. The following is a "Monkey Patch"
+         * that fixes a problem with Receiver.js where it wasn't checking if
+         * an Object was null before accessing its properties, so it was
+         * possible to see errors like:
+         * TypeError: Cannot read property 'fragmentedOperation' of null
+         * at Receiver.endPacket (.....node_modules/ws/lib/Receiver.js:224:18)
+         * This problem is generally seen in Server code after messenger.stop()
+         * I *think* that the underlying issue is actually because ws calls
+         * cleanup directly rather than pushing it onto the event loop so the
+         * this.state stuff gets cleared before the endPacket method is called.
+         * This fix simply interposes a check to avoid calling endPacket if
+         * the state has been cleared (i.e. the WebSocket has been closed).
+         */
+        if (ENVIRONMENT_IS_NODE) {
+            try {
+                var ws = require('ws');
+                // Array notation to stop Closure compiler minifying properties we need.
+                ws['Receiver'].prototype['originalEndPacket'] = ws['Receiver'].prototype['endPacket'];
+                ws['Receiver'].prototype['endPacket'] = function() {
+                    if (this['state']) {
+                        this['originalEndPacket']();
+                    }
+                };
+            } catch (e) {
+                console.error("Failed to apply Monkey Patch to ws WebSocket library");
+            }
+        }
+
+        _initialise = function() {}; // After first call replace with null function.
+    };
+
     /**
-     * We employ a cheat/hack to map file descriptors to the Messenger instance
-     * that owns them. In put/subscribe we set the current Messenger and then we
-     * intercept the library socket call with our own, which makes a call to
-     * the real library socket but also maps the file descriptor to _currentMessenger.
+     * Messenger error handling can be a bit inconsistent and in several places
+     * rather than returning an error code or setting an error it simply writes
+     * to fprintf. This is something of a Monkey Patch that replaces the emscripten
+     * library fprintf call with one that checks the message and sets a variable
+     * if the message is an ERROR. TODO At some point hopefully Dominic Evans'
+     * patch on Jira PROTON-571 will render this code redundant.
      */
-    var _currentMessenger = null;
-    var _messengers = {};
-
-    var _fd2Messenger = {};
+    _fprintf = function(stream, format, varargs) {
+        var array = __formatString(format, varargs);
+        array.pop(); // Remove the trailing \n
+        var string = intArrayToString(array); // Convert to native JavaScript string.
+        if (string.indexOf('ERROR') === -1) { // If not an ERROR just log the message.
+            console.log(string);
+        } else {
+            _error = string;
+        }
+    };
 
     /**
-     * Provides functionality roughly equivalent to the following C code:
-     * while (1) {
-     *     pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
-     *     process();
-     * }
-     * The blocking call isn't viable in JavaScript as it is entirely asynchronous
-     * and we wouldn't want to replace the while(1) with a timed loop either!!
-     * This method gets triggered asynchronously by the emscripten socket events and
-     * we then perform an equivalent loop for each messenger, triggering every
-     * registered callback whilst there is work remaining. If triggered by close
-     * we bypass the _pn_messenger_work test as it will never succeed after closing.
+     * This method iterates through all registered Messengers and retrieves any
+     * pending selectables, which are stored in a _selectables map keyed by fd.
      */
-    var _pump = function(fd, closing) {
-//console.log("\t_pump entry " + fd + ", " + closing);
-        for (var i in _messengers) {
-            if (_messengers.hasOwnProperty(i)) {
-                var messenger = _messengers[i];
-                //var messenger = _fd2Messenger[fd];
-
-                if (closing) {
-//console.log("_pump closing");
-                    messenger._emit('work');
+    var _updateSelectables = function() {
+        var sel = 0;
+        var fd = -1;
+        for (var name in _messengers) {
+            var messenger = _messengers[name];
+            while ((sel = _pn_messenger_selectable(messenger._messenger))) {
+                fd = _pn_selectable_fd(sel);
+                // Only register valid selectables, otherwise free them.
+                if (fd === -1) {
+                    _pn_selectable_free(sel);
                 } else {
-//console.log("_pump while start");
-                    while (_pn_messenger_work(messenger._messenger, 0) > 0) {
-                    //while (messenger['work']()) {
-                    //while (messenger._check(_pn_messenger_work(messenger._messenger, 0)) > 0) {
-//console.log("A");
-                        messenger._checkSubscriptions();
-                        messenger._emit('work');
-//console.log("B");
+                    _selectables[fd] = {messenger: messenger, selectable: sel};
+                }
+            }
+        }
+        return fd; // Return the most recently added selector's file descriptor.
+    };
+
+    /**
+     * Continually pump data while there's still work to do.
+     */
+    var _pump = function() {
+        while (_pumpOnce());
+    };
+
+    /**
+     * This method more or less follows the pattern of the pump_once method from
+     * class Pump in tests/python/proton_tests/messenger.py. It looks a little
+     * different because the select/poll implemented here uses some low-level
+     * emscripten internals (stream = FS.getStream(fd), sock = stream.node.sock,
+     * mask = sock.sock_ops.poll(sock)). We use the internals so we don't have
+     * to massage from file descriptors into the C style poll interface.
+     */
+    var _pumpOnce = function() {
+        _updateSelectables();
+
+        var count = 0;
+        for (var fd in _selectables) {
+            var selectable = _selectables[fd];
+            var sel = selectable.selectable;
+            var terminal = _pn_selectable_is_terminal(sel);
+            if (terminal) {
+                _pn_selectable_free(sel);
+                delete _selectables[fd];
+            } else {
+                var stream = FS.getStream(fd);
+                if (stream) {
+                    var sock = stream.node.sock;
+                    if (sock.sock_ops.poll) {
+                        var mask = sock.sock_ops.poll(sock); // Low-level poll call.
+                        if (mask) {
+                            var messenger = selectable.messenger;
+                            var capacity = _pn_selectable_capacity(sel) > 0;
+                            var pending = _pn_selectable_pending(sel) > 0;
+
+                            if ((mask & POLLIN) && capacity) {
+//console.log("- readable fd = " + fd + ", capacity = " + _pn_selectable_capacity(sel));
+                                _error = null; // May get set by _pn_selectable_readable.
+                                _pn_selectable_readable(sel);
+                                count++; // Should this be inside the test for _error? Don't know.
+                                var errno = messenger['getErrno']();
+                                _error = errno ? messenger['getError']() : _error;
+                                if (_error) {
+                                    _errorHandler([fd, 0, _error]);
+                                } else {
+                                    // Don't send work event if it's a listen socket.
+                                    if (!sock.server) {
+                                        messenger._checkSubscriptions();
+                                        messenger._emit('work');
+                                    }
+                                }
+                            }
+                            if ((mask & POLLOUT) && pending) {
+//console.log("- writeable fd = " + fd + ", pending = " + _pn_selectable_pending(sel));
+                                _pn_selectable_writable(sel);
+                                //TODO looks like this block isn't needed. Need to
+                                //check with a test-case that writes data as fast as
+                                //it can. If not needed then delete.
+                                /*
+                                count++;
+                                // Check _selectables again in case the call to
+                                // _pn_selectable_writable caused a socket close.
+                                if (_selectables[fd]) {
+                                    messenger._checkSubscriptions();
+                                    messenger._emit('work');
+                                }
+                                */
+                            }
+                        }
                     }
-//console.log("_pump while finish");
                 }
             }
         }
-//console.log("\t_pump exit");
+
+        return count;
     };
 
     /**
-     * Listener for the emscripten socket close event. Delegates to _pump()
-     * passing a flag to indicate that the socket is closing.
+     * Handler for the emscripten socket close event.
      */
-    var _close = function(fd) {
-//console.log("calling close fd = " + fd);
-        _pump(fd, true);
-        delete _fd2Messenger[fd];
+    var _closeHandler = function(fd) {
+        var selectable = _selectables[fd];
+        if (selectable) {
+            // Close and remove the selectable.
+            var sel = selectable.selectable;
+            _pn_selectable_free(sel); // This closes the underlying socket too.
+            delete _selectables[fd];
+
+            var messenger = selectable.messenger;
+            messenger._emit('work');
+        }
     };
 
-    var _error = function(error) {
+    /**
+     * Handler for the emscripten socket error event.
+     */
+    var _errorHandler = function(error) {
         var fd = error[0];
-        var messenger = _fd2Messenger[fd];
-        messenger._emit('error', new Module['MessengerError'](error[2]));
-        delete _fd2Messenger[fd];
+        var message = error[2];
+
+        _updateSelectables();
+
+        var selectable = _selectables[fd];
+        if (selectable) {
+            // Close and remove the selectable.
+            var sel = selectable.selectable;
+            _pn_selectable_free(sel); // This closes the underlying socket too.
+            delete _selectables[fd];
+
+            var messenger = selectable.messenger;
+
+            // Remove any pending Subscriptions whose fd matches the error fd.
+            var subscriptions = messenger._pendingSubscriptions;
+            for (var i = 0; i < subscriptions.length; i++) {
+                subscription = subscriptions[i];
+                // Use == not === as we don't care if fd is a number or a string.
+                if (subscription.fd == fd) {
+                    messenger._pendingSubscriptions.splice(i, 1);
+                    if (message.indexOf('EHOSTUNREACH:') === 0) {
+                        message = 'CONNECTION ERROR (' + subscription.source + '): bind: Address already in use';
+                    }
+                    messenger._emit('error', new Module['SubscriptionError'](subscription.source, message));
+                    return;
+                }
+            }
+
+            messenger._emit('error', new Module['MessengerError'](message));
+        }
     };
 
     /**
-     * This code cheekily replaces the library socket call with our own one.
-     * The real socket call returns a file descriptor so we harvest that and use
-     * that as a key to map file descriptors to their owning Messenger.
+     * Flush any data that has been written by the Messenger put() method.
+     * @method flush
      */
-    var realsocket = _socket;
-    _socket = function(domain, type, protocol) {
-        var fd = realsocket(domain, type, protocol);
-//console.log("calling socket fd = " + fd);
-        if (_currentMessenger) {
-            _fd2Messenger[fd] = _currentMessenger;
-        } else {
-            console.error("Error: file descriptor " + fd + " cannot be mapped to a Messenger.");
+    this.flush = function() {
+        _pump();
+    };
+
+    /**
+     * Subscribe to a specified source address.
+     * <p>
+     * This method is delegated to by the subscribe method of {@link proton.Messenger}.
+     * We delegate to EventDispatch because we create Subscription objects that
+     * contain some additional information (such as file descriptors) which are
+     * only available to EventDispatch and we don't really want to expose to the
+     * wider API. This low-level information is mainly used for error handling
+     * which is itself encapsulated in EventDispatch.
+     * @method subscribe
+     * @memberof! proton.EventDispatch#
+     * @param {proton.Messenger} messenger the Messenger instance that this
+     *        subscription relates to.
+     * @param {string} source the address that we'd like to subscribe to.
+     */
+    this.subscribe = function(messenger, source) {
+        // First update selectables before subscribing so we can work out the
+        // Subscription fd (which will be the listen file descriptor).
+        _updateSelectables();
+        var sp = Runtime.stackSave();
+        var subscription = _pn_messenger_subscribe(messenger._messenger,
+                                                   allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
+        Runtime.stackRestore(sp);
+        var fd = _updateSelectables();
+
+        subscription = new Subscription(subscription, source, fd);
+        messenger._pendingSubscriptions.push(subscription);
+
+        // For passive subscriptions emit a subscription event (almost) immediately,
+        // otherwise defer until the address has been resolved remotely.
+        if (subscription.passive) {
+            // We briefly delay the call to checkSubscriptions because it is possible
+            // for passive subscriptions to fail if another process is bound to the
+            // port specified in the subscription.
+            var check = function() {messenger._checkSubscriptions();};
+            setTimeout(check, 10);
         }
-        return fd;
-    }
 
-    this.setCurrentMessenger = function(messenger) {
-        _currentMessenger = messenger;
-    }
+        return subscription;
+    };
 
     /**
      * Register the specified Messenger as being interested in network events.
+     * @method registerMessenger
+     * @memberof! proton.EventDispatch#
+     * @param {proton.Messenger} messenger the Messenger instance we want to
+     *        register to receive network events.
      */
     this.registerMessenger = function(messenger) {
-        if (_firstCall) {
-            /**
-             * Initialises the emscripten network callback functions. This needs
-             * to be done the first time we call registerMessenger rather than
-             * when we create the Singleton because emscripten's socket filesystem
-             * has to be mounted before can listen for any of these events.
-             */
-            Module['websocket']['on']('open', _pump);
-            Module['websocket']['on']('connection', _pump);
-            Module['websocket']['on']('message', _pump);
-            Module['websocket']['on']('close', _close);
-            Module['websocket']['on']('error', _error);
-            _firstCall = false;
-        }
+        _initialise();
 
-        var name = messenger.getName();
+        var name = messenger['getName']();
         _messengers[name] = messenger;
+
+        // Set the Messenger "passive" as we are supplying our own event loop here.
+        _pn_messenger_set_passive(messenger._messenger, true);
     };
 
     /**
      * Unregister the specified Messenger from interest in network events.
+     * @method unregisterMessenger
+     * @memberof! proton.EventDispatch#
+     * @param {proton.Messenger} messenger the Messenger instance we want to
+     *        unregister from receiving network events.
      */
     this.unregisterMessenger = function(messenger) {
-        var name = messenger.getName();
+        var name = messenger['getName']();
         delete _messengers[name];
     };
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e8faa57e/proton-c/bindings/javascript/subscription.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/subscription.js b/proton-c/bindings/javascript/subscription.js
index 602a741..89fd1a3 100644
--- a/proton-c/bindings/javascript/subscription.js
+++ b/proton-c/bindings/javascript/subscription.js
@@ -32,11 +32,19 @@
  * constructor in the scope of the package and don't export it via Module.
  * @constructor Subscription
  * @param {number} subscription a pointer to the underlying subscription object.
- * @param {string} address if the address is already known it can be (optionally) specified.
+ * @param {string} source the address that we want to subscribe to.
+ * @param {number} fd the file descriptor associated with the subscription. This
+ *                 is used internally to tidy up during error handling.
  */
-var Subscription = function(subscription, address) { // Subscription Constructor.
+var Subscription = function(subscription, source, fd) { // Subscription Constructor.
     this._subscription = subscription;
-    this._address = address;
+    this.source = source;
+    this.fd = fd;
+    if (source.indexOf('~') !== -1) {
+        this.passive = true;
+    } else {
+        this.passive = false;
+    }
 };
 
 /**
@@ -65,8 +73,8 @@ Subscription.prototype['setContext'] = function(context) {
  * @returns the Subscription's Address.
  */
 Subscription.prototype['getAddress'] = function() {
-    if (this._address) {
-        return this._address;
+    if (this.passive) {
+        return this.source;
     }
     return Pointer_stringify(_pn_subscription_address(this._subscription));
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e8faa57e/proton-c/src/codec/data.h
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/data.h b/proton-c/src/codec/data.h
index a528d26..99e8228 100644
--- a/proton-c/src/codec/data.h
+++ b/proton-c/src/codec/data.h
@@ -61,7 +61,7 @@ struct pn_data_t {
   pni_nid_t base_current;
 };
 
-inline pni_node_t * pn_data_node(pn_data_t *data, pni_nid_t nd) 
+static inline pni_node_t * pn_data_node(pn_data_t *data, pni_nid_t nd) 
 {
   return nd ? (data->nodes + nd - 1) : NULL;
 }


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