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/09/04 21:14:34 UTC
[7/7] qpid-proton git commit: PROTON-865: C++ reactor binding for
proton.
PROTON-865: C++ reactor binding for proton.
This is a C++ interface to proton, providing an event-driven API similar to the
python reactive API.
Each of the proton "classes" such as pn_link_t, pn_connection_t etc. is
represented by a C++ "facade" class that provides the relevant member
functions. These classes take up no memory, they are actually pointers to the
proton C structs with some casting magic to translate C++ member function calls
into C function calls.
A C++ smart pointer, proton::counted_ptr, automates proton reference
counting. It can be converted automatically to standard C++ shared_ptr,
unique_ptr etc. with the expected semantics.
The goal is to provide very low overhead access to the proton C library with the
convenience and safety of C++. There is no additional memory allocation or
reference counting imposed by the C++ layer. It is possible to mix C and C++
code.
The C++ documentation includes a tutorial and examples similar to the python
tutorial/examples.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/445f8873
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/445f8873
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/445f8873
Branch: refs/heads/master
Commit: 445f8873968e2317218ec348444284a4bd7c8be0
Parents: f37e2af
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Sep 4 15:13:46 2015 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Sep 4 15:13:46 2015 -0400
----------------------------------------------------------------------
CMakeLists.txt | 21 +-
docs/markdown/memory_management.md | 18 +-
examples/CMakeLists.txt | 3 +
examples/cpp/CMakeLists.txt | 55 +
examples/cpp/README.hpp | 120 ++
examples/cpp/broker.cpp | 215 +++
examples/cpp/client.cpp | 96 +
examples/cpp/direct_recv.cpp | 86 +
examples/cpp/direct_send.cpp | 93 +
examples/cpp/encode_decode.cpp | 261 +++
examples/cpp/example_test.py | 228 +++
examples/cpp/helloworld.cpp | 66 +
examples/cpp/helloworld_blocking.cpp | 52 +
examples/cpp/helloworld_direct.cpp | 74 +
examples/cpp/options.hpp | 173 ++
examples/cpp/server.cpp | 86 +
examples/cpp/server_direct.cpp | 105 ++
examples/cpp/simple_recv.cpp | 85 +
examples/cpp/simple_send.cpp | 90 +
examples/cpp/sync_client.cpp | 67 +
examples/go/README.md | 69 -
examples/go/event/broker.go | 255 ---
examples/go/receive.go | 176 --
examples/go/send.go | 158 --
proton-c/CMakeLists.txt | 71 +-
proton-c/bindings/CMakeLists.txt | 175 +-
proton-c/bindings/cpp/CMakeLists.txt | 151 ++
proton-c/bindings/cpp/README.md | 40 +
proton-c/bindings/cpp/docs/CMakeLists.txt | 33 +
proton-c/bindings/cpp/docs/mainpage.md | 123 ++
proton-c/bindings/cpp/docs/tutorial.hpp | 427 +++++
proton-c/bindings/cpp/docs/user.doxygen.in | 1702 ++++++++++++++++++
.../bindings/cpp/include/proton/acceptor.hpp | 43 +
proton-c/bindings/cpp/include/proton/acking.hpp | 50 +
.../cpp/include/proton/blocking_connection.hpp | 62 +
.../cpp/include/proton/blocking_link.hpp | 57 +
.../cpp/include/proton/blocking_receiver.hpp | 62 +
.../cpp/include/proton/blocking_sender.hpp | 50 +
.../bindings/cpp/include/proton/comparable.hpp | 38 +
proton-c/bindings/cpp/include/proton/config.hpp | 57 +
.../bindings/cpp/include/proton/connection.hpp | 81 +
.../bindings/cpp/include/proton/container.hpp | 90 +
.../bindings/cpp/include/proton/counted.hpp | 48 +
.../bindings/cpp/include/proton/counted_ptr.hpp | 117 ++
proton-c/bindings/cpp/include/proton/data.hpp | 130 ++
.../bindings/cpp/include/proton/decoder.hpp | 234 +++
.../bindings/cpp/include/proton/delivery.hpp | 72 +
.../bindings/cpp/include/proton/duration.hpp | 53 +
.../bindings/cpp/include/proton/encoder.hpp | 187 ++
.../bindings/cpp/include/proton/endpoint.hpp | 66 +
proton-c/bindings/cpp/include/proton/error.hpp | 45 +
proton-c/bindings/cpp/include/proton/event.hpp | 69 +
proton-c/bindings/cpp/include/proton/export.hpp | 49 +
proton-c/bindings/cpp/include/proton/facade.hpp | 145 ++
.../bindings/cpp/include/proton/handler.hpp | 61 +
proton-c/bindings/cpp/include/proton/link.hpp | 107 ++
proton-c/bindings/cpp/include/proton/memory.hpp | 33 +
.../bindings/cpp/include/proton/message.hpp | 225 +++
.../cpp/include/proton/messaging_adapter.hpp | 78 +
.../cpp/include/proton/messaging_event.hpp | 108 ++
.../cpp/include/proton/messaging_handler.hpp | 110 ++
.../cpp/include/proton/proton_event.hpp | 296 +++
.../cpp/include/proton/proton_handler.hpp | 86 +
.../bindings/cpp/include/proton/reactor.hpp | 75 +
.../bindings/cpp/include/proton/receiver.hpp | 46 +
proton-c/bindings/cpp/include/proton/sender.hpp | 49 +
.../bindings/cpp/include/proton/session.hpp | 83 +
.../include/proton/sync_request_response.hpp | 63 +
.../bindings/cpp/include/proton/terminus.hpp | 77 +
.../bindings/cpp/include/proton/transport.hpp | 45 +
.../bindings/cpp/include/proton/type_traits.hpp | 118 ++
proton-c/bindings/cpp/include/proton/types.hpp | 248 +++
proton-c/bindings/cpp/include/proton/url.hpp | 128 ++
proton-c/bindings/cpp/src/acceptor.cpp | 30 +
.../bindings/cpp/src/blocking_connection.cpp | 39 +
.../cpp/src/blocking_connection_impl.cpp | 103 ++
.../cpp/src/blocking_connection_impl.hpp | 60 +
proton-c/bindings/cpp/src/blocking_fetcher.cpp | 66 +
proton-c/bindings/cpp/src/blocking_fetcher.hpp | 48 +
proton-c/bindings/cpp/src/blocking_link.cpp | 85 +
proton-c/bindings/cpp/src/blocking_receiver.cpp | 102 ++
proton-c/bindings/cpp/src/blocking_sender.cpp | 68 +
proton-c/bindings/cpp/src/connection.cpp | 82 +
proton-c/bindings/cpp/src/connector.cpp | 62 +
proton-c/bindings/cpp/src/connector.hpp | 58 +
proton-c/bindings/cpp/src/container.cpp | 73 +
proton-c/bindings/cpp/src/container_impl.cpp | 181 ++
proton-c/bindings/cpp/src/container_impl.hpp | 77 +
proton-c/bindings/cpp/src/contexts.cpp | 116 ++
proton-c/bindings/cpp/src/contexts.hpp | 61 +
proton-c/bindings/cpp/src/conversion_test.cpp | 74 +
proton-c/bindings/cpp/src/data.cpp | 134 ++
proton-c/bindings/cpp/src/decoder.cpp | 328 ++++
proton-c/bindings/cpp/src/delivery.cpp | 38 +
proton-c/bindings/cpp/src/duration.cpp | 31 +
proton-c/bindings/cpp/src/encoder.cpp | 135 ++
proton-c/bindings/cpp/src/endpoint.cpp | 38 +
proton-c/bindings/cpp/src/error.cpp | 34 +
proton-c/bindings/cpp/src/event.cpp | 71 +
proton-c/bindings/cpp/src/facade.cpp | 71 +
proton-c/bindings/cpp/src/grep | 47 +
proton-c/bindings/cpp/src/handler.cpp | 35 +
proton-c/bindings/cpp/src/interop_test.cpp | 123 ++
proton-c/bindings/cpp/src/link.cpp | 92 +
proton-c/bindings/cpp/src/message.cpp | 215 +++
proton-c/bindings/cpp/src/messaging_adapter.cpp | 395 ++++
proton-c/bindings/cpp/src/messaging_event.cpp | 150 ++
proton-c/bindings/cpp/src/messaging_handler.cpp | 122 ++
proton-c/bindings/cpp/src/msg.hpp | 58 +
proton-c/bindings/cpp/src/proton_bits.cpp | 56 +
proton-c/bindings/cpp/src/proton_bits.hpp | 45 +
proton-c/bindings/cpp/src/proton_event.cpp | 183 ++
proton-c/bindings/cpp/src/proton_handler.cpp | 73 +
proton-c/bindings/cpp/src/reactor.cpp | 57 +
proton-c/bindings/cpp/src/receiver.cpp | 38 +
proton-c/bindings/cpp/src/sender.cpp | 59 +
proton-c/bindings/cpp/src/session.cpp | 78 +
.../bindings/cpp/src/sync_request_response.cpp | 57 +
proton-c/bindings/cpp/src/terminus.cpp | 68 +
proton-c/bindings/cpp/src/test_bits.hpp | 48 +
proton-c/bindings/cpp/src/transport.cpp | 31 +
proton-c/bindings/cpp/src/types.cpp | 96 +
proton-c/bindings/cpp/src/url.cpp | 114 ++
proton-c/bindings/cpp/src/uuid.cpp | 59 +
proton-c/bindings/cpp/src/uuid.hpp | 39 +
proton-c/bindings/go/README.md | 5 -
proton-c/docs/api/user.doxygen.in | 4 +-
proton-c/include/proton/codec.h | 20 +-
proton-c/include/proton/event.h | 3 +-
proton-c/include/proton/handlers.h | 1 -
proton-c/include/proton/reactor.h | 1 -
proton-c/include/proton/selectable.h | 1 +
proton-c/src/codec/codec.c | 10 +-
proton-c/src/windows/io.c | 13 +-
134 files changed, 13050 insertions(+), 826 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cfe5566..5ef9f56 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,16 +20,15 @@ cmake_minimum_required (VERSION 2.6)
project (Proton C)
+# Enable C++ now for examples and bindings subdirectories, but make it optional.
+enable_language(CXX OPTIONAL)
+
if (MSVC)
# No C99 capability, use C++
set(DEFAULT_BUILD_WITH_CXX ON)
endif (MSVC)
option(BUILD_WITH_CXX "Compile Proton using C++" ${DEFAULT_BUILD_WITH_CXX})
-if (BUILD_WITH_CXX)
- enable_language (CXX)
-endif (BUILD_WITH_CXX)
-
if (CMAKE_CONFIGURATION_TYPES)
# There is no single "build type"...
message(STATUS "Build types are ${CMAKE_CONFIGURATION_TYPES}")
@@ -140,7 +139,21 @@ if (BUILD_JAVA)
add_subdirectory(proton-j)
endif()
+# Check for valgrind here so tests under proton-c/ and examples/ can use it.
+find_program(VALGRIND_EXE valgrind DOC "Location of the valgrind program")
+option(ENABLE_VALGRIND "Use valgrind to detect run-time problems" ON)
+if (ENABLE_VALGRIND)
+ if (NOT VALGRIND_EXE)
+ message(STATUS "Can't locate the valgrind command; no run-time error detection")
+ else ()
+ set (VALGRIND_ENV "VALGRIND=${VALGRIND_EXE}")
+ endif ()
+endif (ENABLE_VALGRIND)
+
+mark_as_advanced (VALGRIND_EXE)
+
add_subdirectory(proton-c)
+add_subdirectory(examples)
install (FILES LICENSE README.md TODO
DESTINATION ${PROTON_SHARE})
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/docs/markdown/memory_management.md
----------------------------------------------------------------------
diff --git a/docs/markdown/memory_management.md b/docs/markdown/memory_management.md
index e81318f..5a70911 100644
--- a/docs/markdown/memory_management.md
+++ b/docs/markdown/memory_management.md
@@ -1,7 +1,3 @@
-
-*Warning*: contains remarks about unreleased (but design-complete as far as the
-remarks are concerned) C++ and Go bindings.
-
Proton memory mangement
=======================
@@ -69,9 +65,9 @@ The proton C API has standard reference counting rules (but see [1] below)
- A pointer *returned* by a `pn_` function is either *borrowed* by the caller,
or the caller *owns* a reference (the API doc says which.)
-- The owner of a reference must call `pn_object_decref()` exactly once to
+- The owner of a reference must call `pn_decref()` exactly once to
release it.
-- To keep a borrowed pointer, call `pn_object_incref()`. This adds a new
+- To keep a borrowed pointer, call `pn_incref()`. This adds a new
reference, which you now own.
- A pointer *passed* to a `pn_` function has no change of ownership. If you
owned a reference you still do, if you didn't you still don't.
@@ -80,7 +76,7 @@ The proton C API has standard reference counting rules (but see [1] below)
A *borrowed* pointer is valid within some scope (typically the scope of an event
handling function) but beyond that scope you cannot assume it is valid unless
-you make a new reference with `pn_object_incref`. The API documentation for the
+you make a new reference with `pn_incref`. The API documentation for the
function that returned the pointer should tell you what the scope is.
There are "container" relationships in proton: e.g. a connection contains
@@ -96,11 +92,11 @@ container are released [1]. This is useful for bindings to langauges with
objects in memory for as long as any binding object needs them.
For example: if you call `pn_message()` then you *own* a reference to the
-newly-created `pn_message_t` and you must call `pn_object_decref` when you are
+newly-created `pn_message_t` and you must call `pn_decref` when you are
done [2]. If you call `pn_event_link()` in an event handler then you get a
*borrowed* reference to the link. You can use it in the scope of the event
-handler, but if you want to save it for later you must call `pn_object_incref`
-to add a reference and of course call `pn_object_decref` when you are done with
+handler, but if you want to save it for later you must call `pn_incref`
+to add a reference and of course call `pn_decref` when you are done with
that reference.
[1] *Internally* the proton library plays tricks with reference counts to
@@ -111,7 +107,7 @@ implementation of the proton C library itself you may need to learn more, ask on
proton@qpid.apache.org.
[2] Actually if you call `pn_message()` then you must *either* call
-`pn_object_decref()` *or* `pn_message_free()`, definitely not both. It is
+`pn_decref()` *or* `pn_message_free()`, definitely not both. It is
possible to mix reference couting and 'free' style memory management in the same
codebase (`free` is sort-of an alias for `decref`) but it is probably not a good
idea.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index feac758..5724e59 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -21,3 +21,6 @@ set (Proton_DIR ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_subdirectory(c/messenger)
+if (BUILD_CPP)
+ add_subdirectory(cpp)
+endif()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
new file mode 100644
index 0000000..77cc9c5
--- /dev/null
+++ b/examples/cpp/CMakeLists.txt
@@ -0,0 +1,55 @@
+#
+# 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_directories(
+ "${CMAKE_SOURCE_DIR}/proton-c/include"
+ "${CMAKE_SOURCE_DIR}/proton-c/bindings/cpp/include")
+
+foreach(example
+ broker
+ helloworld
+ helloworld_blocking
+ helloworld_direct
+ simple_recv
+ simple_send
+ direct_recv
+ direct_send
+ sync_client
+ client
+ server
+ server_direct
+ encode_decode)
+ add_executable(${example} ${example}.cpp)
+ target_link_libraries(${example} qpid-proton-cpp)
+ set_source_files_properties(${example}.cpp PROPERTIES COMPILE_FLAGS "${CXX_WARNING_FLAGS}")
+endforeach()
+
+set(env_py "${CMAKE_SOURCE_DIR}/proton-c/env.py")
+set(test_bin_dir "$<TARGET_FILE_DIR:broker>")
+if (WIN32)
+ # Ignore existing path (usualy containting spaces, escape chars).
+ # Choose just enough path for Windows, ';' separated.
+ set(test_path "${test_bin_dir}" "$<TARGET_FILE_DIR:qpid-proton>" "$<TARGET_FILE_DIR:qpid-proton-cpp>")
+else(WIN32)
+ # ':' separated path with test_bin_dir first.
+ set(test_path "${test_bin_dir}:$ENV{PATH}")
+endif(WIN32)
+
+add_test(NAME cpp_example_test
+ COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}" "PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}" ${VALGRIND_ENV} ${PYTHON_EXECUTABLE} -m unittest -v example_test)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/README.hpp
----------------------------------------------------------------------
diff --git a/examples/cpp/README.hpp b/examples/cpp/README.hpp
new file mode 100644
index 0000000..d2a51eb
--- /dev/null
+++ b/examples/cpp/README.hpp
@@ -0,0 +1,120 @@
+// Examples overview.
+//
+// For a better overview, see the tutorial in the generated documentation.
+// In your build directory do:
+// make docs-cpp
+// then open proton-c/bindings/cpp/docs/html/tutorial.html in your browser.
+//
+
+// DEVELOPER NOTE: if you are adding or modifying examples you should keep this
+// file and ../proton-c/bindings/cpp/docs/tutorial.hpp up to date.
+
+/** \example 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.
+
+*/
+
+/** \example helloworld.cpp
+
+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.
+
+*/
+
+/** \example helloworld_direct.cpp
+
+A variant of the basic helloworld example, that does not use an
+intermediary, but listens for incoming connections itself. It
+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.
+
+*/
+
+/** \example 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.
+
+*/
+
+/** \example 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 127.0.0.1:5672.
+
+*/
+
+/** \example simple_recv.cpp
+
+Subscribes to the 'examples' node on an intermediary accessible
+on 127.0.0.1:5672. Simply prints out the body of received messages.
+
+*/
+
+/** \example 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`.
+
+*/
+
+/** \example 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`.
+
+*/
+
+/** \example encode_decode.cpp
+
+Shows how C++ data types can be converted to and from AMQP types.
+
+*/
+
+/** \example client.cpp
+
+The client part of a request-response example. Sends requests and
+prints out responses. Requires an intermediary that supports the AMQP
+1.0 dynamic nodes on which the responses are received. The requests
+are sent through the 'examples' node.
+
+*/
+
+/** \example server.cpp
+
+The server part of a request-response example, that receives requests
+via the examples node, converts the body to uppercase and sends the
+result back to the indicated reply address.
+
+*/
+
+/** \example server_direct.cpp
+
+A variant of the server part of a request-response example, that
+accepts incoming connections and does not need an intermediary. Much
+like the original server, it receives incoming requests, converts the
+body to uppercase and sends the result back to the indicated reply
+address. Can be used in conjunction with any of the client
+alternatives.
+
+*/
+
+/** \example sync_client.cpp
+
+A variant of the client part, that uses a blocking/synchronous style
+instead of the reactive/asynchronous style.
+
+*/
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
new file mode 100644
index 0000000..7f32650
--- /dev/null
+++ b/examples/cpp/broker.cpp
@@ -0,0 +1,215 @@
+/*
+ *
+ * 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 "options.hpp"
+
+#include "proton/acceptor.hpp"
+#include "proton/container.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/url.hpp"
+
+#include <iostream>
+#include <sstream>
+#include <deque>
+#include <map>
+#include <list>
+#include <string>
+
+class queue {
+ public:
+ bool dynamic;
+ typedef std::deque<proton::message_value> message_queue;
+ typedef std::list<proton::counted_ptr<proton::sender> > sender_list;
+ message_queue messages;
+ sender_list consumers;
+
+ queue(bool dyn = false) : dynamic(dyn) {}
+
+ void subscribe(proton::sender &c) {
+ consumers.push_back(c.ptr());
+ }
+
+ bool unsubscribe(proton::sender &c) {
+ consumers.remove(c.ptr());
+ return (consumers.size() == 0 && (dynamic || messages.size() == 0));
+ }
+
+ void publish(const proton::message_value &m) {
+ messages.push_back(m);
+ dispatch(0);
+ }
+
+ void dispatch(proton::sender *s) {
+ while (deliver_to(s)) {}
+ }
+
+ bool deliver_to(proton::sender *consumer) {
+ // deliver to single consumer if supplied, else all consumers
+ int count = consumer ? 1 : consumers.size();
+ if (!count) return false;
+ bool result = false;
+ sender_list::iterator it = consumers.begin();
+ if (!consumer && count)
+ consumer = it->get();
+
+ while (messages.size()) {
+ if (consumer->credit()) {
+ consumer->send(messages.front());
+ messages.pop_front();
+ result = true;
+ }
+ if (--count)
+ it++;
+ else
+ return result;
+ }
+ return false;
+ }
+};
+
+class broker : public proton::messaging_handler {
+ private:
+ typedef std::map<std::string, queue *> queue_map;
+ proton::url url;
+ queue_map queues;
+ uint64_t queue_count; // Use to generate unique queue IDs.
+
+ public:
+
+ broker(const proton::url &u) : url(u), queue_count(0) {}
+
+ void on_start(proton::event &e) {
+ e.container().listen(url);
+ std::cout << "broker listening on " << url << std::endl;
+ }
+
+ class queue &get_queue(std::string &address) {
+ queue_map::iterator it = queues.find(address);
+ if (it == queues.end()) {
+ queues[address] = new queue();
+ return *queues[address];
+ }
+ else {
+ return *it->second;
+ }
+ }
+
+ std::string queue_name() {
+ std::ostringstream os;
+ os << "q" << queue_count++;
+ return os.str();
+ }
+
+ void on_link_opening(proton::event &e) {
+ proton::link& lnk = e.link();
+ if (lnk.is_sender()) {
+ proton::sender &sender(lnk.sender());
+ proton::terminus &remote_source(lnk.remote_source());
+ if (remote_source.is_dynamic()) {
+ std::string address = queue_name();
+ lnk.source().address(address);
+ 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;
+ }
+ }
+ }
+ else {
+ std::string address = lnk.remote_target().address();
+ if (!address.empty())
+ lnk.target().address(address);
+ std::cout << "broker incoming link to " << address << std::endl;
+ }
+ }
+
+ void unsubscribe (proton::sender &lnk) {
+ std::string address = lnk.source().address();
+ queue_map::iterator it = queues.find(address);
+ if (it != queues.end() && it->second->unsubscribe(lnk)) {
+ delete it->second;
+ queues.erase(it);
+ }
+ }
+
+ void on_link_closing(proton::event &e) {
+ proton::link &lnk = e.link();
+ if (lnk.is_sender()) {
+ unsubscribe(lnk.sender());
+ }
+ }
+
+ void on_connection_closing(proton::event &e) {
+ remove_stale_consumers(e.connection());
+ }
+
+ void on_disconnected(proton::event &e) {
+ remove_stale_consumers(e.connection());
+ }
+
+ void remove_stale_consumers(proton::connection &connection) {
+ proton::link *l = connection.link_head(proton::endpoint::REMOTE_ACTIVE);
+ while (l) {
+ if (l->is_sender()) {
+ unsubscribe(l->sender());
+ }
+ l = l->next(proton::endpoint::REMOTE_ACTIVE);
+ }
+ }
+
+ void on_sendable(proton::event &e) {
+ proton::link& lnk = e.link();
+ std::string addr = lnk.source().address();
+ proton::sender &s(lnk.sender());
+ get_queue(addr).dispatch(&s);
+ }
+
+ void on_message(proton::event &e) {
+ std::string addr = e.link().target().address();
+ proton::message_value msg = e.message();
+ get_queue(addr).publish(msg);
+ }
+};
+
+int main(int argc, char **argv) {
+ // Command line options
+ proton::url url("0.0.0.0");
+ options opts(argc, argv);
+ opts.add_value(url, 'a', "address", "listen on URL", "URL");
+ try {
+ opts.parse();
+ broker broker(url);
+ proton::container(broker).run();
+ return 0;
+ } catch (const bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/client.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/client.cpp b/examples/cpp/client.cpp
new file mode 100644
index 0000000..21c83f8
--- /dev/null
+++ b/examples/cpp/client.cpp
@@ -0,0 +1,96 @@
+/*
+ *
+ * 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 "options.hpp"
+#include "proton/container.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/connection.hpp"
+
+#include <iostream>
+#include <vector>
+
+class client : public proton::messaging_handler {
+ private:
+ proton::url url;
+ std::vector<std::string> requests;
+ proton::counted_ptr<proton::sender> sender;
+ proton::counted_ptr<proton::receiver> receiver;
+
+ public:
+ client(const proton::url &u, const std::vector<std::string>& r) : url(u), requests(r) {}
+
+ void on_start(proton::event &e) {
+ sender = e.container().create_sender(url).ptr();
+ // Create a receiver with a dynamically chosen unique address.
+ receiver = sender->connection().create_receiver("", true/*dynamic*/).ptr();
+ }
+
+ void send_request() {
+ proton::message_value req;
+ req.body(requests.front());
+ req.reply_to(receiver->remote_source().address());
+ sender->send(req);
+ }
+
+ void on_link_opened(proton::event &e) {
+ if (&e.link() == receiver.get())
+ send_request();
+ }
+
+ void on_message(proton::event &e) {
+ if (requests.empty()) return; // Spurious extra message!
+ proton::message& response = e.message();
+ std::cout << '"' << requests.front() << '"' << " => " << response.body() << std::endl;
+ requests.erase(requests.begin());
+ if (!requests.empty()) {
+ send_request();
+ } else {
+ e.connection().close();
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ // Command line options
+ proton::url url("127.0.0.1:5672/examples");
+ options opts(argc, argv);
+ opts.add_value(url, 'a', "address", "connect and send to URL", "URL");
+
+ try {
+ opts.parse();
+
+ std::vector<std::string> requests;
+ requests.push_back("Twas brillig, and the slithy toves");
+ requests.push_back("Did gire and gymble in the wabe.");
+ requests.push_back("All mimsy were the borogroves,");
+ requests.push_back("And the mome raths outgrabe.");
+
+ client c(url, requests);
+ proton::container(c).run();
+
+ return 0;
+ } catch (const bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/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..b6e0e9e
--- /dev/null
+++ b/examples/cpp/direct_recv.cpp
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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 "options.hpp"
+
+#include "proton/container.hpp"
+#include "proton/acceptor.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/link.hpp"
+#include "proton/url.hpp"
+
+#include <iostream>
+#include <map>
+
+class direct_recv : public proton::messaging_handler {
+ private:
+ proton::url url;
+ int expected;
+ int received;
+ proton::counted_ptr<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).ptr();
+ std::cout << "direct_recv listening on " << url << std::endl;
+ }
+
+ void on_message(proton::event &e) {
+ proton::message& msg = e.message();
+ proton::data_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();
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ // Command line options
+ std::string address("127.0.0.1:5672/examples");
+ int message_count = 100;
+ options opts(argc, argv);
+ opts.add_value(address, 'a', "address", "listen and receive on URL", "URL");
+ opts.add_value(message_count, 'm', "messages", "receive COUNT messages", "COUNT");
+ try {
+ opts.parse();
+ direct_recv recv(address, message_count);
+ proton::container(recv).run();
+ return 0;
+ } catch (const bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
+
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/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..02bc372
--- /dev/null
+++ b/examples/cpp/direct_send.cpp
@@ -0,0 +1,93 @@
+/*
+ *
+ * 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 "options.hpp"
+
+#include "proton/acceptor.hpp"
+#include "proton/connection.hpp"
+#include "proton/container.hpp"
+#include "proton/messaging_handler.hpp"
+
+#include <iostream>
+#include <map>
+
+class simple_send : public proton::messaging_handler {
+ private:
+ proton::url url;
+ int sent;
+ int confirmed;
+ int total;
+ proton::counted_ptr<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).ptr();
+ 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_value msg;
+ msg.id(proton::data_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;
+ }
+};
+
+int main(int argc, char **argv) {
+ // Command line options
+ std::string address("127.0.0.1:5672/examples");
+ int message_count = 100;
+ options opts(argc, argv);
+ opts.add_value(address, 'a', "address", "listen and send on URL", "URL");
+ opts.add_value(message_count, 'm', "messages", "send COUNT messages", "COUNT");
+ try {
+ opts.parse();
+ simple_send send(address, message_count);
+ proton::container(send).run();
+ return 0;
+ } catch (const bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/encode_decode.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/encode_decode.cpp b/examples/cpp/encode_decode.cpp
new file mode 100644
index 0000000..5657e73
--- /dev/null
+++ b/examples/cpp/encode_decode.cpp
@@ -0,0 +1,261 @@
+/*
+ * 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/data.hpp>
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <vector>
+
+using namespace std;
+
+// Examples of how to use the encoder and decoder to create and examine AMQP values.
+//
+
+// Print is defined at the end as an example of how to query and extract complex
+// values in terms of their simple components.
+void print(proton::data&);
+
+// Inserting and extracting simple C++ values.
+void simple_insert_extract() {
+ cout << endl << "== Simple values: int, string, bool" << endl;
+ proton::data_value dv;
+ dv.encoder() << 42 << "foo" << true;
+ print(dv);
+ int i;
+ string s;
+ bool b;
+ dv.decoder().rewind();
+ dv.decoder() >> i >> s >> b;
+ cout << "Extracted: " << i << ", " << s << ", " << b << endl;
+ // Encode and decode as AMQP
+ string amqp_data = dv.encoder().encode();
+ cout << "Encoded as AMQP in " << amqp_data.size() << " bytes" << endl;
+ proton::data_value dt2;
+ dt2.decoder().decode(amqp_data);
+ dt2.decoder() >> i >> s >> b;
+ cout << "Decoded: " << i << ", " << s << ", " << b << endl;
+}
+
+// Inserting values as a specific AMQP type
+void simple_insert_extract_exact_type() {
+ proton::data_value dv;
+ cout << endl << "== Specific AMQP types: byte, long, symbol" << endl;
+ dv.encoder() << proton::amqp_byte('x') << proton::amqp_long(123456789123456789) << proton::amqp_symbol("bar");
+ print(dv);
+ dv.decoder().rewind();
+ // Check that we encoded the correct types, but note that decoding will
+ // still convert to standard C++ types, in particular any AMQP integer type
+ // can be converted to a long-enough C++ integer type..
+ int64_t i1, i2;
+ string s;
+ dv.decoder() >> i1 >> i2 >> s;
+ cout << "Extracted (with conversion) " << i1 << ", " << i2 << ", " << s << endl;
+
+ // Now use the as() function to fail unless we extract the exact AMQP type expected.
+ dv.decoder().rewind(); // amqp_byte(1) << amqp_long(2) << amqp_symbol("bar");
+ proton::amqp_long l;
+ // Fails, extracting amqp_byte as amqp_long
+ try { dv.decoder() >> proton::as<proton::LONG>(l); throw logic_error("expected error"); } catch (proton::decode_error) {}
+ proton::amqp_byte b;
+ dv.decoder() >> proton::as<proton::BYTE>(b) >> proton::as<proton::LONG>(l); // OK, extract amqp_byte as amqp_byte, amqp_long as amqp_long.
+ string str;
+ // Fails, extracting amqp_symbol as amqp_string.
+ try { dv.decoder() >> proton::as<proton::STRING>(str); throw logic_error("expected error"); } catch (proton::decode_error) {}
+ dv.decoder() >> proton::as<proton::SYMBOL>(str); // OK, extract amqp_symbol as amqp_symbol
+ cout << "Extracted (exact) " << b << ", " << l << ", " << str << endl;
+}
+
+// Some helper templates to print map and vector results.
+namespace std {
+template<class T, class U> ostream& operator<<(ostream& o, const pair<T,U>& p) {
+ return o << p.first << ":" << p.second;
+}
+template<class T> ostream& operator<<(ostream& o, const vector<T>& v) {
+ o << "[ ";
+ ostream_iterator<T> oi(o, " ");
+ copy(v.begin(), v.end(), oi);
+ return o << "]";
+}
+template<class K, class T> ostream& operator<<(ostream& o, const map<K, T>& m) {
+ o << "{ ";
+ ostream_iterator<pair<K,T> > oi(o, " ");
+ copy(m.begin(), m.end(), oi);
+ return o << "}";
+}
+}
+
+// Insert/extract C++ containers.
+void insert_extract_containers() {
+ cout << endl << "== Array, list and map." << endl;
+
+ vector<int> a;
+ a.push_back(1);
+ a.push_back(2);
+ a.push_back(3);
+ vector<int> l;
+ l.push_back(4);
+ l.push_back(5);
+ map<string, int> m;
+ m["one"] = 1;
+ m["two"] = 2;
+
+ proton::data_value dv;
+ dv.encoder() << proton::as<proton::ARRAY>(a) << proton::as<proton::LIST>(l) << proton::as<proton::MAP>(m);
+ print(dv);
+
+ vector<int> a1, l1;
+ map<string, int> m1;
+ dv.decoder().rewind();
+ dv.decoder() >> proton::as<proton::ARRAY>(a1) >> proton::as<proton::LIST>(l1) >> proton::as<proton::MAP>(m1);
+ cout << "Extracted: " << a1 << ", " << l1 << ", " << m1 << endl;
+}
+
+// Containers with mixed types, use value to represent arbitrary AMQP types.
+void mixed_containers() {
+ cout << endl << "== List and map of mixed type values." << endl;
+ vector<proton::data_value> l;
+ l.push_back(proton::data_value(42));
+ l.push_back(proton::data_value(proton::amqp_string("foo")));
+ map<proton::data_value, proton::data_value> m;
+ m[proton::data_value("five")] = proton::data_value(5);
+ m[proton::data_value(4)] = proton::data_value("four");
+ proton::data_value dv;
+ dv.encoder() << proton::as<proton::LIST>(l) << proton::as<proton::MAP>(m);
+ print(dv);
+
+ vector<proton::data_value> l1;
+ map<proton::data_value, proton::data_value> m1;
+ dv.decoder().rewind();
+ dv.decoder() >> proton::as<proton::LIST>(l1) >> proton::as<proton::MAP>(m1);
+ cout << "Extracted: " << l1 << ", " << m1 << endl;
+}
+
+// Insert using stream operators (see print_next for example of extracting with stream ops.)
+void insert_extract_stream_operators() {
+ cout << endl << "== Insert with stream operators." << endl;
+ proton::data_value dv;
+ // Note: array elements must be encoded with the exact type, they are not
+ // automaticlly converted. Mismatched types for array elements will not
+ // be detected until dv.encode() is called.
+ dv.encoder() << proton::start::array(proton::INT) << proton::amqp_int(1) << proton::amqp_int(2) << proton::amqp_int(3) << proton::finish();
+ print(dv);
+
+ dv.clear();
+ dv.encoder() << proton::start::list() << proton::amqp_int(42) << false << proton::amqp_symbol("x") << proton::finish();
+ print(dv);
+
+ dv.clear();
+ dv.encoder() << proton::start::map() << "k1" << proton::amqp_int(42) << proton::amqp_symbol("k2") << false << proton::finish();
+ print(dv);
+}
+
+int main(int, char**) {
+ try {
+ simple_insert_extract();
+ simple_insert_extract_exact_type();
+ insert_extract_containers();
+ mixed_containers();
+ insert_extract_stream_operators();
+ return 0;
+ } catch (const exception& e) {
+ cerr << endl << "error: " << e.what() << endl;
+ }
+ return 1;
+}
+
+// print_next prints the next value from values by recursively descending into complex values.
+//
+// NOTE this is for example puroses only: There is a built in ostream operator<< for values.
+//
+//
+void print_next(proton::data& dv) {
+ proton::type_id type = dv.type();
+ proton::start s;
+ switch (type) {
+ case proton::ARRAY: {
+ dv.decoder() >> s;
+ cout << "array<" << s.element;
+ if (s.is_described) {
+ cout << ", descriptor=";
+ print_next(dv);
+ }
+ cout << ">[";
+ for (size_t i = 0; i < s.size; ++i) {
+ if (i) cout << ", ";
+ print_next(dv);
+ }
+ cout << "]";
+ dv.decoder() >> proton::finish();
+ break;
+ }
+ case proton::LIST: {
+ dv.decoder() >> s;
+ cout << "list[";
+ for (size_t i = 0; i < s.size; ++i) {
+ if (i) cout << ", ";
+ print_next(dv);
+ }
+ cout << "]";
+ dv.decoder() >> proton::finish();
+ break;
+ }
+ case proton::MAP: {
+ dv.decoder() >> s;
+ cout << "map{";
+ for (size_t i = 0; i < s.size/2; ++i) {
+ if (i) cout << ", ";
+ print_next(dv);
+ cout << ":"; // key:value
+ print_next(dv);
+ }
+ cout << "}";
+ dv.decoder() >> proton::finish();
+ break;
+ }
+ case proton::DESCRIBED: {
+ dv.decoder() >> s;
+ cout << "described(";
+ print_next(dv); // Descriptor
+ print_next(dv); // value
+ dv.decoder() >> proton::finish();
+ break;
+ }
+ default:
+ // A simple type. We could continue the switch for all AMQP types but
+ // instead we us the `value` type which can hold and print any AMQP
+ // value.
+ proton::data_value v;
+ dv.decoder() >> v;
+ cout << type << "(" << v << ")";
+ }
+}
+
+// Print all the values with print_next
+void print(proton::data& dv) {
+ dv.decoder().rewind();
+ cout << "Values: ";
+ while (dv.decoder().more()) {
+ print_next(dv);
+ if (dv.decoder().more()) cout << ", ";
+ }
+ cout << endl;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
new file mode 100644
index 0000000..7922deb
--- /dev/null
+++ b/examples/cpp/example_test.py
@@ -0,0 +1,228 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+# This is a test script to run the examples and verify that they behave as expected.
+
+import unittest
+import os, sys, socket, time
+from random import randrange
+from subprocess import Popen, PIPE, STDOUT
+import platform
+
+def cmdline(*args):
+ """Adjust executable name args[0] for windows and/or valgrind"""
+ args = list(args)
+ if platform.system() == "Windows":
+ args[0] += ".exe"
+ else:
+ args[0] = "./" + args[0]
+ if "VALGRIND" in os.environ and os.environ["VALGRIND"]:
+ args = [os.environ["VALGRIND"], "-q"] + args
+ return args
+
+def background(*args):
+ """Run executable in the backround, return the popen"""
+ p = Popen(cmdline(*args), stdout=PIPE, stderr=sys.stderr)
+ p.args = args # Save arguments for debugging output
+ return p
+
+def verify(p):
+ """Wait for executable to exit and verify status."""
+ try:
+ out, err = p.communicate()
+ except Exception as e:
+ raise Exception("Error running %s: %s", p.args, e)
+ if p.returncode:
+ raise Exception("""%s exit code %s
+vvvvvvvvvvvvvvvv
+%s
+^^^^^^^^^^^^^^^^
+""" % (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."""
+ # TODO 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"""
+
+ @classmethod
+ def get(cls):
+ if not hasattr(cls, "_broker"):
+ cls._broker = Broker()
+ return cls._broker
+
+ @classmethod
+ def stop(cls):
+ if cls.get() and cls._broker.process:
+ cls._broker.process.kill()
+ cls._broker = None
+
+ def __init__(self):
+ self.addr = pick_addr()
+ cmd = cmdline("broker", "-a", self.addr)
+ try:
+ self.process = Popen(cmd, stdout=NULL, stderr=sys.stderr)
+ wait_addr(self.addr)
+ self.addr += "/examples"
+ except Exception as e:
+ raise Exception("Error running %s: %s", cmd, e)
+
+class ExampleTest(unittest.TestCase):
+ """Run the examples, verify they behave as expected."""
+
+ @classmethod
+ def tearDownClass(self):
+ Broker.stop()
+
+ def test_helloworld(self):
+ b = Broker.get()
+ hw = execute("helloworld", b.addr)
+ self.assertEqual('"Hello World!"\n', hw)
+
+ def test_helloworld_blocking(self):
+ b = Broker.get()
+ hw = execute("helloworld_blocking", b.addr, b.addr)
+ self.assertEqual('"Hello World!"\n', hw)
+
+ def test_helloworld_direct(self):
+ addr = pick_addr()
+ hw = execute("helloworld_direct", addr)
+ self.assertEqual('"Hello World!"\n', hw)
+
+ def test_simple_send_recv(self):
+ b = Broker.get()
+ send = execute("simple_send", "-a", b.addr)
+ self.assertEqual("all messages confirmed\n", send)
+ 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)
+
+ 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))
+
+ CLIENT_EXPECT=""""Twas brillig, and the slithy toves" => "TWAS BRILLIG, AND THE SLITHY TOVES"
+"Did gire and gymble in the wabe." => "DID GIRE AND GYMBLE IN THE WABE."
+"All mimsy were the borogroves," => "ALL MIMSY WERE THE BOROGROVES,"
+"And the mome raths outgrabe." => "AND THE MOME RATHS OUTGRABE."
+"""
+ def test_simple_recv_send(self):
+ # Start receiver first, then run sender"""
+ b = Broker.get()
+ 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_request_response(self):
+ b = Broker.get()
+ server = background("server", "-a", b.addr)
+ try:
+ self.assertEqual(execute("client", "-a", b.addr), self.CLIENT_EXPECT)
+ finally:
+ server.kill()
+
+ def test_sync_request_response(self):
+ b = Broker.get()
+ server = background("server", "-a", b.addr)
+ try:
+ self.assertEqual(execute("sync_client", "-a", b.addr), self.CLIENT_EXPECT)
+ finally:
+ server.kill()
+
+ def test_request_response_direct(self):
+ addr = pick_addr()
+ server = background("server_direct", "-a", addr+"/examples")
+ wait_addr(addr)
+ try:
+ self.assertEqual(execute("client", "-a", addr+"/examples"), self.CLIENT_EXPECT)
+ finally:
+ server.kill()
+
+ def test_encode_decode(self):
+ expect="""
+== Simple values: int, string, bool
+Values: int(42), string("foo"), bool(true)
+Extracted: 42, foo, 1
+Encoded as AMQP in 8 bytes
+Decoded: 42, foo, 1
+
+== Specific AMQP types: byte, long, symbol
+Values: byte(120), long(123456789123456789), symbol(:bar)
+Extracted (with conversion) 120, 123456789123456789, bar
+Extracted (exact) x, 123456789123456789, bar
+
+== Array, list and map.
+Values: array<int>[int(1), int(2), int(3)], list[int(4), int(5)], map{string("one"):int(1), string("two"):int(2)}
+Extracted: [ 1 2 3 ], [ 4 5 ], { one:1 two:2 }
+
+== List and map of mixed type values.
+Values: list[int(42), string("foo")], map{int(4):string("four"), string("five"):int(5)}
+Extracted: [ 42 "foo" ], { 4:"four" "five":5 }
+
+== Insert with stream operators.
+Values: array<int>[int(1), int(2), int(3)]
+Values: list[int(42), bool(false), symbol(:x)]
+Values: map{string("k1"):int(42), symbol(:"k2"):bool(false)}
+"""
+ self.maxDiff = None
+ self.assertEqual(expect, execute("encode_decode"))
+if __name__ == "__main__":
+ unittest.main()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/helloworld.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/helloworld.cpp b/examples/cpp/helloworld.cpp
new file mode 100644
index 0000000..bbb5330
--- /dev/null
+++ b/examples/cpp/helloworld.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * 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/url.hpp"
+
+#include <iostream>
+
+class hello_world : public proton::messaging_handler {
+ private:
+ proton::url url;
+
+ public:
+
+ hello_world(const proton::url& u) : url(u) {}
+
+ void on_start(proton::event &e) {
+ proton::connection& conn = e.container().connect(url);
+ conn.create_receiver(url.path());
+ conn.create_sender(url.path());
+ }
+
+ void on_sendable(proton::event &e) {
+ proton::message_value m;
+ m.body("Hello World!");
+ e.sender().send(m);
+ e.sender().close();
+ }
+
+ void on_message(proton::event &e) {
+ proton::data& body(e.message().body());
+ std::cout << body << std::endl;
+ e.connection().close();
+ }
+};
+
+int main(int argc, char **argv) {
+ try {
+ std::string url = argc > 1 ? argv[1] : "127.0.0.1:5672/examples";
+ hello_world hw(url);
+ proton::container(hw).run();
+ return 0;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/helloworld_blocking.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/helloworld_blocking.cpp b/examples/cpp/helloworld_blocking.cpp
new file mode 100644
index 0000000..49094a3
--- /dev/null
+++ b/examples/cpp/helloworld_blocking.cpp
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/messaging_handler.hpp"
+#include "proton/blocking_connection.hpp"
+#include "proton/blocking_sender.hpp"
+#include "proton/blocking_receiver.hpp"
+#include "proton/duration.hpp"
+
+#include <iostream>
+
+int main(int argc, char **argv) {
+ try {
+ proton::url url(argc > 1 ? argv[1] : "127.0.0.1:5672/examples");
+ proton::blocking_connection conn(url);
+ proton::blocking_receiver receiver(conn, url.path());
+ proton::blocking_sender sender(conn, url.path());
+
+ proton::message_value m;
+ m.body("Hello World!");
+ sender.send(m);
+
+ proton::duration timeout(30000);
+ proton::message_value m2 = receiver.receive(timeout);
+ std::cout << m2.body() << std::endl;
+ receiver.accept();
+
+ conn.close();
+ return 0;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/helloworld_direct.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/helloworld_direct.cpp b/examples/cpp/helloworld_direct.cpp
new file mode 100644
index 0000000..119d134
--- /dev/null
+++ b/examples/cpp/helloworld_direct.cpp
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/acceptor.hpp"
+#include "proton/container.hpp"
+#include "proton/messaging_handler.hpp"
+
+//#include "proton/acceptor.hpp"
+#include <iostream>
+
+class hello_world_direct : public proton::messaging_handler {
+ private:
+ proton::url url;
+ proton::counted_ptr<proton::acceptor> acceptor;
+ public:
+
+ hello_world_direct(const proton::url& u) : url(u) {}
+
+ void on_start(proton::event &e) {
+ acceptor = e.container().listen(url).ptr();
+ e.container().create_sender(url);
+ }
+
+ void on_sendable(proton::event &e) {
+ proton::message_value m;
+ m.body("Hello World!");
+ e.sender().send(m);
+ e.sender().close();
+ }
+
+ void on_message(proton::event &e) {
+ std::cout << e.message().body() << std::endl;
+ }
+
+ void on_accepted(proton::event &e) {
+ e.connection().close();
+ }
+
+ void on_connection_closed(proton::event &e) {
+ acceptor->close();
+ }
+};
+
+int main(int argc, char **argv) {
+ try {
+ // Pick an "unusual" port since we are going to be talking to ourselves, not a broker.
+ std::string url = argc > 1 ? argv[1] : "127.0.0.1:8888/examples";
+
+ hello_world_direct hwd(url);
+ proton::container(hwd).run();
+ return 0;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/options.hpp
----------------------------------------------------------------------
diff --git a/examples/cpp/options.hpp b/examples/cpp/options.hpp
new file mode 100644
index 0000000..bd477b5
--- /dev/null
+++ b/examples/cpp/options.hpp
@@ -0,0 +1,173 @@
+#ifndef OPTIONS_HPP
+#define OPTIONS_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 <string>
+#include <sstream>
+#include <ostream>
+#include <vector>
+#include <stdexcept>
+
+/** bad_option is thrown for option parsing errors */
+struct bad_option : public std::runtime_error {
+ bad_option(const std::string& s) : std::runtime_error(s) {}
+};
+
+/** Simple command-line option parser for example programs */
+class options {
+ public:
+
+ options(int argc, char const * const * argv) : argc_(argc), argv_(argv), prog_(argv[0]), help_() {
+ size_t slash = prog_.find_last_of("/\\");
+ if (slash != std::string::npos)
+ prog_ = prog_.substr(slash+1); // Extract prog name from path
+ add_flag(help_, 'h', "help", "Print the help message");
+ }
+
+ ~options() {
+ for (opts::iterator i = opts_.begin(); i != opts_.end(); ++i)
+ delete *i;
+ }
+
+ /** Updates value when parse() is called if option is present with a value. */
+ template<class T>
+ void add_value(T& value, char short_name, const std::string& long_name, const std::string& description, const std::string var) {
+ opts_.push_back(new option_value<T>(value, short_name, long_name, description, var));
+ }
+
+ /** Sets flag when parse() is called if option is present. */
+ void add_flag(bool& flag, char short_name, const std::string& long_name, const std::string& description) {
+ opts_.push_back(new option_flag(flag, short_name, long_name, description));
+ }
+
+ /** Parse the command line, return the index of the first non-option argument.
+ *@throws bad_option if there is a parsing error or unknown option.
+ */
+ int parse() {
+ int arg = 1;
+ for (; arg < argc_ && argv_[arg][0] == '-'; ++arg) {
+ opts::iterator i = opts_.begin();
+ while (i != opts_.end() && !(*i)->parse(argc_, argv_, arg))
+ ++i;
+ if (i == opts_.end())
+ throw bad_option(std::string("unknown option ") + argv_[arg]);
+ }
+ if (help_) throw bad_option("");
+ return arg;
+ }
+
+ /** Print a usage message */
+ friend std::ostream& operator<<(std::ostream& os, const options& op) {
+ os << std::endl << "usage: " << op.prog_ << " [options]" << std::endl;
+ os << std::endl << "options:" << std::endl;
+ for (opts::const_iterator i = op.opts_.begin(); i < op.opts_.end(); ++i)
+ os << **i << std::endl;
+ return os;
+ }
+
+ private:
+ class option {
+ public:
+ option(char s, const std::string& l, const std::string& d, const std::string v) :
+ short_(std::string("-") + s), long_("--" + l), desc_(d), var_(v) {}
+ virtual ~option() {}
+
+ virtual bool parse(int argc, char const * const * argv, int &i) = 0;
+ virtual void print_default(std::ostream&) const {};
+
+ friend std::ostream& operator<<(std::ostream& os, const option& op) {
+ os << " " << op.short_;
+ if (!op.var_.empty()) os << " " << op.var_;
+ os << ", " << op.long_;
+ if (!op.var_.empty()) os << "=" << op.var_;
+ os << std::endl << " " << op.desc_;
+ op.print_default(os);
+ return os;
+ }
+
+ protected:
+ std::string short_, long_, desc_, var_;
+ };
+
+ template <class T>
+ class option_value : public option {
+ public:
+ option_value(T& value, char s, const std::string& l, const std::string& d, const std::string& v) :
+ option(s, l, d, v), value_(value) {}
+
+ bool parse(int argc, char const * const * argv, int &i) {
+ std::string arg(argv[i]);
+ if (arg == short_ || arg == long_) {
+ if (i < argc-1) {
+ set_value(arg, argv[++i]);
+ return true;
+ } else {
+ throw bad_option("missing value for " + arg);
+ }
+ }
+ if (arg.compare(0, long_.size(), long_) == 0 && arg[long_.size()] == '=' ) {
+ set_value(long_, arg.substr(long_.size()+1));
+ return true;
+ }
+ return false;
+ }
+
+ virtual void print_default(std::ostream& os) const { os << " (default " << value_ << ")"; }
+
+ void set_value(const std::string& opt, const std::string& s) {
+ std::istringstream is(s);
+ is >> value_;
+ if (is.fail() || is.bad())
+ throw bad_option("bad value for " + opt + ": " + s);
+ }
+
+ private:
+ T& value_;
+ };
+
+ class option_flag: public option {
+ public:
+ option_flag(bool& flag, const char s, const std::string& l, const std::string& d) :
+ option(s, l, d, ""), flag_(flag)
+ { flag_ = false; }
+
+ bool parse(int /*argc*/, char const * const * argv, int &i) {
+ if (argv[i] == short_ || argv[i] == long_) {
+ flag_ = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private:
+ bool &flag_;
+ };
+
+ typedef std::vector<option*> opts;
+
+ int argc_;
+ char const * const * argv_;
+ std::string prog_;
+ opts opts_;
+ bool help_;
+};
+
+#endif // OPTIONS_HPP
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/server.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/server.cpp b/examples/cpp/server.cpp
new file mode 100644
index 0000000..60cc972
--- /dev/null
+++ b/examples/cpp/server.cpp
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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 "options.hpp"
+
+#include "proton/container.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/url.hpp"
+
+#include <iostream>
+#include <map>
+#include <string>
+#include <cctype>
+
+class server : public proton::messaging_handler {
+ private:
+ typedef std::map<std::string, proton::counted_ptr<proton::sender> > sender_map;
+ proton::url url;
+ proton::counted_ptr<proton::connection> connection;
+ sender_map senders;
+
+ public:
+
+ server(const std::string &u) : url(u) {}
+
+ void on_start(proton::event &e) {
+ connection = e.container().connect(url).ptr();
+ connection->create_receiver(url.path());
+ std::cout << "server connected to " << url << std::endl;
+ }
+
+ std::string to_upper(const std::string &s) {
+ std::string uc(s);
+ size_t l = uc.size();
+ for (size_t i=0; i<l; i++) uc[i] = std::toupper(uc[i]);
+ return uc;
+ }
+
+ void on_message(proton::event &e) {
+ std::cout << "Received " << e.message().body() << std::endl;
+ std::string reply_to = e.message().reply_to();
+ proton::message_value reply;
+ reply.address(reply_to);
+ reply.body(to_upper(e.message().body().get<std::string>()));
+ reply.correlation_id(e.message().correlation_id());
+ if (!senders[reply_to])
+ senders[reply_to] = connection->create_sender(reply_to).ptr();
+ senders[reply_to]->send(reply);
+ }
+};
+
+int main(int argc, char **argv) {
+ // Command line options
+ std::string address("amqp://127.0.0.1:5672/examples");
+ options opts(argc, argv);
+ opts.add_value(address, 'a', "address", "listen on URL", "URL");
+ try {
+ opts.parse();
+ server srv(address);
+ proton::container(srv).run();
+ return 0;
+ } catch (const bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/server_direct.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/server_direct.cpp b/examples/cpp/server_direct.cpp
new file mode 100644
index 0000000..1e1839c
--- /dev/null
+++ b/examples/cpp/server_direct.cpp
@@ -0,0 +1,105 @@
+/*
+ *
+ * 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 "options.hpp"
+
+#include "proton/acceptor.hpp"
+#include "proton/container.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/url.hpp"
+
+#include <iostream>
+#include <map>
+#include <string>
+#include <sstream>
+#include <cctype>
+
+class server : public proton::messaging_handler {
+ private:
+ typedef std::map<std::string, proton::counted_ptr<proton::sender> > sender_map;
+ proton::url url;
+ sender_map senders;
+ int address_counter;
+
+ public:
+
+ server(const std::string &u) : url(u), address_counter(0) {}
+
+ void on_start(proton::event &e) {
+ e.container().listen(url);
+ std::cout << "server listening on " << url << std::endl;
+ }
+
+ std::string to_upper(const std::string &s) {
+ std::string uc(s);
+ size_t l = uc.size();
+ for (size_t i=0; i<l; i++) uc[i] = std::toupper(uc[i]);
+ return uc;
+ }
+
+ std::string generate_address() {
+ std::ostringstream addr;
+ addr << "server" << address_counter++;
+ return addr.str();
+ }
+
+ void on_link_opening(proton::event& e) {
+ proton::link& link = e.link();
+ if (link.is_sender() && link.has_remote_source() && link.remote_source().is_dynamic()) {
+ link.source().address(generate_address());
+ senders[link.source().address()] = link.sender().ptr();
+ }
+ }
+
+ void on_message(proton::event &e) {
+ std::cout << "Received " << e.message().body() << std::endl;
+ std::string reply_to = e.message().reply_to();
+ sender_map::iterator it = senders.find(reply_to);
+ if (it == senders.end()) {
+ std::cout << "No link for reply_to: " << reply_to << std::endl;
+ } else {
+ proton::counted_ptr<proton::sender> sender = it->second;
+ proton::message_value reply;
+ reply.address(reply_to);
+ reply.body(to_upper(e.message().body().get<std::string>()));
+ reply.correlation_id(e.message().correlation_id());
+ sender->send(reply);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ // Command line options
+ std::string address("amqp://127.0.0.1:5672/examples");
+ options opts(argc, argv);
+ opts.add_value(address, 'a', "address", "listen on URL", "URL");
+ try {
+ opts.parse();
+ server srv(address);
+ proton::container(srv).run();
+ return 0;
+ } catch (const bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/simple_recv.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_recv.cpp b/examples/cpp/simple_recv.cpp
new file mode 100644
index 0000000..f669e30
--- /dev/null
+++ b/examples/cpp/simple_recv.cpp
@@ -0,0 +1,85 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "options.hpp"
+
+#include "proton/container.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/link.hpp"
+
+#include <iostream>
+#include <map>
+
+
+
+class simple_recv : public proton::messaging_handler {
+ private:
+ proton::url url;
+ proton::counted_ptr<proton::receiver> receiver;
+ int expected;
+ int received;
+ public:
+
+ simple_recv(const std::string &s, int c) : url(s), expected(c), received(0) {}
+
+ void on_start(proton::event &e) {
+ receiver = e.container().create_receiver(url).ptr();
+ std::cout << "simple_recv listening on " << url << std::endl;
+ }
+
+ void on_message(proton::event &e) {
+ proton::message& msg = e.message();
+ proton::data_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();
+ }
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ // Command line options
+ std::string address("127.0.0.1:5672/examples");
+ int message_count = 100;
+ options opts(argc, argv);
+ opts.add_value(address, 'a', "address", "connect to and receive from URL", "URL");
+ opts.add_value(message_count, 'm', "messages", "receive COUNT messages", "COUNT");
+
+ try {
+ opts.parse();
+ simple_recv recv(address, message_count);
+ proton::container(recv).run();
+ return 0;
+ } catch (const bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/simple_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_send.cpp b/examples/cpp/simple_send.cpp
new file mode 100644
index 0000000..11af17c
--- /dev/null
+++ b/examples/cpp/simple_send.cpp
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "options.hpp"
+
+#include "proton/container.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/connection.hpp"
+
+#include <iostream>
+#include <map>
+
+class simple_send : public proton::messaging_handler {
+ private:
+ proton::url url;
+ proton::counted_ptr<proton::sender> sender;
+ int sent;
+ int confirmed;
+ int total;
+ public:
+
+ simple_send(const std::string &s, int c) : url(s), sent(0), confirmed(0), total(c) {}
+
+ void on_start(proton::event &e) {
+ sender = e.container().create_sender(url).ptr();
+ }
+
+ void on_sendable(proton::event &e) {
+ proton::sender& sender = e.sender();
+ while (sender.credit() && sent < total) {
+ proton::message_value msg;
+ msg.id(proton::data_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();
+ }
+ }
+
+ void on_disconnected(proton::event &e) {
+ sent = confirmed;
+ }
+};
+
+int main(int argc, char **argv) {
+ // Command line options
+ std::string address("127.0.0.1:5672/examples");
+ int message_count = 100;
+ options opts(argc, argv);
+ opts.add_value(address, 'a', "address", "connect and send to URL", "URL");
+ opts.add_value(message_count, 'm', "messages", "receive COUNT messages", "COUNT");
+ try {
+ opts.parse();
+ simple_send send(address, message_count);
+ proton::container(send).run();
+ return 0;
+ } catch (const bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/cpp/sync_client.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/sync_client.cpp b/examples/cpp/sync_client.cpp
new file mode 100644
index 0000000..7bf08d9
--- /dev/null
+++ b/examples/cpp/sync_client.cpp
@@ -0,0 +1,67 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "options.hpp"
+
+#include "proton/container.hpp"
+#include "proton/blocking_connection.hpp"
+#include "proton/sync_request_response.hpp"
+#include "proton/url.hpp"
+#include "proton/types.hpp"
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+
+int main(int argc, char **argv) {
+ // Command line options
+ proton::url url("127.0.0.1:5672/examples");
+ uint64_t timeout(5000);
+ options opts(argc, argv);
+ opts.add_value(url, 'a', "address", "connect to URL", "URL");
+ opts.add_value(timeout, 't', "timeout", "give up after this TIMEOUT (milliseconds)", "TIMEOUT");
+
+ std::vector<std::string> requests;
+ requests.push_back("Twas brillig, and the slithy toves");
+ requests.push_back("Did gire and gymble in the wabe.");
+ requests.push_back("All mimsy were the borogroves,");
+ requests.push_back("And the mome raths outgrabe.");
+
+ try {
+ opts.parse();
+
+ proton::blocking_connection conn(url, proton::duration(timeout));
+ proton::sync_request_response client(conn, url.path());
+ for (std::vector<std::string>::const_iterator i=requests.begin(); i != requests.end(); i++) {
+ proton::message_value request;
+ request.body(*i);
+ proton::message_value response(client.call(request));
+ std::cout << request.body() << " => " << response.body() << std::endl;
+ }
+ return 0;
+ } catch (const bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/go/README.md
----------------------------------------------------------------------
diff --git a/examples/go/README.md b/examples/go/README.md
deleted file mode 100644
index 719a3d1..0000000
--- a/examples/go/README.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# Go examples for proton
-
-The Go support for proton consists of 3 packages:
-
-- proton: converts AMQP messages and data types to and from Go data types.
-- proton/messaging: easy-to-use, concurrent API for messaging clients and servers.
-- proton/event: full low-level access to the proton engine.
-
-Most applications should use the proton/messaging API. proton/event is for
-applications that need low-level access to the proton engine. proton/messaging
-itself is implemented using proton/event.
-
-## proton/messaging examples
-
-- [receive.go](receive.go) receive from many connections concurrently.
-- [send.go](send.go) send to many connections concurrently.
-
-## proton/event examples
-
-- [broker.go](event/broker.go) simple mini-broker, queues are created automatically.
-
-## Running the examples
-
-Proton needs to be installed in a standard place such as `/usr` or `/usr/local`.
-(in future the examples will be able to use the local proton build)
-
-Set your environment:
-
- export GOPATH=<path-to-proton-checkout>/proton-c/bindings/go
-
-You can run the examples directly from source with
-
- go run <program>.go
-
-This is a little slow (a couple of seconds) as it compiles the program and runs it in one step.
-You can compile the program first and then run the executable to avoid the delay:
-
- go build <program>.go
- ./<program>
-
-All the examples take a `-h` flag to show usage information, see comments in the example
-source for more details.
-
-## Example of running the examples.
-
-First start the broker:
-
- go run event/broker.go
-
-Send messages concurrently to queues "foo" and "bar", 10 messages to each queue:
-
- go run go/send.go -count 10 localhost:/foo localhost:/bar
-
-Receive messages concurrently from "foo" and "bar". Note -count 20 for 10 messages each on 2 queues:
-
- go run go/receive.go -count 20 localhost:/foo localhost:/bar
-
-The broker and clients use the amqp port on the local host by default, to use a
-different address use the `-addr host:port` flag.
-
-You can mix it up by running the Go clients with the python broker:
-
- python ../python/broker.py
-
-Or use the Go broker and the python clients:
-
- python ../python/simple_send.py
- python ../python/simple_recv.py`.
-
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org