Repository: qpid-proton Updated Branches: refs/heads/0.13.x 85aaf3a3a -> 662592386
PROTON-1200: Various C++ doc improvements - Update the topic pages for clarity, style, and correct links - Fix the example includes in the tutorial - Add missing API doc for coerce(scalar) - Spruce up the README a bit - Remove an unused include from helloworld.cpp - Mark all drain-related API experimental - Hide all the amqp typedefs in anticipation of removing them - Don't show PN_CPP_OVERRIDE in the generated API docs for default_container Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/66259238 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/66259238 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/66259238 Branch: refs/heads/0.13.x Commit: 662592386fd4a54f290b3b6672308ef44335a505 Parents: 85aaf3a Author: Justin Ross <[email protected]> Authored: Sun Jun 5 14:48:31 2016 -0700 Committer: Justin Ross <[email protected]> Committed: Sun Jun 5 14:51:20 2016 -0700 ---------------------------------------------------------------------- examples/cpp/helloworld.cpp | 2 +- examples/cpp/tutorial.dox | 389 ++++++++++--------- proton-c/bindings/cpp/README.md | 39 +- proton-c/bindings/cpp/docs/io.md | 30 +- proton-c/bindings/cpp/docs/main.md | 66 ++-- proton-c/bindings/cpp/docs/mt.md | 75 ++-- proton-c/bindings/cpp/docs/types.md | 11 +- proton-c/bindings/cpp/docs/user.doxygen.in | 2 +- .../cpp/include/proton/codec/amqp_types.hpp | 5 + .../bindings/cpp/include/proton/container.hpp | 25 +- .../cpp/include/proton/internal/type_traits.hpp | 4 +- proton-c/bindings/cpp/include/proton/link.hpp | 8 +- .../cpp/include/proton/messaging_handler.hpp | 7 +- .../bindings/cpp/include/proton/receiver.hpp | 16 +- proton-c/bindings/cpp/include/proton/scalar.hpp | 12 + proton-c/bindings/cpp/include/proton/sender.hpp | 7 +- proton-c/bindings/cpp/include/proton/source.hpp | 2 +- proton-c/bindings/cpp/include/proton/target.hpp | 2 +- 18 files changed, 371 insertions(+), 331 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/examples/cpp/helloworld.cpp ---------------------------------------------------------------------- diff --git a/examples/cpp/helloworld.cpp b/examples/cpp/helloworld.cpp index 84a5919..fa95af0 100644 --- a/examples/cpp/helloworld.cpp +++ b/examples/cpp/helloworld.cpp @@ -23,7 +23,6 @@ #include <proton/default_container.hpp> #include <proton/delivery.hpp> #include <proton/messaging_handler.hpp> -#include <proton/tracker.hpp> #include <proton/url.hpp> #include <iostream> @@ -64,6 +63,7 @@ int main(int argc, char **argv) { hello_world hw(url); proton::default_container(hw).run(); + return 0; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/examples/cpp/tutorial.dox ---------------------------------------------------------------------- diff --git a/examples/cpp/tutorial.dox b/examples/cpp/tutorial.dox index 87456b9..56345a1 100644 --- a/examples/cpp/tutorial.dox +++ b/examples/cpp/tutorial.dox @@ -4,88 +4,95 @@ // is markdown wrapped in a doxygen comment - which works. The file is best viewed/editied // as markdown. -/**@page 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. +@page 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. Proton provides an "event-driven" programming model, where you implement a subclass of `proton::messaging_handler` and override functions that react to various AMQP events (connections opening and -closing, messages being delivered and so on.) - -The examples below show how to implement handlers for clients and servers and -how to run them using the `proton::container`, a portable, easy-to-use way to -build single-threaded clients or servers. +closing, messages being delivered, and so on). -@note Proton can also be embedded or integrated into arbitrary IO frameworks and used -to build multi-threaded applications. See @ref mt_page for more. +The examples below show how to implement handlers for clients and +servers and how to run them using the `proton::default_container`, a +portable, easy-to-use way to build single-threaded clients or servers. -Some of the examples require an AMQP *broker* that can receive, store and send -messages. @ref broker.hpp and @ref broker.cpp define a simple example -broker. Run without arguments it listens on `0.0.0.0:5672`, the standard AMQP -port on all network interfaces. To use a different port or network interface: +Some of the examples require an AMQP *broker* that can receive, store, +and send messages. @ref broker.hpp and @ref broker.cpp define a simple +example broker. If run without arguments, it listens on +`0.0.0.0:5672`, the standard AMQP port on all network interfaces. To +use a different port or network interface: broker -a <host>:<port> -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". +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". -The `helloworld` examples take an optional URL argument. The other examples take -an option `-a URL`. A URL looks like: +The `helloworld` examples take an optional URL argument. The other +examples take an option `-a URL`. A URL looks like this: 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` +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 +Tradition dictates that we start with Hello World! This example +demonstrates sending and receiving by sending a message to a broker +and then receiving the same message back. 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 -mentioned above. +We will include the following classes: `proton::default_container` (an +implementation of `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::connection` and `proton::delivery` are AMQP +entities used in the handler functions. `proton::url` is a simple +parser for the URL format mentioned above. -\skip proton/container -\until proton/url +\skip proton/connection +\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 +`proton::messaging_handler` and overrides functions to handle the events of interest in sending and receiving a message. \skip class hello_world \until {} -`on_container_start()` is called when the event loop first starts. We -handle that by establishing a connection and creating a sender and a -receiver. +`proton::messaging_handler::on_container_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_container_start \until } +\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()`. +`proton::messaging_handler::on_sendable()` is called when the 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, since we +only want to send one message. Closing the sender will prevent further +calls to `proton::messaging_handler::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 +`proton::messaging_handler::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 } @@ -94,7 +101,7 @@ 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 +and a `proton::default_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 @@ -105,50 +112,53 @@ turn is a subclass of `std::exception`. \until } \until } -Hello World, Direct! +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 to communicate directly if desired. +Though often used in conjunction with a broker, AMQP does not +*require* this. It also allows senders and receivers to 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 +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 and +receive scenario. The full code is 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. +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_container_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. +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. +We send the message in response to the +`proton::messaging_handler::on_sendable()` callback and print the +message out in response to the +`proton::messaging_handler::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_delivery_accept()` -callback. +However, we also handle two new events. We now close the connection +from the sender's 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 +`proton::messaging_handler::on_tracker_accept()` callback. -\skip on_delivery_accept +\skip on_tracker_accept \until } -Then, once the connection has been closed, of which we are -notified through the `on_connection_close()` 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. +Then, once the connection has been closed, of which we are notified +through the `proton::messaging_handler::on_connection_close()` +callback, we stop accepting incoming connections. A that point there +is no work to be done, the event loop exits, and the +`proton::container::run()` method returns. \skip on_connection_close \until } @@ -160,121 +170,128 @@ to ourselves rather than a broker. \skipline url = -Asynchronous Send and Receive +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). +Of course, these `Hello World!` 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. +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. +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. +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_container_start()` event to establish our sender link over which -we will transfer messages. +As before, we use the +`proton::messaging_handler::on_container_start()` event to establish +our sender link over which we will transfer messages. \skip on_container_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. +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. +In the `proton::messaging_handler::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. +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 +`proton::messaging_handler::on_tracker_accept()` 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_delivery_accept +\skip on_tracker_accept \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 +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 +`proton::messaging_handler::on_transport_close()` 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. +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_disconnect +\skip on_transport_close \until } \dontinclude simple_recv.cpp -Now let's look at the corresponding receiver @ref 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 expect and -a `received` variable to count how many we have received so far. +This time we'll use an `expected` member variable for for the number +of messages we expect and a `received` variable to count how many we +have received so far. \skip class simple_recv \until received -We handle `on_container_start()` by creating our receiver, much like -we did for the sender. +We handle `proton::messaging_handler::on_container_start()` by +creating our receiver, much like we did for the sender. \skip on_container_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. +We also handle the `proton::messaging_handler::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 and then 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 +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 +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_container_start \until } -When we have received all the expected messages, we then stop listening for -incoming connections by calling `container::stop_listening()` +When we have received all the expected messages, we then stop +listening for incoming connections by calling +`proton::listener::stop()` \skip on_message \until } @@ -283,12 +300,13 @@ incoming connections by calling `container::stop_listening()` \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). +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: +We can also modify the sender to allow the original receiver to +connect to it, in @ref direct_send.cpp. Again, that requires just two +modifications: \dontinclude direct_send.cpp @@ -299,70 +317,74 @@ link, we listen for incoming connections. \until } When we have received confirmation of all the messages we sent, we call -`container::stop_listening()` to exit. +`container::listener::stop()` to exit. -\skip on_delivery_accept +\skip on_tracker_accept \until } \until } -To try this modified sender, run the original @ref simple_recv.cpp against it. +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.hpp and @ref -broker.cpp provide a simple broker for testing purposes is an example of this). +The symmetry in the underlying AMQP wire protocol 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. -Request/Response ----------------- +Request and response +-------------------- -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. +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. -Our server will provide a very simple service: it will respond with the -body of the request converted to uppercase. +Our server will provide a very simple service: it will respond with +the body of the request converted to uppercase. \dontinclude server.cpp \skip class server \until }; -The code here is not too different from the simple receiver example. When we -receive a request in `on_message` however, we look at the -`proton::message::reply_to` address and create a sender with that address for -the response. We'll cache the senders incase we get further requests with the -same `reply_to`. +The code here is not too different from the simple receiver example. +However, when we receive a request in +`proton::messaging_handler::on_message`, we look at the +`proton::message::reply_to` address and create a sender with that +address for the response. We'll cache the senders in case we get +further requests with the same `reply_to`. Now let's create a simple @ref client.cpp to test this service out. \dontinclude client.cpp -Our client takes a list of strings to send as requests +Our client takes a list of strings to send as requests. \skipline client( Since we will be sending and receiving, we create a sender and a -receiver in `on_container_start`. Our receiver has a blank address -and sets the `dynamic` flag to true, which means we expect the remote -end (broker or server) to assign a unique address for us. +receiver in `proton::messaging_handler::on_container_start`. Our +receiver has a blank address and sets the `dynamic` flag to true, +which means we expect the remote end (the broker or server) to assign +a unique address for us. \skip on_container_start \until } -Now a function to send the next request from our list of requests. We set the -reply_to address to be the dynamically assigned address of our receiver. +Now we need a function to send the next request from our list of +requests. We set the `reply_to` address to be the dynamically assigned +address of our receiver. \skip send_request \until } -We need to use the address assigned by the broker as the `reply_to` address of -our requests, so we can't send them until our receiver has been set up. To do -that, we add an `on_link_open()` 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. +We need to use the address assigned by the broker as the `reply_to` +address of our requests, so we can't send them until our receiver has +been set up. To do that, we add an +`proton::messaging_handler::on_receiver_open()` method to our handler +class and use that as the trigger to send our first request. -\skip on_link_open +\skip on_receiver_open \until } When we receive a reply, we send the next request. @@ -372,34 +394,35 @@ When we receive a reply, we send the next request. \until } \until } -Direct Request/Response ------------------------ +Direct request and response +--------------------------- We can avoid the intermediary process by writing a server that accepts -connections directly, @ref server_direct.cpp. It involves the following changes -to our original server: +connections directly, @ref server_direct.cpp. It involves the +following changes to our original server: \dontinclude server_direct.cpp -Our server must generate a unique reply-to addresses for links from the -client that request a dynamic address (previously this was done by the broker.) -We use a simple counter. +Our server must generate unique `reply-to` addresses for links from +the client that request a dynamic address (previously this was done by +the broker). We use a simple counter. \skip generate_address \until } -Next we need to handle incoming requests for links with dynamic addresses from -the client. We give the link a unique address and record it in our `senders` -map. +Next we need to handle incoming requests for links with dynamic +addresses from the client. We give the link a unique address and +record it in our `senders` map. -\skip on_link_open +\skip on_sender_open \until } -Note we are interested in *sender* links above because we are implementing the -server. A *receiver* link created on the client corresponds to a *sender* link -on the server. +Note that we are interested in *sender* links above because we are +implementing the server. A *receiver* link created on the client +corresponds to a *sender* link on the server. -Finally when we receive a message we look up its `reply_to` in our senders map and send the reply. +Finally when we receive a message we look up its `reply_to` in our +senders map and send the reply. \skip on_message \until } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/README.md ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/README.md b/proton-c/bindings/cpp/README.md index c89534e..bedfd0d 100644 --- a/proton-c/bindings/cpp/README.md +++ b/proton-c/bindings/cpp/README.md @@ -1,38 +1,43 @@ -# C++ binding for proton. +# Qpid Proton C++ -This is a C++ binding for the proton API. +This is a C++ binding for the Proton API. The documentation includes a tutorial and API documentation. -To generate the documentation go to your build directory, run `make docs-cpp` -and open `proton-c/bindings/cpp/docs/html/index.html` in a browser. +To generate the documentation go to your build directory, run `make +docs-cpp`, and open `proton-c/bindings/cpp/docs/html/index.html` in a +browser. -# TO DO +## Todo + +### Tests -Tests - Interop/type testing: proton/tests/interop, new interop suite -- More unit testing, measured code coverage. -- Test examples against AM-Q and qpidd. +- More unit testing, measured code coverage +- Test examples against ActiveMQ and qpidd + +### Bugs -Bugs - Error handling: - - examples exit silently on broker exit/not running, core on no-such-queue (e.g. with qpidd) + - examples exit silently on broker exit/not running, core on + no-such-queue (e.g., with qpidd) + +### Features -Features - SASL/SSL support with interop tests. - Reconnection - Browsing - Selectors -- AMQP described types and arrays, full support and tests. +- AMQP described types and arrays, full support and tests - Durable subscriptions & demos (see python changes) - Transactions - Heartbeats -# Nice to have +### Nice to have -- C++11 lambda version of handlers. +- C++11 lambda version of handlers - Helpers (or at least doc) for multi-threaded use (container per connection) -- Usable support for decimal types. -- Expose endpoint conditions as C++ proton::condition error class. +- Usable support for decimal types +- Expose endpoint conditions as C++ proton::condition error class - Selectables and 3rd party event loop support -- More efficient shared_ptr (single family per proton object.) +- More efficient shared_ptr (single family per proton object) http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/docs/io.md ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/docs/io.md b/proton-c/bindings/cpp/docs/io.md index 0eac8da..a892e61 100644 --- a/proton-c/bindings/cpp/docs/io.md +++ b/proton-c/bindings/cpp/docs/io.md @@ -1,21 +1,27 @@ # IO integration {#io_page} -**Experimental** +**Experimental** - The `proton::io` interfaces are new and remain +subject to change. -The `proton::io` namespace contains a service provider interface (SPI) that -allows you to implement the @ref proton API over alternative IO or threading -libraries. +The `proton::io` namespace contains a service provider interface (SPI) +that allows you to implement the Proton API over alternative IO or +threading libraries. -The `proton::io::connection_engine` converts an AMQP-encoded byte stream, read -from any IO source, into `proton::messaging_handler` calls. It generates an -AMQP-encoded byte stream as output, that can be written to any IO destination. +The `proton::io::connection_engine` class converts an AMQP-encoded +byte stream, read from any IO source, into `proton::messaging_handler` +calls. It generates an AMQP-encoded byte stream as output that can be +written to any IO destination. -The connection_engine can be used stand-alone, as an AMQP translator or you -can implement the following two interfaces to provide a complete implementation -of the proton API, that can run any proton application: +The connection engine is deliberately very simple and low level. It +performs no IO of its own, no thread-related locking, and is written +in simple C++98-compatible code. - - `proton::container` lets the user initiate or listen for connections. +The connection engine can be used standalone as an AMQP translator, or +you can implement the following two interfaces to provide a complete +implementation of the Proton API that can run any Proton application: - - `proton::event_loop` lets the user serialize work with a connection. + - `proton::container` lets the user initiate or listen for connections. + - `proton::event_loop` lets the user serialize work with respect to a + connection. @see @ref mt/epoll\_container.cpp for an example. http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/docs/main.md ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/docs/main.md b/proton-c/bindings/cpp/docs/main.md index 3ff00a1..011df29 100644 --- a/proton-c/bindings/cpp/docs/main.md +++ b/proton-c/bindings/cpp/docs/main.md @@ -22,13 +22,16 @@ Sessions are created over a `proton::connection`, which represents the network connection. You can create links directly on a connection using its default session if you don't need multiple sessions. -`proton::message` represents the message: the body (content), properties, -headers and annotations. A `proton::delivery` represents the act of transferring -a message over a link. The receiver acknowledges the delivery by accepting or -rejecting it. The delivery is *settled* when both ends are done with it. -Different settlement methods give different levels of reliability: -*at-most-once*, *at-least-once*, and *exactly-once*. See "Delivery Guarantees" -below for details. +`proton::message` represents the message: the body (content), +properties, headers, and annotations. A `proton::delivery` represents +a message being received over a link. The receiver acknowledges the +delivery by accepting or rejecting it. The corresponding message +sender uses a `proton::tracker` to follow the state of the delivery. + +The delivery is *settled* when both ends are done with it. Different +settlement methods give different levels of reliability: +*at-most-once*, *at-least-once*, and *exactly-once*. See "Delivery +Guarantees" below for details. ## Sources and targets @@ -63,6 +66,9 @@ implement a queueless request-response server. ## Delivery guarantees +Proton offers three levels of message delivery guarantee: +*at-most-once*, *at-least-once*, and *exactly-once*. + 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. @@ -72,7 +78,7 @@ 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. +it is delivered multiple times, however. Finally, for *exactly-once*, the receiver accepts the message but doesn't settle it. The sender settles once it is aware that the @@ -103,44 +109,20 @@ conversion between AMQP and C++ data types. There are several ways to manage handlers and AMQP objects, for different types of application. All of them use the same -`proton::messaging_handler` sub-classes so code can be re-used if you +`proton::messaging_handler` subclasses so code can be re-used if you change your approach. -### %proton::container - Easy single-threaded applications +### %proton::default_container - Easy single-threaded applications -`proton::container` is the top level object in a proton application. -Use proton::connection::connect() and proton::container::listen() to +`proton::container` is the top-level object in a proton application. +Use proton::container::connect() and proton::container::listen() to create connections. The container polls multiple connections and calls -protocol events on your `proton::messaging_handler` sub-classes. - -<!-- XXX This is wrong? -The default container implementation is created by -`proton::new_default_container()`. ---> - -You can implement your own container to integrate proton with -arbitrary your own container using the -`proton::io::connection_engine`. - -### %proton::io::connection_engine - Integrating with foreign IO - -The `proton::io::connection_engine` is different from the other proton -APIs. You might think of it as more like an SPI (service provider -interface). - -The engine provides a very low-level way of driving a -`proton::messaging_handler`: You feed raw byte-sequence fragments of -an AMQP-encoded stream to the engine and it converts that into calls -on a proton::handler. The engine provides you with outgoing protocol -stream bytes in return. +protocol events on your `proton::messaging_handler` subclasses. -The engine is deliberately very simple and low level. It does no IO, no -thread-related locking, and is written in simple C++98-compatible code. +The default container implementation is created using +`proton::default_container`. -You can use the engine directly to connect your application to any -kind of IO framework or library, memory-based streams, or any other -source or sink for byte-stream data. +You can implement your own container to integrate proton with any IO +provider using the `proton::io::connection_engine`. -You can also use the engine to build a custom implementation of -`proton::container` so portable proton applications can run without -modification on your platform. +@see @ref io_page http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/docs/mt.md ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/docs/mt.md b/proton-c/bindings/cpp/docs/mt.md index 7c3cf32..1a63ea6 100644 --- a/proton-c/bindings/cpp/docs/mt.md +++ b/proton-c/bindings/cpp/docs/mt.md @@ -1,41 +1,44 @@ -# Multithreaded Proton Applications {#mt_page} - -**Experimental** +# Multithreaded Proton applications {#mt_page} For an example see @ref mt/broker.cpp -Most classes in namespace @ref proton are not thread-safe. Objects belonging -to a single connection (`proton::connection`, `proton::sender`, -`proton::receiver` and so on) *must not* be used concurrently. Objects associated with -*different* connections *can* be used concurrently in separate threads. - -A multi-threaded container calls event-handling functions for each connection -*sequentially* but can process *different* connections concurrently in different -threads. If you use a *separate* `proton::messaging_handler` to for each -connection, then event handling functions can can use their parameters and the -handler's own data members without locks. The handler functions will never be -called concurrently. You can set the handlers for each connection using +Most classes in namespace @ref proton are not thread-safe. Objects +belonging to a single connection (`proton::connection`, +`proton::sender`, `proton::receiver`, and so on) *must not* be used +concurrently. Objects associated with *different* connections *can* be +used concurrently in separate threads. + +A multithreaded container calls event-handling functions for each +connection *sequentially* but can process *different* connections +concurrently in different threads. If you use a *separate* +`proton::messaging_handler` for each connection, then event-handling +functions can can use their parameters and the handler's own data +members without locks. The handler functions will never be called +concurrently. You can set the handlers for each connection using `proton::container::connect()` and `proton::container::listen()`. -The example @ref mt/broker.cpp is a multi-threaded broker using this approach. -It creates a new handler for each incoming connection to manage the state of -that connection's `proton::sender` and `proton::receiver` links. The handler -needs no lock because it only deals with state for one connection. - -The `proton::event_loop` represents the sequence of events associated with a -connection. `proton::event_loop::inject()` allows another thread to "inject" -work to be executed in sequence with the rest of the events so it can operate -safely on data associated with the connection. - -In the @ref mt/broker.cpp example, a queue can receive messages from one -connection but have subscribers on another connection. Subscribers pass a -function object to the queue which uses `proton::event_loop::inject()` to call a -notification callback on the handler for that connection. The callback is -executed in the connection's event-loop so it can use a `proton::sender` object -to send the message safely. - -Note: It is possible to share a single handler between more than one connection. -In that case it *can* be called concurrently on behalf of different connections, so -you will need suitable locking. - -@see @ref io_page - implementing your own container. +The example @ref mt/broker.cpp is a multithreaded broker using this +approach. It creates a new handler for each incoming connection to +manage the state of that connection's `proton::sender` and +`proton::receiver` links. The handler needs no lock because it only +deals with state in the context of one connection. + +The `proton::event_loop` class represents the sequence of events +associated with a connection. `proton::event_loop::inject()` allows +another thread to "inject" work to be executed in sequence with the +rest of the events so it can operate safely on data associated with +the connection. + +In the @ref mt/broker.cpp example, a queue can receive messages from +one connection but have subscribers on another connection. Subscribers +pass a function object to the queue which uses +`proton::event_loop::inject()` to call a notification callback on the +handler for that connection. The callback is executed in the +connection's event loop so it can use a `proton::sender` object to +send the message safely. + +*Note*: It is possible to share a single handler between more than one +connection. In that case it *can* be called concurrently on behalf of +different connections, so you will need suitable locking. + +@see @ref io_page - Implementing your own container. http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/docs/types.md ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/docs/types.md b/proton-c/bindings/cpp/docs/types.md index 7a643bc..6a56be0 100644 --- a/proton-c/bindings/cpp/docs/types.md +++ b/proton-c/bindings/cpp/docs/types.md @@ -29,11 +29,11 @@ proton::decimal32 | proton::DECIMAL32 | 32-bit decimal floating point proton::decimal64 | proton::DECIMAL64 | 64-bit decimal floating point proton::decimal128 | proton::DECIMAL128 | 128-bit decimal floating point proton::uuid | proton::UUID | 128-bit universally-unique identifier -std::string | proton::STRING | UTF-8 encoded unicode string +std::string | proton::STRING | UTF-8 encoded Unicode string proton::symbol | proton::SYMBOL | 7-bit ASCII encoded string proton::binary | proton::BINARY | Variable-length binary data -proton::scalar is a holder that can hold a scalar value of any type. +proton::scalar is a holder that can accept a scalar value of any type. ## Compound types @@ -43,7 +43,7 @@ See below | proton::ARRAY | Sequence of values of the same type See below | proton::LIST | Sequence of values of mixed types See below | proton::MAP | Map of key-value pairs -proton::value is a holder that can hold any AMQP value, scalar, or +proton::value is a holder that can accept any AMQP value, scalar or compound. proton::ARRAY converts to and from C++ sequences: std::vector, @@ -69,8 +69,9 @@ You can decode any AMQP LIST or ARRAY into: ## Include files -You can simply include proton/types.hpp to include all the type definitions and -conversions. Alternatively, you can selectively include only what you need: +You can simply include proton/types.hpp to get all the type +definitions and conversions. Alternatively, you can selectively +include only what you need: - Include proton/types_fwd.hpp: forward declarations for all types. - Include individual `.hpp` files as per the table above. http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/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 7628151..8ec4e47 100644 --- a/proton-c/bindings/cpp/docs/user.doxygen.in +++ b/proton-c/bindings/cpp/docs/user.doxygen.in @@ -43,7 +43,7 @@ ALPHABETICAL_INDEX = NO ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES -PREDEFINED = protected=private PN_CPP_EXTERN= +PREDEFINED = protected=private PN_CPP_EXTERN= PN_CPP_OVERRIDE= EXCLUDE_SYMBOLS = internal internal::* # Configuration options related to warning and progress messages http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/include/proton/codec/amqp_types.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/codec/amqp_types.hpp b/proton-c/bindings/cpp/include/proton/codec/amqp_types.hpp index b245690..5456225 100644 --- a/proton-c/bindings/cpp/include/proton/codec/amqp_types.hpp +++ b/proton-c/bindings/cpp/include/proton/codec/amqp_types.hpp @@ -22,6 +22,9 @@ * */ +/// @cond INTERNAL +/// XXX Remove this entirely + namespace proton { namespace codec { @@ -103,4 +106,6 @@ typedef proton::decimal128 decimal128_type; } // codec } // proton +/// @endcond + #endif // PROTON_CODEC_AMQP_TYPES_HPP http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/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 0d278b7..d904e85 100644 --- a/proton-c/bindings/cpp/include/proton/container.hpp +++ b/proton-c/bindings/cpp/include/proton/container.hpp @@ -122,36 +122,39 @@ class PN_CPP_CLASS_EXTERN container { /// - run() will return in all threads. virtual void stop(const error_condition& err = error_condition()) = 0; - /// Open a connection to `url` and open a sender for `url.path()`. + /// Open a connection and sender for `url`. PN_CPP_EXTERN virtual returned<sender> open_sender(const std::string &url); - /// Open a connection to `url` and open a sender for `url.path()`. + /// Open a connection and sender for `url`. + /// /// Any supplied sender options will override the container's /// template options. PN_CPP_EXTERN virtual returned<sender> open_sender(const std::string &url, const proton::sender_options &o); - /// Open a connection to `url` and open a sender for `url.path()`. + /// Open a connection and sender for `url`. + /// /// Any supplied sender or connection options will override the /// container's template options. virtual returned<sender> open_sender(const std::string &url, const proton::sender_options &o, const connection_options &c) = 0; - /// Open a connection to `url` and open a receiver for - /// `url.path()`. + /// Open a connection and receiver for `url`. PN_CPP_EXTERN virtual returned<receiver> open_receiver(const std::string&url); - /// Open a connection to `url` and open a receiver for - /// `url.path()`. Any supplied receiver options will override the - /// container's template options. + /// Open a connection and receiver for `url`. + /// + /// Any supplied receiver options will override the container's + /// template options. PN_CPP_EXTERN virtual returned<receiver> open_receiver(const std::string&url, const proton::receiver_options &o); - /// Open a connection to `url` and open a receiver for - /// `url.path()`. Any supplied receiver or connection options will - /// override the container's template options. + /// Open a connection and receiver for `url`. + /// + /// Any supplied receiver or connection options will override the + /// container's template options. virtual returned<receiver> open_receiver(const std::string&url, const proton::receiver_options &o, const connection_options &c) = 0; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp b/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp index c99c248..3119804 100644 --- a/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp +++ b/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp @@ -22,9 +22,7 @@ * */ -/// @file -/// -/// Internal: Type traits for mapping between AMQP and C++ types. +/// Type traits for mapping between AMQP and C++ types. /// /// Also provides workarounds for missing type_traits classes on older /// C++ compilers. http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/include/proton/link.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/link.hpp b/proton-c/bindings/cpp/include/proton/link.hpp index a9fb336..40200e8 100644 --- a/proton-c/bindings/cpp/include/proton/link.hpp +++ b/proton-c/bindings/cpp/include/proton/link.hpp @@ -82,10 +82,10 @@ PN_CPP_CLASS_EXTERN link : public internal::object<pn_link_t> , public endpoint /// Credit available on the link. PN_CPP_EXTERN int credit() const; - /// True for a receiver if a drain cycle has been started and the - /// corresponding `on_receiver_drain_finish` event is still - /// pending. True for a sender if the receiver has requested a - /// drain of credit and the sender has unused credit. + /// **Experimental** - True for a receiver if a drain cycle has + /// been started and the corresponding `on_receiver_drain_finish` + /// event is still pending. True for a sender if the receiver has + /// requested a drain of credit and the sender has unused credit. /// /// @see @ref receiver::drain. PN_CPP_EXTERN bool draining(); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/include/proton/messaging_handler.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/messaging_handler.hpp b/proton-c/bindings/cpp/include/proton/messaging_handler.hpp index 04f7c11..cef7328 100644 --- a/proton-c/bindings/cpp/include/proton/messaging_handler.hpp +++ b/proton-c/bindings/cpp/include/proton/messaging_handler.hpp @@ -148,11 +148,12 @@ PN_CPP_CLASS_EXTERN messaging_handler { /// The sending peer settled a transfer. PN_CPP_EXTERN virtual void on_delivery_settle(delivery &d); - /// The receiving peer has requested a drain of remaining credit. + /// **Experimental** - The receiving peer has requested a drain of + /// remaining credit. PN_CPP_EXTERN virtual void on_sender_drain_start(sender &s); - /// The credit outstanding at the time of the call to - /// receiver::drain has been consumed or returned. + /// **Experimental** - The credit outstanding at the time of the + /// call to receiver::drain has been consumed or returned. PN_CPP_EXTERN virtual void on_receiver_drain_finish(receiver &r); /// Fallback error handling. http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/include/proton/receiver.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/receiver.hpp b/proton-c/bindings/cpp/include/proton/receiver.hpp index ebb1391..986765e 100644 --- a/proton-c/bindings/cpp/include/proton/receiver.hpp +++ b/proton-c/bindings/cpp/include/proton/receiver.hpp @@ -65,14 +65,14 @@ PN_CPP_CLASS_EXTERN receiver : public link { /// the drain completes. PN_CPP_EXTERN void add_credit(uint32_t); - /// Commence a drain cycle. If there is positive credit, a - /// request is sent to the sender to immediately use up all of the - /// existing credit balance by sending messages that are - /// immediately available and releasing any unused credit (see - /// sender::return_credit). Throws proton::error if a drain cycle - /// is already in progress. An on_receiver_drain_finish event - /// will be generated when the outstanding drained credit reaches - /// zero. + /// **Experimental** - Commence a drain cycle. If there is + /// positive credit, a request is sent to the sender to + /// immediately use up all of the existing credit balance by + /// sending messages that are immediately available and releasing + /// any unused credit (see sender::return_credit). Throws + /// proton::error if a drain cycle is already in progress. An + /// on_receiver_drain_finish event will be generated when the + /// outstanding drained credit reaches zero. PN_CPP_EXTERN void drain(); /// @cond INTERNAL http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/include/proton/scalar.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/scalar.hpp b/proton-c/bindings/cpp/include/proton/scalar.hpp index eed5255..ab7cb2a 100644 --- a/proton-c/bindings/cpp/include/proton/scalar.hpp +++ b/proton-c/bindings/cpp/include/proton/scalar.hpp @@ -71,6 +71,18 @@ template<class T> T get(const scalar& s) { return internal::get<T>(s); } /// according to `std::is_convertible` /// @related scalar template<class T> T coerce(const scalar& x) { return internal::coerce<T>(x); } + + +/// Coerce the contained value to type T. For example: +/// +/// uint64_t i = get<uint64_t>(x) +/// +/// This will succeed if x contains any numeric value, but may lose +/// precision if it contains a float or double value. +/// +/// @throw conversion_error if the value cannot be converted to T +/// according to `std::is_convertible` +/// @related scalar template<class T> T coerce(scalar& x) { return internal::coerce<T>(x); } } // proton http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/include/proton/sender.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/sender.hpp b/proton-c/bindings/cpp/include/proton/sender.hpp index b422fec..5d34b23 100644 --- a/proton-c/bindings/cpp/include/proton/sender.hpp +++ b/proton-c/bindings/cpp/include/proton/sender.hpp @@ -64,9 +64,10 @@ PN_CPP_CLASS_EXTERN sender : public link { /// Get the target node. PN_CPP_EXTERN class target target() const; - /// Return all unused credit to the receiver in response to a - /// drain request. Has no effect unless there has been a drain - /// request and there is remaining credit to use or return. + /// **Experimental** - Return all unused credit to the receiver in + /// response to a drain request. Has no effect unless there has + /// been a drain request and there is remaining credit to use or + /// return. /// /// @see receiver::drain PN_CPP_EXTERN void return_credit(); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/include/proton/source.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/source.hpp b/proton-c/bindings/cpp/include/proton/source.hpp index 0c0998c..60ff38c 100644 --- a/proton-c/bindings/cpp/include/proton/source.hpp +++ b/proton-c/bindings/cpp/include/proton/source.hpp @@ -35,7 +35,7 @@ namespace proton { class sender; class receiver; -/// The source node is where messages originate. +/// A point of origin for messages. /// /// @see proton::sender, proton::receiver, proton::target class source : public terminus { http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66259238/proton-c/bindings/cpp/include/proton/target.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/target.hpp b/proton-c/bindings/cpp/include/proton/target.hpp index 27be9f2..5ba5281 100644 --- a/proton-c/bindings/cpp/include/proton/target.hpp +++ b/proton-c/bindings/cpp/include/proton/target.hpp @@ -34,7 +34,7 @@ namespace proton { class sender; class receiver; -/// The target is the destination node of a sent or received message. +/// A destination for messages. /// /// @see proton::sender, proton::receiver, proton::target class target : public terminus { --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
