You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2015/07/15 00:26:59 UTC

[3/3] qpid-proton git commit: PROTON-865: C++ binding tutorial in progress. Added public proton::url class.

PROTON-865: C++ binding tutorial in progress. Added public proton::url class.

WIP Tutorial starting point - to FIXME

WIP: tutorial in progress.

WIP: tutorial

WIP tutorial, direct_recv example, proton::url

WIP: tutorials working, unfinished.

WIP More examples, use url consistently.


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

Branch: refs/heads/cjansen-cpp-client
Commit: 52c90597783073582649034436299350310ed483
Parents: 976950d
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Jul 10 16:57:37 2015 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Jul 14 18:24:12 2015 -0400

----------------------------------------------------------------------
 examples/cpp/CMakeLists.txt                     |   2 +
 examples/cpp/README.md                          | 116 ++++--
 examples/cpp/README_dev.md                      |   9 -
 examples/cpp/broker.cpp                         |  12 +-
 examples/cpp/direct_recv.cpp                    | 117 ++++++
 examples/cpp/direct_send.cpp                    | 125 +++++++
 examples/cpp/example_test.py                    | 115 +++---
 examples/cpp/helloworld.cpp                     |  16 +-
 examples/cpp/helloworld_blocking.cpp            |   3 +-
 examples/cpp/helloworld_direct.cpp              |   8 +-
 examples/cpp/simple_recv.cpp                    |   4 +-
 examples/cpp/simple_send.cpp                    |   4 +-
 proton-c/bindings/cpp/docs/CMakeLists.txt       |   2 +
 proton-c/bindings/cpp/docs/mainpage.md          |  97 +++++
 proton-c/bindings/cpp/docs/tutorial.md          | 362 +++++++++++++++++++
 proton-c/bindings/cpp/docs/user.doxygen.in      |  22 +-
 .../bindings/cpp/include/proton/connection.hpp  |   2 +-
 .../bindings/cpp/include/proton/container.hpp   |  11 +-
 proton-c/bindings/cpp/include/proton/index.md   |   7 -
 .../bindings/cpp/include/proton/mainpage.hpp    |  14 -
 proton-c/bindings/cpp/include/proton/url.hpp    | 102 ++++++
 .../cpp/src/blocking_connection_impl.cpp        |   2 +-
 .../cpp/src/blocking_connection_impl.hpp        |   4 +-
 proton-c/bindings/cpp/src/connection_impl.hpp   |   2 +-
 proton-c/bindings/cpp/src/connector.cpp         |  23 +-
 proton-c/bindings/cpp/src/connector.hpp         |  11 +-
 proton-c/bindings/cpp/src/container.cpp         |  17 +-
 proton-c/bindings/cpp/src/container_impl.cpp    |  46 ++-
 proton-c/bindings/cpp/src/container_impl.hpp    |  10 +-
 proton-c/bindings/cpp/src/grep                  |   4 +-
 proton-c/bindings/cpp/src/url.cpp               |  93 +++--
 proton-c/bindings/cpp/src/url.hpp               |  48 ---
 32 files changed, 1126 insertions(+), 284 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
index 7dba5c5..fde4eee 100644
--- a/examples/cpp/CMakeLists.txt
+++ b/examples/cpp/CMakeLists.txt
@@ -28,6 +28,8 @@ foreach(example
     helloworld_direct
     simple_recv
     simple_send
+    direct_recv
+    direct_send
     encode_decode)
   add_executable(${example} ${example}.cpp)
   target_link_libraries(${example} qpid-proton-cpp)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/README.md
----------------------------------------------------------------------
diff --git a/examples/cpp/README.md b/examples/cpp/README.md
index 52b73e7..bd94b55 100644
--- a/examples/cpp/README.md
+++ b/examples/cpp/README.md
@@ -1,4 +1,5 @@
-# C++ examples
+C++ examples
+============
 
 Many of the examples expect a broker to be running on the standard AMQP
 port. You can use any broker that supports AMQP 1.0, or you can use the simple
@@ -7,32 +8,54 @@ running the other examples.
 
 If you use another broker you will need to create a queue named `examples`.
 
-## broker.cpp
+NOTE: Most of these examples are described in more detail as part of the \ref tutorial.
+
+Note on Brokers and URLs
+------------------------
+
+Some of the examples require an AMQP *broker* that can receive, store and send messages.
+
+There is a very simple broker included as an example (\ref broker.cpp) which you can use.
+Run it like this:
+
+    broker [URL]
+
+The default URL is "0.0.0.0:5672" which listens on the standard AMQP port on all
+network interfaces.
+
+Instead of the example broker, you can use any AMQP 1.0 compliant broker. You
+must configure your broker to have a queue or topic named "examples".
+
+Most of the examples take an optional URL argument, the simplest form is:
+
+    HOST:PORT/ADDRESS
+
+It usually defaults to `127.0.0.1:5672/examples`, but you can change this if
+your broker is on a different host or port, or you want to use a different queue
+or topic name (the ADDRESS part of the URL). URL details are at `proton::url`
+
+broker.cpp
+----------
 
 A very simple "mini broker". You can use this to run other examples that reqiure
 an intermediary, or you can use any AMQP 1.0 broker. This broker creates queues
 automatically when a client tries to send or subscribe.
 
-    $ ./broker
-    broker listening on :5672
+Source: \ref broker.cpp
 
-## helloworld.cpp
+helloworld.cpp
+--------------
 
-Basic example that connects to an intermediary on localhost:5672,
-establishes a subscription from the 'examples' node on that
+Basic example that connects to an intermediary on 127.0.0.1:5672,
+establishes a subscription from the 'examples' nodeu on that
 intermediary, then creates a sending link to the same node and sends
 one message. On receving the message back via the subcription, the
 connection is closed.
 
-## helloworld_blocking.cpp
-
-The same as the basic helloworld.cpp, but using a
-synchronous/sequential style wrapper on top of the
-asynchronous/reactive API. The purpose of this example is just to show
-how different functionality can be easily layered should it be
-desired.
+Source: \ref helloworld.cpp
 
-## helloworld_direct.cpp
+helloworld_direct.cpp
+---------------------
 
 A variant of the basic helloworld example, that does not use an
 intermediary, but listens for incoming connections itself. It
@@ -40,17 +63,68 @@ establishes a connection to itself with a link over which a single
 message is sent. This demonstrates the ease with which a simple daemon
 can be built using the API.
 
-## simple_send.cpp
+Source: \ref helloworld_direct.cpp
+
+helloworld_blocking.cpp
+-----------------------
+
+The same as the basic helloworld.cpp, but using a
+synchronous/sequential style wrapper on top of the
+asynchronous/reactive API. The purpose of this example is just to show
+how different functionality can be easily layered should it be
+desired.
+
+Source: \ref helloworld_blocking.cpp
+
+simple_send.cpp
+---------------
 
 An example of sending a fixed number of messages and tracking their
 (asynchronous) acknowledgement. Messages are sent through the 'examples' node on
-an intermediary accessible on port 5672 on localhost.
+an intermediary accessible on 127.0.0.1:5672.
+
+Source: \ref simple_send.cpp
 
-# simple_recv.cpp
+simple_recv.cpp
+---------------
 
-Subscribes to the 'examples' node on an intermediary accessible on port 5672 on
-localhost. Simply prints out the body of received messages.
+Subscribes to the 'examples' node on an intermediary accessible
+on 127.0.0.1:5672. Simply prints out the body of received messages.
 
-## encode_decode.cpp
+Source: \ref simple_recv.cpp
+
+direct_send.cpp
+---------------
+
+Accepts an incoming connection and then sends like `simple_send`.  You can
+connect directly to `direct_send` *without* a broker using \ref simple_recv.cpp.
+Make sure to stop the broker first or use a different port for `direct_send`.
+
+Source: \ref direct_send.cpp
+
+direct_recv.cpp
+---------------
+
+Accepts an incoming connection and then receives like `simple_recv`.  You can
+connect directly to `direct_recv` *without* a broker using \ref simple_send.cpp.
+Make sure to stop the broker first or use a different port for `direct_recv`.
+
+Source: \ref direct_recv.cpp
+
+encode_decode.cpp
+-----------------
 
 Shows how C++ data types can be converted to and from AMQP types.
+
+Source: \ref encode_decode.cpp
+
+    <!-- For generated doxygen docmentation. Note \ref tags above are also for doxygen -->
+    \example helloworld.cpp
+    \example helloworld_direct.cpp
+    \example helloworld_blocking.cpp
+    \example broker.cpp
+    \example encode_decode.cpp
+    \example simple_recv.cpp
+    \example simple_send.cpp
+    \example direct_recv.cpp
+    \example direct_send.cpp

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/README_dev.md
----------------------------------------------------------------------
diff --git a/examples/cpp/README_dev.md b/examples/cpp/README_dev.md
deleted file mode 100644
index 0b23a2f..0000000
--- a/examples/cpp/README_dev.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Notes for example developers
-
-Use the C++ std library/boost conventions. File names are (*.hpp, *.cpp) and
-identifiers are lowercase_underscore names not CamelCase.
-
-No "using namespace proton" in examples. This is not a general rule, but for
-_example_ code the explicit `proton::` qualifier makes it easier to see what is
-part of the proton library vs. standard library or code that is just part of the
-example.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index cd5eb54..86f5b89 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -21,6 +21,7 @@
 
 #include "proton/container.hpp"
 #include "proton/messaging_handler.hpp"
+#include "proton/url.hpp"
 
 #include <iostream>
 #include <sstream>
@@ -84,13 +85,13 @@ class queue {
 class broker : public proton::messaging_handler {
   private:
     typedef std::map<std::string, queue *> queue_map;
-    std::string url;
+    proton::url url;
     queue_map queues;
     uint64_t queue_count;       // Use to generate unique queue IDs.
 
   public:
 
-    broker(const std::string &s) : url(s), queue_count(0) {}
+    broker(const proton::url &u) : url(u), queue_count(0) {}
 
     void on_start(proton::event &e) {
         e.container().listen(url);
@@ -125,12 +126,14 @@ class broker : public proton::messaging_handler {
                 queue *q = new queue(true);
                 queues[address] = q;
                 q->subscribe(sender);
+                std::cout << "broker dynamic outgoing link from " << address << std::endl;
             }
             else {
                 std::string address = remote_source.address();
                 if (!address.empty()) {
                     lnk.source().address(address);
                     get_queue(address).subscribe(sender);
+                    std::cout << "broker outgoing link from " << address << std::endl;
                 }
             }
         }
@@ -138,6 +141,7 @@ class broker : public proton::messaging_handler {
             std::string address = lnk.remote_target().address();
             if (!address.empty())
                 lnk.target().address(address);
+            std::cout << "broker incoming link to " << address << std::endl;
         }
     }
 
@@ -192,9 +196,9 @@ class broker : public proton::messaging_handler {
 };
 
 int main(int argc, char **argv) {
-    std::string url = argc > 1 ? argv[1] : ":5672";
-    broker broker(url);
     try {
+        std::string url(argc > 1 ? argv[1] : "0.0.0.0");
+        broker broker(url);
         proton::container(broker).run();
     } catch (const std::exception& e) {
         std::cerr << e.what() << std::endl;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/direct_recv.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/direct_recv.cpp b/examples/cpp/direct_recv.cpp
new file mode 100644
index 0000000..5c8c808
--- /dev/null
+++ b/examples/cpp/direct_recv.cpp
@@ -0,0 +1,117 @@
+/*
+ *
+ * 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/container.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/link.hpp"
+#include "proton/url.hpp"
+
+#include <iostream>
+#include <map>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+
+class direct_recv : public proton::messaging_handler {
+  private:
+    proton::url url;
+    int expected;
+    int received;
+    proton::acceptor acceptor;
+
+  public:
+    direct_recv(const std::string &s, int c) : url(s), expected(c), received(0) {}
+
+    void on_start(proton::event &e) {
+        acceptor = e.container().listen(url);
+        std::cout << "direct_recv listening on " << url << std::endl;
+    }
+
+    void on_message(proton::event &e) {
+        proton::message msg = e.message();
+        proton::value id = msg.id();
+        if (id.type() == proton::ULONG) {
+            if (id.get<int>() < received)
+                return; // ignore duplicate
+        }
+        if (expected == 0 || received < expected) {
+            std::cout << msg.body() << std::endl;
+            received++;
+        }
+        if (received == expected) {
+            e.receiver().close();
+            e.connection().close();
+            if (acceptor) acceptor.close();
+        }
+    }
+};
+
+static void parse_options(int argc, char **argv, int &count, std::string &addr);
+
+int main(int argc, char **argv) {
+    try {
+        int message_count = 100;
+        std::string address("127.0.0.1:5672/examples");
+        parse_options(argc, argv, message_count, address);
+        direct_recv recv(address, message_count);
+        proton::container(recv).run();
+    } catch (const std::exception& e) {
+        std::cerr << e.what() << std::endl;
+        return 1;
+    }
+}
+
+
+static void usage() {
+    std::cout << "Usage: direct_recv -m message_count -a address:" << std::endl;
+    exit (1);
+}
+
+
+static void parse_options(int argc, char **argv, int &count, std::string &addr) {
+    int c, i;
+    for (i = 1; i < argc; i++) {
+        if (strlen(argv[i]) == 2 && argv[i][0] == '-') {
+            c = argv[i][1];
+            const char *nextarg = i < argc ? argv[i+1] : NULL;
+
+            switch (c) {
+            case 'a':
+                if (!nextarg) usage();
+                addr = nextarg;
+                i++;
+                break;
+            case 'm':
+                if (!nextarg) usage();
+                unsigned newc;
+                if (sscanf( nextarg, "%d", &newc) != 1) usage();
+                count = newc;
+                i++;
+                break;
+            default:
+                usage();
+            }
+        }
+        else usage();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/direct_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/direct_send.cpp b/examples/cpp/direct_send.cpp
new file mode 100644
index 0000000..9ffa28a
--- /dev/null
+++ b/examples/cpp/direct_send.cpp
@@ -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.
+ *
+ */
+
+#include "proton/container.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/connection.hpp"
+
+#include <iostream>
+#include <map>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+
+class simple_send : public proton::messaging_handler {
+  private:
+    proton::url url;
+    int sent;
+    int confirmed;
+    int total;
+    proton::acceptor acceptor;
+  public:
+
+    simple_send(const std::string &s, int c) : url(s), sent(0), confirmed(0), total(c) {}
+
+    void on_start(proton::event &e) {
+        acceptor = e.container().listen(url);
+        std::cout << "direct_send listening on " << url << std::endl;
+    }
+
+    void on_sendable(proton::event &e) {
+        proton::sender sender = e.sender();
+        while (sender.credit() && sent < total) {
+            proton::message msg;
+            msg.id(proton::value(sent + 1));
+            std::map<std::string, int> m;
+            m["sequence"] = sent+1;
+            msg.body(proton::as<proton::MAP>(m));
+            sender.send(msg);
+            sent++;
+        }
+    }
+
+    void on_accepted(proton::event &e) {
+        confirmed++;
+        if (confirmed == total) {
+            std::cout << "all messages confirmed" << std::endl;
+            e.connection().close();
+            acceptor.close();
+        }
+    }
+
+    void on_disconnected(proton::event &e) {
+        sent = confirmed;
+    }
+};
+
+static void parse_options(int argc, char **argv, int &count, std::string &addr);
+
+int main(int argc, char **argv) {
+    try {
+        int message_count = 100;
+        std::string address("127.0.0.1:5672/examples");
+        parse_options(argc, argv, message_count, address);
+        simple_send send(address, message_count);
+        proton::container(send).run();
+    } catch (const std::exception& e) {
+        std::cerr << e.what() << std::endl;
+        return 1;
+    }
+}
+
+
+static void usage() {
+    std::cout << "Usage: simple_send -m message_count -a address:" << std::endl;
+    exit (1);
+}
+
+
+static void parse_options(int argc, char **argv, int &count, std::string &addr) {
+    int c, i;
+    for (i = 1; i < argc; i++) {
+        if (strlen(argv[i]) == 2 && argv[i][0] == '-') {
+            c = argv[i][1];
+            const char *nextarg = i < argc ? argv[i+1] : NULL;
+
+            switch (c) {
+            case 'a':
+                if (!nextarg) usage();
+                addr = nextarg;
+                i++;
+                break;
+            case 'm':
+                if (!nextarg) usage();
+                unsigned newc;
+                if (sscanf( nextarg, "%d", &newc) != 1) usage();
+                count = newc;
+                i++;
+                break;
+            default:
+                usage();
+            }
+        }
+        else usage();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 03c5b49..b2110f6 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -28,29 +28,55 @@ import platform
 def exe_name(name):
     if platform.system() == "Windows":
         return name + ".exe"
-    return name
+    return "./" + name
 
-def execute(*args):
-    """Run executable and return its output"""
+def background(*args):
+    """Run executable in the backround, return the popen"""
     args = [exe_name(args[0])]+list(args[1:])
+    p = Popen(args, stdout=PIPE, stderr=STDOUT)
+    p.args = args               # Save arguments for debugging output
+    return p
+
+def verify(p):
+    """Wait for executable to exit and verify status."""
     try:
-        p = Popen(args, stdout=PIPE, stderr=STDOUT)
         out, err = p.communicate()
     except Exception as e:
-        raise Exception("Error running %s: %s", args, e)
+        raise Exception("Error running %s: %s", p.args, e)
     if p.returncode:
         raise Exception("""%s exit code %s
 vvvvvvvvvvvvvvvv
 %s
 ^^^^^^^^^^^^^^^^
-""" % (args[0], p.returncode, out))
+""" % (p.args, p.returncode, out))
     if platform.system() == "Windows":
         # Just \n please
         out = out.translate(None, '\r')
     return out
 
+def execute(*args):
+    return verify(background(*args))
+
 NULL = open(os.devnull, 'w')
 
+def wait_addr(addr, timeout=10):
+    """Wait up to timeout for something to listen on port"""
+    deadline = time.time() + timeout
+    while time.time() < deadline:
+        try:
+            c = socket.create_connection(addr.split(":"), deadline - time.time())
+            c.close()
+            return
+        except socket.error as e:
+            time.sleep(0.01)
+    raise Exception("Timed out waiting for %s", addr)
+
+def pick_addr():
+    """Pick a new host:port address."""
+    # FIXME aconway 2015-07-14: need a safer way to pick ports.
+    p =  randrange(10000, 20000)
+    return "127.0.0.1:%s" % p
+
 class Broker(object):
     """Run the test broker"""
 
@@ -62,31 +88,19 @@ class Broker(object):
 
     @classmethod
     def stop(cls):
-        if cls._broker and cls._broker.process:
+        if cls.get() and cls._broker.process:
             cls._broker.process.kill()
             cls._broker = None
 
     def __init__(self):
-        self.port = randrange(10000, 20000)
-        self.addr = ":%s" % self.port
+        self.addr = pick_addr()
         cmd = [exe_name("broker"), self.addr]
         try:
             self.process = Popen(cmd, stdout=NULL, stderr=NULL)
+            wait_addr(self.addr)
+            self.addr += "/examples"
         except Exception as e:
             raise Exception("Error running %s: %s", cmd, e)
-        # Wait 10 secs for broker to listen
-        deadline = time.time() + 10
-        c = None
-        while time.time() < deadline:
-            try:
-                c = socket.create_connection(("127.0.0.1", self.port), deadline - time.time())
-                break
-            except socket.error as e:
-                time.sleep(0.01)
-        if c is None:
-            raise Exception("Timed out waiting for broker")
-        c.close()
-
 
 class ExampleTest(unittest.TestCase):
     """Run the examples, verify they behave as expected."""
@@ -98,41 +112,54 @@ class ExampleTest(unittest.TestCase):
     def test_helloworld(self):
         b = Broker.get()
         hw = execute("helloworld", b.addr)
-        self.assertEqual("Hello World!\n", hw)
+        self.assertEqual('"Hello World!"\n', hw)
 
     def test_helloworld_blocking(self):
         b = Broker.get()
-        hw = execute("helloworld_blocking", b.addr)
-        self.assertEqual("Hello World!\n", hw)
+        hw = execute("helloworld_blocking", b.addr, b.addr)
+        self.assertEqual('"Hello World!"\n', hw)
 
     def test_helloworld_direct(self):
-        url = ":%s/examples" % randrange(10000, 20000)
-        hw = execute("helloworld_direct", url)
-        self.assertEqual("Hello World!\n", hw)
+        addr = pick_addr()
+        hw = execute("helloworld_direct", addr)
+        self.assertEqual('"Hello World!"\n', hw)
 
     def test_simple_send_recv(self):
         b = Broker.get()
-        n = 5
-        send = execute("simple_send", "-a", b.addr, "-m", str(n))
+        send = execute("simple_send", "-a", b.addr)
         self.assertEqual("all messages confirmed\n", send)
-        recv = execute("simple_recv", "-a", b.addr, "-m", str(n))
-        recv_expect = "simple_recv listening on %s\n" % (b.addr)
-        recv_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(n)])
+        recv = execute("simple_recv", "-a", b.addr)
+        recv_expect = "simple_recv listening on amqp://%s\n" % (b.addr)
+        recv_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
         self.assertEqual(recv_expect, recv)
 
-        # FIXME aconway 2015-06-16: bug when receiver is started before sender, messages
-        # are not delivered to receiver.
-    def FIXME_test_simple_recv_send(self):
+    def test_simple_send_direct_recv(self):
+        addr = pick_addr()
+        recv = background("direct_recv", "-a", addr)
+        wait_addr(addr)
+        self.assertEqual("all messages confirmed\n", execute("simple_send", "-a", addr))
+        recv_expect = "direct_recv listening on amqp://%s\n" % (addr)
+        recv_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
+        self.assertEqual(recv_expect, verify(recv))
+
+    def test_simple_recv_direct_send(self):
+        addr = pick_addr()
+        send = background("direct_send", "-a", addr)
+        wait_addr(addr)
+        recv_expect = "simple_recv listening on amqp://%s\n" % (addr)
+        recv_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
+        self.assertEqual(recv_expect, execute("simple_recv", "-a", addr))
+        send_expect = "direct_send listening on amqp://%s\nall messages confirmed\n" % (addr)
+        self.assertEqual(send_expect, verify(send))
+
+    def test_simple_recv_send(self):
         """Start receiver first, then run sender"""
         b = Broker.get()
-        n = 5
-        recv = Popen(["simple_recv", "-a", b.addr, "-m", str(n)], stdout=PIPE)
-        self.assertEqual("simple_recv listening on %s\n" % (b.addr), recv.stdout.readline())
-        send = execute("simple_send", "-a", b.addr, "-m", str(n))
-        self.assertEqual("all messages confirmed\n", send)
-        recv_expect = "".join(['[%d]: b"some arbitrary binary data"\n' % (i+1) for i in range(n)])
-        out, err = recv.communicate()
-        self.assertEqual(recv_expect, out)
+        recv = background("simple_recv", "-a", b.addr)
+        self.assertEqual("all messages confirmed\n", execute("simple_send", "-a", b.addr))
+        recv_expect = "simple_recv listening on amqp://%s\n" % (b.addr)
+        recv_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
+        self.assertEqual(recv_expect, verify(recv))
 
     def test_encode_decode(self):
         expect="""

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/helloworld.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/helloworld.cpp b/examples/cpp/helloworld.cpp
index c00ec8e..13bdbc7 100644
--- a/examples/cpp/helloworld.cpp
+++ b/examples/cpp/helloworld.cpp
@@ -21,16 +21,17 @@
 
 #include "proton/container.hpp"
 #include "proton/messaging_handler.hpp"
+#include "proton/url.hpp"
 
 #include <iostream>
 
 class hello_world : public proton::messaging_handler {
   private:
-    std::string server;
+    proton::url server;
     std::string address;
   public:
 
-    hello_world(const std::string &s, const std::string &addr) : server(s), address(addr) {}
+    hello_world(const proton::url &url) : server(url), address(url.path()) {}
 
     void on_start(proton::event &e) {
         proton::connection conn = e.container().connect(server);
@@ -46,19 +47,16 @@ class hello_world : public proton::messaging_handler {
     }
 
     void on_message(proton::event &e) {
-        std::string s;
-        proton::value v(e.message().body());
-        std::cout << v.get<std::string>() << std::endl;
+        proton::value body(e.message().body());
+        std::cout << body << std::endl;
         e.connection().close();
     }
-
 };
 
 int main(int argc, char **argv) {
     try {
-        std::string server = argc > 1 ? argv[1] : ":5672";
-        std::string addr = argc > 2 ? argv[2] : "examples";
-        hello_world hw(server, addr);
+        std::string url = argc > 1 ? argv[1] : "127.0.0.1:5672/examples";
+        hello_world hw(url);
         proton::container(hw).run();
     } catch (const std::exception& e) {
         std::cerr << e.what() << std::endl;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/helloworld_blocking.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/helloworld_blocking.cpp b/examples/cpp/helloworld_blocking.cpp
index e08e93d..ff14320 100644
--- a/examples/cpp/helloworld_blocking.cpp
+++ b/examples/cpp/helloworld_blocking.cpp
@@ -39,8 +39,7 @@ class hello_world_blocking : public proton::messaging_handler {
     }
 
     void on_message(proton::event &e) {
-        proton::value v(e.message().body());
-        std::cout << v.get<std::string>() << std::endl;
+        std::cout << e.message().body() << std::endl;
         e.connection().close();
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/helloworld_direct.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/helloworld_direct.cpp b/examples/cpp/helloworld_direct.cpp
index 1d87037..d81d2b7 100644
--- a/examples/cpp/helloworld_direct.cpp
+++ b/examples/cpp/helloworld_direct.cpp
@@ -25,12 +25,9 @@
 //#include "proton/acceptor.hpp"
 #include <iostream>
 
-
-
-
 class hello_world_direct : public proton::messaging_handler {
   private:
-    std::string url_;
+    proton::url url_;
     proton::acceptor acceptor_;
   public:
 
@@ -49,8 +46,7 @@ class hello_world_direct : public proton::messaging_handler {
     }
 
     void on_message(proton::event &e) {
-        proton::value v(e.message().body());
-        std::cout << v.get<std::string>() << std::endl;
+        std::cout << e.message().body() << std::endl;
     }
 
     void on_accepted(proton::event &e) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/simple_recv.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_recv.cpp b/examples/cpp/simple_recv.cpp
index 806d928..8cc8bc4 100644
--- a/examples/cpp/simple_recv.cpp
+++ b/examples/cpp/simple_recv.cpp
@@ -33,7 +33,7 @@
 
 class simple_recv : public proton::messaging_handler {
   private:
-    std::string url;
+    proton::url url;
     int expected;
     int received;
   public:
@@ -68,7 +68,7 @@ static void parse_options(int argc, char **argv, int &count, std::string &addr);
 int main(int argc, char **argv) {
     try {
         int message_count = 100;
-        std::string address("localhost:5672/examples");
+        std::string address("127.0.0.1:5672/examples");
         parse_options(argc, argv, message_count, address);
         simple_recv recv(address, message_count);
         proton::container(recv).run();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/examples/cpp/simple_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_send.cpp b/examples/cpp/simple_send.cpp
index 703561c..0cf4cd3 100644
--- a/examples/cpp/simple_send.cpp
+++ b/examples/cpp/simple_send.cpp
@@ -33,7 +33,7 @@
 
 class simple_send : public proton::messaging_handler {
   private:
-    std::string url;
+    proton::url url;
     int sent;
     int confirmed;
     int total;
@@ -76,7 +76,7 @@ static void parse_options(int argc, char **argv, int &count, std::string &addr);
 int main(int argc, char **argv) {
     try {
         int message_count = 100;
-        std::string address("localhost:5672/examples");
+        std::string address("127.0.0.1:5672/examples");
         parse_options(argc, argv, message_count, address);
         simple_send send(address, message_count);
         proton::container(send).run();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/docs/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/docs/CMakeLists.txt b/proton-c/bindings/cpp/docs/CMakeLists.txt
index 7dbc9df..9c2d0d4 100644
--- a/proton-c/bindings/cpp/docs/CMakeLists.txt
+++ b/proton-c/bindings/cpp/docs/CMakeLists.txt
@@ -29,3 +29,5 @@ if (DOXYGEN_FOUND)
            COMPONENT documentation
            ${OPTIONAL_ARG})
 endif (DOXYGEN_FOUND)
+
+set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES html)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/docs/mainpage.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/docs/mainpage.md b/proton-c/bindings/cpp/docs/mainpage.md
new file mode 100644
index 0000000..3e3cd43
--- /dev/null
+++ b/proton-c/bindings/cpp/docs/mainpage.md
@@ -0,0 +1,97 @@
+Introduction     {#mainpage}
+============
+
+This is the C++ API for the proton AMQP protocol engine. It allows you to write
+client and server applications that send and receive AMQP messages.
+
+The best way to start is with the \ref tutorial "tutorial".
+
+An overview of the model
+------------------------
+
+Messages are transferred between connected peers over 'links'. At the
+sending peer the link is called a sender. At the receiving peer it is
+called a receiver. Messages are sent by senders and received by
+receivers. Links may have named 'source' and 'target' addresses (for
+example to identify the queue from which message were to be received
+or to which they were to be sent).
+
+Links are established over sessions. Sessions are established over
+connections. Connections are (generally) established between two
+uniquely identified containers. Though a connection can have multiple
+sessions, often this is not needed. The container API allows you to
+ignore sessions unless you actually require them.
+
+The sending of a message over a link is called a delivery. The message
+is the content sent, including all meta-data such as headers and
+annotations. The delivery is the protocol exchange associated with the
+transfer of that content.
+
+To indicate that a delivery is complete, either the sender or the
+receiver 'settles' it. When the other side learns that it has been
+settled, they will no longer communicate about that delivery. The
+receiver can also indicate whether they accept or reject the
+message.
+
+Three different delivery levels or 'guarantees' can be achieved: at-most-once,
+at-least-once or exactly-once. See below for details.
+
+Commonly used classes
+---------------------
+
+A brief summary of some of the key classes follows.
+
+The `proton::container` class is a convenient entry point into the API, allowing
+connections and links to be established. Applications are structured as one or
+more event handlers.
+
+The easiest way to implement a handler is to define a subclass of
+`proton::messaging_handler` and over-ride the event handling member functions
+that interest you.
+
+To send messages, call `proton::container::create_sender()` to create a
+`proton::sender` and then call `proton::sender::send()`. This is typically done
+when the sender is *sendable*, a condition indicated by the
+`proton::messaging_handler::on_sendable()` event, to avoid execessive build up
+of messages.
+
+To receive messages, call `proton::container::create_receiver()` to create a
+`proton::receiver`.  When messages are recieved the
+`proton::messaging_handler::on_message()` event handler function will be called.
+
+Other key classes:
+
+- proton::message represents an AMQP message, which has a body, headers and other properties.
+- proton::connection represents a connection to a remote AMQP endpoint.
+- proton::delivery holds the delivery status of a message.
+- proton::event carries details of an event.
+
+The library provides intuitive default conversions between AMQP and C++ types
+for message data q, but also allows detailed examination and construction of
+complex AMQP types. For details on converting between AMQP and C++ data types
+see the \ref encode_decode.cpp example and classes `proton::encoder`,
+`proton::decoder` and `proton::value`.
+
+Delivery Guarantees
+-------------------
+
+For *at-most-once*, the sender settles the message as soon as it sends
+it. If the connection is lost before the message is received by the
+receiver, the message will not be delivered.
+
+For *at-least-once*, the receiver accepts and settles the message on
+receipt. If the connection is lost before the sender is informed of
+the settlement, then the delivery is considered in-doubt and should be
+retried. This will ensure it eventually gets delivered (provided of
+course the connection and link can be reestablished). It may mean that
+it is delivered multiple times though.
+
+Finally, for *exactly-once*, the receiver accepts the message but
+doesn't settle it. The sender settles once it is aware that the
+receiver accepted it. In this way the receiver retains knowledge of an
+accepted message until it is sure the sender knows it has been
+accepted. If the connection is lost before settlement, the receiver
+informs the sender of all the unsettled deliveries it knows about, and
+from this the sender can deduce which need to be redelivered. The
+sender likewise informs the receiver which deliveries it knows about,
+from which the receiver can deduce which have already been settled.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/docs/tutorial.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/docs/tutorial.md b/proton-c/bindings/cpp/docs/tutorial.md
new file mode 100644
index 0000000..91c3c91
--- /dev/null
+++ b/proton-c/bindings/cpp/docs/tutorial.md
@@ -0,0 +1,362 @@
+Tutorial {#tutorial}
+========
+
+This is a brief tutorial that will walk you through the fundamentals of building
+messaging applications in incremental steps. There are further examples, in
+addition the ones mentioned in the tutorial.
+
+Note on Brokers and URLs
+------------------------
+
+Some of the examples require an AMQP *broker* that can receive, store and send messages.
+
+There is a very simple broker included as an example (\ref broker.cpp) which you can use.
+Run it like this:
+
+    broker [URL]
+
+The default URL is "0.0.0.0:5672" which listens on the standard AMQP port on all
+network interfaces.
+
+Instead of the example broker, you can use any AMQP 1.0 compliant broker. You
+must configure your broker to have a queue (or topic) named "examples".
+
+Most of the examples take an optional URL argument, the simplest form is:
+
+    HOST:PORT/ADDRESS
+
+It usually defaults to `127.0.0.1:5672/examples`, but you can change this if
+your broker is on a different host or port, or you want to use a different queue
+or topic name (the ADDRESS part of the URL). URL details are at `proton::url`
+
+Hello World!
+------------
+
+\dontinclude helloworld.cpp
+
+Tradition dictates that we start with hello world! This example sends a message
+to a broker and the receives the same message back to demonstrate sending and
+receiving. In a realistic system the sender and receiver would normally be in
+different processes. The complete example is \ref helloworld.cpp
+
+We will include the following classes: `proton::container` runs an event loop
+which dispatches events to a `proton::messaging_handler`. This allows a
+*reactive* style of programming which is well suited to messaging
+applications. `proton::url` is a simple parser for the URL format described
+above.
+
+\skip   proton/container
+\until  proton/url
+
+We will define a class `hello_world` which is a subclass of
+`proton::messaging_handler` and over-rides functions to handle the events
+of interest in sending and receiving a message.
+
+\skip class hello_world
+\until {}
+
+`on_start()` is called when the event loop first starts. We handle that by
+establishing a connection and creating a sender and a receiver.
+
+\skip on_start
+\until }
+
+`on_sendable()` is called when message can be transferred over the associated
+sender link to the remote peer. We create a `proton::message`, set the message
+body to `"Hello World!"` and send the message. Then we close the sender as we only
+want to send one message. Closing the sender will prevent further calls to
+`on_sendable()`.
+
+\skip on_sendable
+\until }
+
+`on_message()` is called when a message is received. We just print the body of
+the message and close the connection, as we only want one message
+
+\skip on_message
+\until }
+
+The message body is a `proton::value`, see the documentation for more on how to
+extract the message body as type-safe C++ values.
+
+Our `main` function creates an instance of the `hello_world` handler and a
+proton::container using that handler. Calling `proton::container::run` sets
+things in motion and returns when we close the connection as there is nothing
+further to do. It may throw an exception, which will be a subclass of
+`proton::error`. That in turn is a subclass of `std::exception`.
+
+\skip main
+\until }
+\until }
+\until }
+
+Hello World, Direct!
+--------------------
+
+\dontinclude helloworld_direct.cpp
+
+Though often used in conjunction with a broker, AMQP does not *require* this. It
+also allows senders and receivers can communicate directly if desired.
+
+We will modify our example to send a message directly to itself. This is a bit
+contrived but illustrates both sides of the direct send/receive scenario. Full
+code at \ref helloworld_direct.cpp
+
+The first difference, is that rather than creating a receiver on the same
+connection as our sender, we listen for incoming connections by invoking the
+`proton::container::listen()` method on the container.
+
+\skip on_start
+\until }
+
+As we only need then to initiate one link, the sender, we can do that by
+passing in a url rather than an existing connection, and the connection
+will also be automatically established for us.
+
+We send the message in response to the `on_sendable()` callback and
+print the message out in response to the `on_message()` callback exactly
+as before.
+
+\skip on_sendable
+\until }
+\until }
+
+However we also handle two new events. We now close the connection from
+the senders side once the message has been accepted.
+The acceptance of the message is an indication of successful transfer to the
+peer. We are notified of that event through the `on_accepted()`
+callback.
+
+\skip on_accepted
+\until }
+
+Then, once the connection has been closed, of which we are
+notified through the `on_closed()` callback, we stop accepting incoming
+connections at which point there is no work to be done and the
+event loop exits, and the run() method will return.
+
+\skip on_closed
+\until }
+
+So now we have our example working without a broker involved!
+
+Asynchronous Send and Receive
+-----------------------------
+
+Of course, these `HelloWorld!` examples are very artificial, communicating as
+they do over a network connection but with the same process. A more realistic
+example involves communication between separate processes (which could indeed be
+running on completely separate machines).
+
+Let's separate the sender from the receiver, and transfer more than a single
+message between them.
+
+We'll start with a simple sender \ref simple_send.cpp.
+
+\dontinclude simple_send.cpp
+
+As with the previous example, we define the application logic in a class that
+handles events. Because we are transferring more than one message, we need to
+keep track of how many we have sent. We'll use a `sent` member variable for
+that.  The `total` member variable will hold the number of messages we want to
+send.
+
+\skip class simple_send
+\until total
+
+As before, we use the `on_start()` event to establish our sender link over which
+we will transfer messages.
+
+\skip on_start
+\until }
+
+AMQP defines a credit-based flow control mechanism. Flow control allows
+the receiver to control how many messages it is prepared to receive at a
+given time and thus prevents any component being overwhelmed by the
+number of messages it is sent.
+
+In the `on_sendable()` callback, we check that our sender has credit
+before sending messages. We also check that we haven't already sent the
+required number of messages.
+
+\skip on_sendable
+\until }
+\until }
+
+The `proton::sender::send()` call above is asynchronous. When it returns the
+message has not yet actually been transferred across the network to the
+receiver. By handling the `on_accepted()` event, we can get notified when the
+receiver has received and accepted the message. In our example we use this event
+to track the confirmation of the messages we have sent. We only close the
+connection and exit when the receiver has received all the messages we wanted to
+send.
+
+\skip on_accepted
+\until }
+\until }
+
+If we are disconnected after a message is sent and before it has been
+confirmed by the receiver, it is said to be `in doubt`. We don't know
+whether or not it was received. In this example, we will handle that by
+resending any in-doubt messages. This is known as an 'at-least-once'
+guarantee, since each message should eventually be received at least
+once, though a given message may be received more than once (i.e.
+duplicates are possible). In the `on_disconnected()` callback, we reset
+the sent count to reflect only those that have been confirmed. The
+library will automatically try to reconnect for us, and when our sender
+is sendable again, we can restart from the point we know the receiver
+got to.
+
+\skip on_disconnected
+\until }
+
+\dontinclude simple_recv.cpp
+
+Now let's look at the corresponding receiver \ref simple_recv.cpp:
+
+This time we'll use an `expected` member variable for for the number of messages we expecct and
+a `received` variable to count how many we have received so far.send.
+
+\skip class simple_recv
+\until received
+
+We handle `on_start()` by creating our receiver, much like we
+did for the sender.
+
+\skip on_start
+\until }
+
+We also handle the `on_message()` event for received messages and print the
+message out as in the `Hello World!` examples.  However we add some logic to
+allow the receiver to wait for a given number of messages, then to close the
+connection and exit. We also add some logic to check for and ignore duplicates,
+using a simple sequential id scheme.
+
+\skip on_message
+\until }
+
+Direct Send and Receive
+-----------------------
+
+Sending between these two examples requires an intermediary broker since neither
+accepts incoming connections. AMQP allows us to send messages directly between
+two processes. In that case one or other of the processes needs to accept
+incoming connections. Let's create a modified version of the receiving example
+that does this with \ref direct_recv.cpp
+
+\dontinclude direct_recv.cpp
+
+There are only two differences here. Instead of initiating a link (and
+implicitly a connection), we listen for incoming connections.
+
+
+\skip on_start
+\until }
+
+When we have received all the expected messages, we then stop listening for
+incoming connections by closing the acceptor object.
+
+\skip on_message
+\until }
+\until }
+\until }
+\until }
+
+You can use the \ref simple_send.cpp example to send to this receiver
+directly. (Note: you will need to stop any broker that is listening on the 5672
+port, or else change the port used by specifying a different address to each
+example via the -a command line switch).
+
+We can also modify the sender to allow the original receiver to connect to it,
+in \ref direct_send.cpp. Again that just requires two modifications:
+
+\dontinclude direct_send.cpp
+
+As with the modified receiver, instead of initiating establishment of a
+link, we listen for incoming connections.
+
+\skip on_start
+\until }
+
+When we have received confirmation of all the messages we sent, we can
+close the acceptor in order to exit.
+
+\skip on_accepted
+\until }
+\until }
+
+To try this modified sender, run the original \ref simple_recv.cpp against it.
+
+The symmetry in the underlying AMQP that enables this is quite unique and
+elegant, and in reflecting this the proton API provides a flexible toolkit for
+implementing all sorts of interesting intermediaries (\ref broker.cpp provided
+as a simple broker for testing purposes is an example of this).
+
+Request/Response
+----------------
+
+\todo FIXME missing example in C++
+
+A common pattern is to send a request message and expect a response message in
+return. AMQP has special support for this pattern. Let's have a look at a simple
+example. We'll start with \ref server.cpp, the program that will process the
+request and send the response. Note that we are still using a broker in this
+example.
+
+\todo FIXME insert server snips
+
+Our server will provide a very simple service: it will respond with the
+body of the request converted to uppercase.
+
+The code here is not too different from the simple receiver example.  When we
+receive a request however, we look at the proton::message::reply_to address on
+proton::message and create a sender for that over which to send the
+response. We'll cache the senders incase we get further requests with the same
+reply\_to.
+
+Now let's create a simple \ref client.cpp to test this service out.
+
+\todo FIXME insert client snips
+
+As well as sending requests, we need to be able to get back the
+responses. We create a receiver for that (see line 14), but we don't
+specify an address, we set the dynamic option which tells the broker we
+are connected to to create a temporary address over which we can receive
+our responses.
+
+We need to use the address allocated by the broker as the reply\_to
+address of our requests, so we can't send them until the broker has
+confirmed our receiving link has been set up (at which point we will
+have our allocated address). To do that, we add an `on_link_opened()`
+method to our handler class, and if the link associated with event is
+the receiver, we use that as the trigger to send our first request.
+
+Again, we could avoid having any intermediary process here if we wished.
+The following code implementas a server to which the client above could
+connect directly without any need for a broker or similar.
+
+\todo FIXME missing server_direct.cpp
+
+Though this requires some more extensive changes than the simple sending
+and receiving examples, the essence of the program is still the same.
+Here though, rather than the server establishing a link for the
+response, it relies on the link that the client established, since that
+now comes in directly to the server process.
+
+### Miscellaneous
+
+Many brokers offer the ability to consume messages based on a 'selector'
+that defines which messages are of interest based on particular values
+of the headers. The following example shows how that can be achieved:
+
+\todo FIXME selected_recv.cpp
+
+When creating the receiver, we specify a Selector object as an option.
+The options argument can take a single object or a list. Another option
+that is sometimes of interest when using a broker is the ability to
+'browse' the messages on a queue, rather than consumig them. This is
+done in AMQP by specifying a distribution mode of 'copy' (instead of
+'move' which is the expected default for queues). An example of that is
+shown next:
+
+\todo FIXME queue_browser.cpp

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/docs/user.doxygen.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/docs/user.doxygen.in b/proton-c/bindings/cpp/docs/user.doxygen.in
index 9c7ad70..93252d1 100644
--- a/proton-c/bindings/cpp/docs/user.doxygen.in
+++ b/proton-c/bindings/cpp/docs/user.doxygen.in
@@ -41,13 +41,13 @@ PROJECT_NAME           = proton-cpp
 # This could be handy for archiving the generated documentation or
 # if some version control system is used.
 
-PROJECT_NUMBER         = 0
+PROJECT_NUMBER         = @PN_VERSION_MAJOR@.@PN_VERSION_MINOR@
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer
 # a quick idea about the purpose of the project. Keep the description short.
 
-PROJECT_BRIEF          =
+PROJECT_BRIEF          = "Proton C++ API"
 
 # With the PROJECT_LOGO tag one can specify an logo or icon that is
 # included in the documentation. The maximum height of the logo should not
@@ -337,7 +337,7 @@ EXTRACT_STATIC         = NO
 # defined locally in source files will be included in the documentation.
 # If set to NO only classes defined in header files are included.
 
-EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_CLASSES  = NO
 
 # This flag is only useful for Objective-C code. When set to YES local
 # methods, which are defined in the implementation section but not in
@@ -616,7 +616,7 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT = @CMAKE_SOURCE_DIR@/proton-c/bindings/cpp/include
+INPUT = @CMAKE_SOURCE_DIR@/proton-c/bindings/cpp/include @CMAKE_SOURCE_DIR@/proton-c/bindings/cpp/docs @CMAKE_SOURCE_DIR@/examples/cpp/README.md
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -634,7 +634,7 @@ INPUT_ENCODING         = UTF-8
 # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
 # *.f90 *.f *.for *.vhd *.vhdl
 
-FILE_PATTERNS          = *.h *.md *.hpp
+FILE_PATTERNS          = *.hpp *.md
 
 # The RECURSIVE tag can be used to turn specify whether or not subdirectories
 # should be searched for input files as well. Possible values are YES and NO.
@@ -675,7 +675,7 @@ EXCLUDE_SYMBOLS        =
 # directories that contain example code fragments that are included (see
 # the \include command).
 
-EXAMPLE_PATH           =
+EXAMPLE_PATH           = @CMAKE_SOURCE_DIR@/examples/cpp
 
 # If the value of the EXAMPLE_PATH tag contains directories, you can use the
 # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -689,7 +689,7 @@ EXAMPLE_PATTERNS       =
 # commands irrespective of the value of the RECURSIVE tag.
 # Possible values are YES and NO. If left blank NO is used.
 
-EXAMPLE_RECURSIVE      = NO
+EXAMPLE_RECURSIVE      = YES
 
 # The IMAGE_PATH tag can be used to specify one or more files or
 # directories that contain image that are included in the documentation (see
@@ -1085,7 +1085,7 @@ ENUM_VALUES_PER_LINE   = 4
 # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
 # Windows users are probably better off using the HTML help feature.
 
-GENERATE_TREEVIEW      = NO
+GENERATE_TREEVIEW      = YES
 
 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
 # used to set the initial width (in pixels) of the frame in which the tree
@@ -1390,13 +1390,13 @@ ENABLE_PREPROCESSING   = YES
 # compilation will be performed. Macro expansion can be done in a controlled
 # way by setting EXPAND_ONLY_PREDEF to YES.
 
-MACRO_EXPANSION        = NO
+MACRO_EXPANSION        = YES
 
 # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
 # then the macro expansion is limited to the macros specified with the
 # PREDEFINED and EXPAND_AS_DEFINED tags.
 
-EXPAND_ONLY_PREDEF     = NO
+EXPAND_ONLY_PREDEF     = YES
 
 # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
 # pointed to by INCLUDE_PATH will be searched when a #include is found.
@@ -1424,7 +1424,7 @@ INCLUDE_FILE_PATTERNS  =
 # undefined via #undef or recursively expanded use the := operator
 # instead of the = operator.
 
-PREDEFINED             =
+PREDEFINED             = PN_CPP_EXTERN=
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
 # this tag can be used to specify a list of macro names that should be expanded.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/include/proton/connection.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/connection.hpp b/proton-c/bindings/cpp/include/proton/connection.hpp
index 15b28fa..9998a0a 100644
--- a/proton-c/bindings/cpp/include/proton/connection.hpp
+++ b/proton-c/bindings/cpp/include/proton/connection.hpp
@@ -58,7 +58,7 @@ class connection : public endpoint, public handle<connection_impl>
     PN_CPP_EXTERN link link_head(endpoint::State mask);
   private:
    friend class private_impl_ref<connection>;
-   friend class Connector;
+   friend class connector;
    friend class connection_impl;
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/include/proton/container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/container.hpp b/proton-c/bindings/cpp/include/proton/container.hpp
index 0a1eb7a..2aaa289 100644
--- a/proton-c/bindings/cpp/include/proton/container.hpp
+++ b/proton-c/bindings/cpp/include/proton/container.hpp
@@ -25,6 +25,7 @@
 #include "proton/handle.hpp"
 #include "proton/acceptor.hpp"
 #include "proton/duration.hpp"
+#include "proton/url.hpp"
 #include <proton/reactor.h>
 #include <string>
 
@@ -32,7 +33,7 @@ namespace proton {
 
 class dispatch_helper;
 class connection;
-class Connector;
+class connector;
 class acceptor;
 class container_impl;
 class messaging_handler;
@@ -51,7 +52,7 @@ class container : public handle<container_impl>
 
     PN_CPP_EXTERN container();
     PN_CPP_EXTERN container(messaging_handler &mhandler);
-    PN_CPP_EXTERN connection connect(std::string &host, handler *h=0);
+    PN_CPP_EXTERN connection connect(const proton::url&, handler *h=0);
     PN_CPP_EXTERN void run();
     PN_CPP_EXTERN void start();
     PN_CPP_EXTERN bool process();
@@ -60,10 +61,10 @@ class container : public handle<container_impl>
     PN_CPP_EXTERN bool is_quiesced();
     PN_CPP_EXTERN pn_reactor_t *reactor();
     PN_CPP_EXTERN sender create_sender(connection &connection, std::string &addr, handler *h=0);
-    PN_CPP_EXTERN sender create_sender(std::string &url);
+    PN_CPP_EXTERN sender create_sender(const proton::url &);
     PN_CPP_EXTERN receiver create_receiver(connection &connection, std::string &addr);
-    PN_CPP_EXTERN receiver create_receiver(const std::string &url);
-    PN_CPP_EXTERN acceptor listen(const std::string &url);
+    PN_CPP_EXTERN receiver create_receiver(const url &);
+    PN_CPP_EXTERN acceptor listen(const proton::url &);
     PN_CPP_EXTERN std::string container_id();
     PN_CPP_EXTERN duration timeout();
     PN_CPP_EXTERN void timeout(duration timeout);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/include/proton/index.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/index.md b/proton-c/bindings/cpp/include/proton/index.md
deleted file mode 100644
index d82ab8a..0000000
--- a/proton-c/bindings/cpp/include/proton/index.md
+++ /dev/null
@@ -1,7 +0,0 @@
-@defgroup cpp C++ API
-
-Proton C++ API
-==============
-
-Provides a C++ object-oriented wrappers for the C proton API and stream-based
-operators to convert between C++ and AMQP data types.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/include/proton/mainpage.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/mainpage.hpp b/proton-c/bindings/cpp/include/proton/mainpage.hpp
deleted file mode 100644
index 92f4ce1..0000000
--- a/proton-c/bindings/cpp/include/proton/mainpage.hpp
+++ /dev/null
@@ -1,14 +0,0 @@
-/**@mainpage
-
-Proton C++ API
-==============
-
-Provides a C++ object-oriented wrappers for the C proton API and stream-based
-operators to convert between C++ and AMQP data types.
-
-For details on converting AMQP data types to/from C++ see the proton::encoder, proton::decoder
-and proton::value classes.
-
-TODO: entry points for reactive API.
-
-*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/include/proton/url.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/url.hpp b/proton-c/bindings/cpp/include/proton/url.hpp
new file mode 100644
index 0000000..1d7ca10
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/url.hpp
@@ -0,0 +1,102 @@
+#ifndef URL_HPP
+#define URL_HPP
+/*
+ * 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/proton_handle.hpp"
+#include "proton/error.hpp"
+#include <iosfwd>
+
+struct pn_url_t;
+
+namespace proton {
+
+struct bad_url : public error { PN_CPP_EXTERN explicit bad_url(const std::string&) throw(); };
+
+
+/**
+ * url is a proton URL of the form <scheme>://<username>:<password>@<host>:<port>/<path>.
+ */
+class url {
+  public:
+    static const std::string AMQP;     ///< "amqp" prefix
+    static const std::string AMQPS;    ///< "amqps" prefix
+
+    /** Create an empty url */
+    PN_CPP_EXTERN url();
+
+    /** Parse url_str as an AMQP URL. If defaults is true, fill in defaults for missing values
+     *  otherwise return an empty string for missing values.
+     *  Note: converts automatically from string.
+     *@throws bad_url if URL is invalid.
+     */
+    PN_CPP_EXTERN url(const std::string& url_str, bool defaults=true);
+
+    PN_CPP_EXTERN url(const url&);
+    PN_CPP_EXTERN ~url();
+    PN_CPP_EXTERN url& operator=(const url&);
+
+    /** Parse a string as a URL 
+     *@throws bad_url if URL is invalid.
+     */
+    PN_CPP_EXTERN void parse(const std::string&);
+
+    PN_CPP_EXTERN bool empty() const;
+
+    /** str returns the URL as a string string */
+    PN_CPP_EXTERN std::string str() const;
+
+    /**@name Get parts of the URL
+     *@{
+     */
+    PN_CPP_EXTERN std::string scheme() const;
+    PN_CPP_EXTERN std::string username() const;
+    PN_CPP_EXTERN std::string password() const;
+    PN_CPP_EXTERN std::string host() const;
+    /** port is a string, it can be a number or a symbolic name like "amqp" */
+    PN_CPP_EXTERN std::string port() const;
+    PN_CPP_EXTERN std::string path() const;
+    //@}
+
+    /** host_port returns just the host:port part of the URL */
+    PN_CPP_EXTERN std::string host_port() const;
+
+    /**@name Set parts of the URL
+     *@{
+     */
+    PN_CPP_EXTERN void scheme(const std::string&);
+    PN_CPP_EXTERN void username(const std::string&);
+    PN_CPP_EXTERN void password(const std::string&);
+    PN_CPP_EXTERN void host(const std::string&);
+    /** port is a string, it can be a number or a symbolic name like "amqp" */
+    PN_CPP_EXTERN void port(const std::string&);
+    PN_CPP_EXTERN void path(const std::string&);
+    //@}
+
+    /** defaults fills in default values for missing parts of the URL */
+    PN_CPP_EXTERN void defaults();
+
+  private:
+    pn_url_t* url_;
+};
+
+std::ostream& operator<<(std::ostream&, const url&);
+}
+
+#endif // URL_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/blocking_connection_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/blocking_connection_impl.cpp b/proton-c/bindings/cpp/src/blocking_connection_impl.cpp
index 0cc824f..43420d7 100644
--- a/proton-c/bindings/cpp/src/blocking_connection_impl.cpp
+++ b/proton-c/bindings/cpp/src/blocking_connection_impl.cpp
@@ -60,7 +60,7 @@ struct connection_closed : public wait_condition {
 }
 
 
-blocking_connection_impl::blocking_connection_impl(std::string &u, duration timeout0, ssl_domain *ssld, container *c)
+blocking_connection_impl::blocking_connection_impl(const url &u, duration timeout0, ssl_domain *ssld, container *c)
     : url_(u), timeout_(timeout0), refcount_(0)
 {
     if (c)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/blocking_connection_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/blocking_connection_impl.hpp b/proton-c/bindings/cpp/src/blocking_connection_impl.hpp
index 02305ba..edb08a6 100644
--- a/proton-c/bindings/cpp/src/blocking_connection_impl.hpp
+++ b/proton-c/bindings/cpp/src/blocking_connection_impl.hpp
@@ -38,7 +38,7 @@ class ssl_domain;
  class blocking_connection_impl : public messaging_handler
 {
   public:
-    PN_CPP_EXTERN blocking_connection_impl(std::string &url, duration d, ssl_domain *ssld, container *c);
+    PN_CPP_EXTERN blocking_connection_impl(const url &url, duration d, ssl_domain *ssld, container *c);
     PN_CPP_EXTERN ~blocking_connection_impl();
     PN_CPP_EXTERN void close();
     PN_CPP_EXTERN void wait(wait_condition &condition);
@@ -51,7 +51,7 @@ class ssl_domain;
     friend class blocking_connection;
     container container_;
     connection connection_;
-    std::string url_;
+    url url_;
     duration timeout_;
     int refcount_;
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/connection_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_impl.hpp b/proton-c/bindings/cpp/src/connection_impl.hpp
index 02c47b4..816f0d5 100644
--- a/proton-c/bindings/cpp/src/connection_impl.hpp
+++ b/proton-c/bindings/cpp/src/connection_impl.hpp
@@ -57,7 +57,7 @@ class connection_impl : public endpoint
     static void incref(connection_impl *);
     static void decref(connection_impl *);
   private:
-    friend class Connector;
+    friend class connector;
     friend class container_impl;
     class container container_;
     int refcount_;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/connector.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connector.cpp b/proton-c/bindings/cpp/src/connector.cpp
index 2b1b935..559a7fd 100644
--- a/proton-c/bindings/cpp/src/connector.cpp
+++ b/proton-c/bindings/cpp/src/connector.cpp
@@ -24,42 +24,41 @@
 #include "proton/container.hpp"
 #include "proton/event.hpp"
 #include "proton/connection.h"
+#include "proton/url.hpp"
+
 #include "connector.hpp"
 #include "connection_impl.hpp"
-#include "url.hpp"
 
 namespace proton {
 
-Connector::Connector(connection &c) : connection_(c), transport_(0) {}
+connector::connector(connection &c) : connection_(c), transport_(0) {}
 
-Connector::~Connector() {}
+connector::~connector() {}
 
-void Connector::address(const std::string &a) {
+void connector::address(const url &a) {
     address_ = a;
 }
 
-void Connector::connect() {
+void connector::connect() {
     pn_connection_t *conn = connection_.pn_connection();
     pn_connection_set_container(conn, connection_.container().container_id().c_str());
-    Url url(address_);
-    std::string hostname = url.host() + ":" + url.port();
-    pn_connection_set_hostname(conn, hostname.c_str());
+    pn_connection_set_hostname(conn, address_.host_port().c_str());
     transport_ = new transport();
     transport_->bind(connection_);
     connection_.impl_->transport_ = transport_;
 }
 
 
-void Connector::on_connection_local_open(event &e) {
+void connector::on_connection_local_open(event &e) {
     connect();
 }
 
-void Connector::on_connection_remote_open(event &e) {}
+void connector::on_connection_remote_open(event &e) {}
 
-void Connector::on_connection_init(event &e) {
+void connector::on_connection_init(event &e) {
 }
 
-void Connector::on_transport_closed(event &e) {
+void connector::on_transport_closed(event &e) {
     // TODO: prepend with reconnect logic
     pn_connection_release(connection_.impl_->pn_connection_);
     // No more interaction, so drop our counted reference.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/connector.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connector.hpp b/proton-c/bindings/cpp/src/connector.hpp
index 29e3326..ad373a9 100644
--- a/proton-c/bindings/cpp/src/connector.hpp
+++ b/proton-c/bindings/cpp/src/connector.hpp
@@ -25,6 +25,7 @@
 #include "proton/proton_handler.hpp"
 #include "proton/event.h"
 #include "proton/reactor.h"
+#include "proton/url.h"
 #include <string>
 
 
@@ -34,12 +35,12 @@ class event;
 class connection;
 class transport;
 
-class Connector : public proton_handler
+class connector : public proton_handler
 {
   public:
-    Connector(connection &c);
-    ~Connector();
-    void address(const std::string &host);
+    connector(connection &c);
+    ~connector();
+    void address(const url&);
     void connect();
     virtual void on_connection_local_open(event &e);
     virtual void on_connection_remote_open(event &e);
@@ -48,7 +49,7 @@ class Connector : public proton_handler
 
   private:
     connection connection_;
-    std::string address_;
+    url address_;
     transport *transport_;
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/container.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container.cpp b/proton-c/bindings/cpp/src/container.cpp
index 750300b..f135336 100644
--- a/proton-c/bindings/cpp/src/container.cpp
+++ b/proton-c/bindings/cpp/src/container.cpp
@@ -25,13 +25,12 @@
 #include "proton/messaging_adapter.hpp"
 #include "proton/acceptor.hpp"
 #include "proton/error.hpp"
+#include "proton/url.hpp"
+
 #include "container_impl.hpp"
 #include "private_impl_ref.hpp"
-
 #include "connector.hpp"
 #include "contexts.hpp"
-#include "url.hpp"
-
 #include "proton/connection.h"
 #include "proton/session.h"
 
@@ -55,7 +54,7 @@ container::container() {
     PI::ctor(*this, cimpl);
 }
 
-connection container::connect(std::string &host, handler *h) { return impl_->connect(host, h); }
+connection container::connect(const url &host, handler *h) { return impl_->connect(host, h); }
 
 pn_reactor_t *container::reactor() { return impl_->reactor(); }
 
@@ -69,20 +68,20 @@ sender container::create_sender(connection &connection, std::string &addr, handl
     return impl_->create_sender(connection, addr, h);
 }
 
-sender container::create_sender(std::string &url_string) {
-    return impl_->create_sender(url_string);
+sender container::create_sender(const proton::url &url) {
+    return impl_->create_sender(url);
 }
 
 receiver container::create_receiver(connection &connection, std::string &addr) {
     return impl_->create_receiver(connection, addr);
 }
 
-receiver container::create_receiver(const std::string &url) {
+receiver container::create_receiver(const proton::url &url) {
     return impl_->create_receiver(url);
 }
 
-acceptor container::listen(const std::string &url_string) {
-    return impl_->listen(url_string);
+acceptor container::listen(const proton::url &url) {
+    return impl_->listen(url);
 }
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container_impl.cpp b/proton-c/bindings/cpp/src/container_impl.cpp
index 3ce6e25..fc1aafd 100644
--- a/proton-c/bindings/cpp/src/container_impl.cpp
+++ b/proton-c/bindings/cpp/src/container_impl.cpp
@@ -25,13 +25,13 @@
 #include "proton/messaging_adapter.hpp"
 #include "proton/acceptor.hpp"
 #include "proton/error.hpp"
+#include "proton/url.hpp"
 
 #include "msg.hpp"
 #include "container_impl.hpp"
 #include "connection_impl.hpp"
 #include "connector.hpp"
 #include "contexts.hpp"
-#include "url.hpp"
 #include "private_impl_ref.hpp"
 
 #include "proton/connection.h"
@@ -73,7 +73,7 @@ class CHandler : public handler
 };
 
 
-// Used to sniff for Connector events before the reactor's global handler sees them.
+// Used to sniff for connector events before the reactor's global handler sees them.
 class override_handler : public handler
 {
   public:
@@ -196,16 +196,16 @@ container_impl::~container_impl() {
     pn_reactor_free(reactor_);
 }
 
-connection container_impl::connect(std::string &host, handler *h) {
+connection container_impl::connect(const proton::url &url, handler *h) {
     if (!reactor_) throw error(MSG("container not started"));
-    container cntnr(this);
-    connection connection(cntnr, handler_);
-    Connector *connector = new Connector(connection);
-    // Connector self-deletes depending on reconnect logic
-    connector->address(host);  // TODO: url vector
-    connection.override(connector);
-    connection.open();
-    return connection;
+    container ctnr(this);
+    connection conn(ctnr, handler_);
+    connector *ctor = new connector(conn);
+    // connector self-deletes depending on reconnect logic
+    ctor->address(url);  // TODO: url vector
+    conn.override(ctor);
+    conn.open();
+    return conn;
 }
 
 pn_reactor_t *container_impl::reactor() { return reactor_; }
@@ -244,11 +244,11 @@ sender container_impl::create_sender(connection &connection, std::string &addr,
     return snd;
 }
 
-sender container_impl::create_sender(std::string &url_string) {
+sender container_impl::create_sender(const proton::url &url) {
     if (!reactor_) throw error(MSG("container not started"));
-    connection conn = connect(url_string, 0);
+    connection conn = connect(url, 0);
     session session = default_session(conn.pn_connection(), &impl(conn)->default_session_);
-    std::string path = Url(url_string).path();
+    std::string path = url.path();
     sender snd = session.create_sender(container_id_ + '-' + path);
     pn_terminus_set_address(pn_link_target(snd.pn_link()), path.c_str());
     snd.open();
@@ -265,31 +265,29 @@ receiver container_impl::create_receiver(connection &connection, std::string &ad
     return rcv;
 }
 
-receiver container_impl::create_receiver(const std::string &url_string) {
+receiver container_impl::create_receiver(const proton::url &url) {
     if (!reactor_) throw error(MSG("container not started"));
     // TODO: const cleanup of API
-    connection conn = connect(const_cast<std::string &>(url_string), 0);
+    connection conn = connect(url, 0);
     session session = default_session(conn.pn_connection(), &impl(conn)->default_session_);
-    std::string path = Url(url_string).path();
+    std::string path = url.path();
     receiver rcv = session.create_receiver(container_id_ + '-' + path);
     pn_terminus_set_address(pn_link_source(rcv.pn_link()), path.c_str());
     rcv.open();
     return rcv;
 }
 
-class acceptor container_impl::acceptor(const std::string &host, const std::string &port) {
-    pn_acceptor_t *acptr = pn_reactor_acceptor(reactor_, host.c_str(), port.c_str(), NULL);
+class acceptor container_impl::acceptor(const proton::url& url) {
+    pn_acceptor_t *acptr = pn_reactor_acceptor(reactor_, url.host().c_str(), url.port().c_str(), NULL);
     if (acptr)
         return proton::acceptor(acptr);
     else
-        throw error(MSG("accept fail: " << pn_error_text(pn_io_error(pn_reactor_io(reactor_))) << "(" << host << ":" << port << ")"));
+        throw error(MSG("accept fail: " << pn_error_text(pn_io_error(pn_reactor_io(reactor_))) << "(" << url << ")"));
 }
 
-acceptor container_impl::listen(const std::string &url_string) {
+acceptor container_impl::listen(const proton::url &url) {
     if (!reactor_) throw error(MSG("container not started"));
-    Url url(url_string);
-    // TODO: SSL
-    return acceptor(url.host(), url.port());
+    return acceptor(url);
 }
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/container_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container_impl.hpp b/proton-c/bindings/cpp/src/container_impl.hpp
index 4507ab6..39f513d 100644
--- a/proton-c/bindings/cpp/src/container_impl.hpp
+++ b/proton-c/bindings/cpp/src/container_impl.hpp
@@ -43,14 +43,14 @@ class container_impl
     PN_CPP_EXTERN container_impl(handler &h);
     PN_CPP_EXTERN container_impl();
     PN_CPP_EXTERN ~container_impl();
-    PN_CPP_EXTERN connection connect(std::string &host, handler *h);
+    PN_CPP_EXTERN connection connect(const url&, handler *h);
     PN_CPP_EXTERN void run();
     PN_CPP_EXTERN pn_reactor_t *reactor();
     PN_CPP_EXTERN sender create_sender(connection &connection, std::string &addr, handler *h);
-    PN_CPP_EXTERN sender create_sender(std::string &url);
+    PN_CPP_EXTERN sender create_sender(const url&);
     PN_CPP_EXTERN receiver create_receiver(connection &connection, std::string &addr);
-    PN_CPP_EXTERN receiver create_receiver(const std::string &url);
-    PN_CPP_EXTERN class acceptor listen(const std::string &url);
+    PN_CPP_EXTERN receiver create_receiver(const url&);
+    PN_CPP_EXTERN class acceptor listen(const url&);
     PN_CPP_EXTERN std::string container_id();
     PN_CPP_EXTERN duration timeout();
     PN_CPP_EXTERN void timeout(duration timeout);
@@ -64,7 +64,7 @@ class container_impl
     static void decref(container_impl *);
   private:
     void dispatch(pn_event_t *event, pn_event_type_t type);
-    class acceptor acceptor(const std::string &host, const std::string &port);
+    class acceptor acceptor(const url&);
     void initialize_reactor();
     pn_reactor_t *reactor_;
     handler *handler_;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/grep
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/grep b/proton-c/bindings/cpp/src/grep
index 6be6b10..2842f5c 100644
--- a/proton-c/bindings/cpp/src/grep
+++ b/proton-c/bindings/cpp/src/grep
@@ -10,8 +10,8 @@
   -rw-rw-r--. 1 aconway aconway  2390 Jun 10 08:40 Connection.cpp
   -rw-rw-r--. 1 aconway aconway  4285 Jun 10 08:40 ConnectionImpl.cpp
   -rw-rw-r--. 1 aconway aconway  2531 Jun 10 08:40 ConnectionImpl.h
-  -rw-rw-r--. 1 aconway aconway  2131 Jun 10 08:40 Connector.cpp
-  -rw-rw-r--. 1 aconway aconway  1624 Jun 10 08:40 Connector.h
+  -rw-rw-r--. 1 aconway aconway  2131 Jun 10 08:40 connector.cpp
+  -rw-rw-r--. 1 aconway aconway  1624 Jun 10 08:40 connector.h
   -rw-rw-r--. 1 aconway aconway  3188 Jun 10 08:40 Container.cpp
   -rw-rw-r--. 1 aconway aconway 12183 Jun 10 08:40 ContainerImpl.cpp
   -rw-rw-r--. 1 aconway aconway  2689 Jun 10 08:40 ContainerImpl.h

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/url.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/url.cpp b/proton-c/bindings/cpp/src/url.cpp
index 5744f49..d5ab411 100644
--- a/proton-c/bindings/cpp/src/url.cpp
+++ b/proton-c/bindings/cpp/src/url.cpp
@@ -20,57 +20,74 @@
  */
 
 #include "proton/error.hpp"
-#include "url.hpp"
-#include "proton_impl_ref.hpp"
-#include "msg.hpp"
+#include "proton/url.hpp"
+#include "proton/url.h"
 
 namespace proton {
 
-template class proton_handle<pn_url_t>;
-typedef proton_impl_ref<Url> PI;
+bad_url::bad_url(const std::string& s) throw() : error(s) {}
 
+namespace {
 
-Url::Url(const std::string &url) {
-    pn_url_t *up = pn_url_parse(url.c_str());
-    // refcount is 1, no need to incref
-    if (!up)
-        throw error(MSG("invalid URL: " << url));
-    impl_ = up;
+pn_url_t* parse_throw(const std::string& s) {
+    pn_url_t* u = pn_url_parse(s.c_str());
+    if (!u) throw bad_url("invalid URL: " + s);
+    return u;
 }
 
-Url::~Url() { PI::dtor(*this); }
-
-Url::Url(const Url& c) : proton_handle<pn_url_t>() {
-    PI::copy(*this, c);
+pn_url_t* parse_allow_empty(const std::string& s) {
+    return s.empty() ? pn_url() : parse_throw(s);
 }
 
-Url& Url::operator=(const Url& c) {
-    return PI::assign(*this, c);
-}
+std::string char_str(const char* s) { return s ? std::string(s) : std::string(); }
 
-std::string Url::port() {
-    const char *p = pn_url_get_port(impl_);
-    if (!p)
-        return std::string("5672");
-    else
-        return std::string(p);
+void replace(pn_url_t*& var, pn_url_t* val) {
+    if (var) pn_url_free(var);
+    var = val;
 }
 
-std::string Url::host() {
-    const char *p = pn_url_get_host(impl_);
-    if (!p)
-        return std::string("0.0.0.0");
-    else
-        return std::string(p);
-}
+} // namespace
 
-std::string Url::path() {
-    const char *p = pn_url_get_path(impl_);
-    if (!p)
-        return std::string("");
-    else
-        return std::string(p);
-}
+url::url() : url_(pn_url()) {}
+
+url::url(const std::string &s, bool d) : url_(parse_throw(s)) { if (d) defaults(); }
+
+url::url(const url& u) : url_(parse_allow_empty(u.str())) {}
+
+url::~url() { pn_url_free(url_); }
+
+url& url::operator=(const url& u) { replace(url_, parse_allow_empty(u.str())); return *this; }
 
+void url::parse(const std::string& s) { replace(url_, parse_throw(s)); }
 
+std::string url::str() const { return char_str(pn_url_str(url_)); }
+
+std::string url::scheme() const { return char_str(pn_url_get_scheme(url_)); }
+std::string url::username() const { return char_str(pn_url_get_username(url_)); }
+std::string url::password() const { return char_str(pn_url_get_password(url_)); }
+std::string url::host() const { return char_str(pn_url_get_host(url_)); }
+std::string url::port() const { return char_str(pn_url_get_port(url_)); }
+std::string url::path() const { return char_str(pn_url_get_path(url_)); }
+
+std::string url::host_port() const { return host() + ":" + port(); }
+
+bool url::empty() const { return str().empty(); }
+
+void url::scheme(const std::string& s) { pn_url_set_scheme(url_, s.c_str()); }
+void url::username(const std::string& s) { pn_url_set_username(url_, s.c_str()); }
+void url::password(const std::string& s) { pn_url_set_password(url_, s.c_str()); }
+void url::host(const std::string& s) { pn_url_set_host(url_, s.c_str()); }
+void url::port(const std::string& s) { pn_url_set_port(url_, s.c_str()); }
+void url::path(const std::string& s) { pn_url_set_path(url_, s.c_str()); }
+
+void url::defaults() {
+    if (scheme().empty()) scheme(AMQP);
+    if (port().empty()) port(scheme());
 }
+
+const std::string url::AMQP("amqp");
+const std::string url::AMQPS("amqps");
+
+std::ostream& operator<<(std::ostream& o, const url& u) { return o << u.str(); }
+
+} // namespace proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/52c90597/proton-c/bindings/cpp/src/url.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/url.hpp b/proton-c/bindings/cpp/src/url.hpp
deleted file mode 100644
index 0cc8690..0000000
--- a/proton-c/bindings/cpp/src/url.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef PROTON_CPP_URL_H
-#define PROTON_CPP_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/export.hpp"
-#include "proton/proton_handle.hpp"
-#include "proton/url.h"
-#include <string>
-
-namespace proton {
-
-class Url : public proton_handle<pn_url_t>
-{
-  public:
-    PN_CPP_EXTERN Url(const std::string &url);
-    PN_CPP_EXTERN ~Url();
-    PN_CPP_EXTERN Url(const Url&);
-    PN_CPP_EXTERN Url& operator=(const Url&);
-    PN_CPP_EXTERN std::string host();
-    PN_CPP_EXTERN std::string port();
-    PN_CPP_EXTERN std::string path();
-  private:
-    friend class proton_impl_ref<Url>;
-};
-
-
-}
-
-#endif  /*!PROTON_CPP_URL_H*/


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