You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by jr...@apache.org on 2018/04/05 19:33:41 UTC
[06/51] [partial] qpid-proton git commit: PROTON-1728: Reorganize the
source tree
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/docs/mt.md
----------------------------------------------------------------------
diff --git a/cpp/docs/mt.md b/cpp/docs/mt.md
new file mode 100644
index 0000000..3be1bc2
--- /dev/null
+++ b/cpp/docs/mt.md
@@ -0,0 +1,124 @@
+# Multithreading {#mt_page}
+
+Full multithreading support is available with C++11 and later. Limited
+multithreading is possible with older versions of C++. See the last
+section of this page for more information.
+
+`proton::container` handles multiple connections concurrently in a
+thread pool, created using `proton::container::run()`. As AMQP events
+occur on a connection the container calls `proton::messaging_handler`
+event callbacks. The calls for each connection are *serialized* -
+callbacks for the same connection are never made concurrently.
+
+You assign a handler to a connection in `proton::container::connect()`
+or `proton::listen_handler::on_accept()` with
+`proton::connection_options::handler()`. We recommend you create a
+separate handler for each connection. That means the handler doesn't
+need locks or other synchronization to protect it against concurrent
+use by Proton threads. If you use the handler concurrently from
+non-Proton threads then you will need synchronization.
+
+The examples @ref multithreaded_client.cpp and @ref
+multithreaded_client_flow_control.cpp illustrate these points.
+
+## Thread-safety rules
+
+`proton::container` is thread-safe *with C++11 or greater*. An
+application thread can open (or listen for) new connections at any
+time. The container uses threads that call `proton::container::run()`
+to handle network IO and call user-defined `proton::messaging_handler`
+callbacks.
+
+`proton::container` ensures that calls to event callbacks for each
+connection instance are *serialized* (not called concurrently), but
+callbacks for different connections can be safely executed in
+parallel.
+
+`proton::connection` and related objects (`proton::session`,
+`proton::sender`, `proton::receiver`, `proton::delivery`) are *not*
+thread-safe and are subject to the following rules.
+
+1. They can only be used from a `proton::messaging_handler` event
+ callback called by Proton or a `proton::work_queue` function (more
+ below).
+
+2. You cannot use objects belonging to one connection from a callback
+ for another connection. We recommend a single handler instance per
+ connection to avoid confusion.
+
+3. You can store Proton objects in member variables for use in a later
+ callback, provided you respect rule two.
+
+`proton::message` is a value type with the same threading constraints
+as a standard C++ built-in type. It cannot be concurrently modified.
+
+## Work queues
+
+`proton::work_queue` provides a safe way to communicate between
+different connection handlers or between non-Proton threads and
+connection handlers.
+
+ * Each connection has an associated `proton::work_queue`.
+
+ * The work queue is thread-safe (C++11 or greater). Any thread can
+ add *work*.
+
+ * *Work* is a `std::function`, and bound arguments will be
+ called like an event callback.
+
+When the work function is called by Proton, it will be serialized
+safely so that you can treat the work function like an event callback
+and safely access the handler and Proton objects stored on it.
+
+The examples @ref multithreaded_client.cpp and @ref
+multithreaded_client_flow_control.cpp show how you can send and
+receive messages from non-Proton threads using work queues.
+
+## The wake primitive
+
+`proton::connection::wake()` allows any thread to "wake up" a
+connection by generating an `on_connection_wake()` callback. This is
+the *only* thread-safe `proton::connection` function.
+
+This is a lightweight, low-level primitive for signaling between
+threads.
+
+ * It does not carry any code or data (unlike `proton::work_queue`).
+
+ * Multiple calls to `wake()` can be "coalesced" into a single
+ `on_connection_wake()`.
+
+ * Calls to `on_connection_wake()` can occur without any call to
+ `connection::wake()`. Proton uses wake internally.
+
+The semantics of `wake()` are similar to
+`std::condition_variable::notify_one`. There will be a wakeup, but
+there must be some shared application state to determine why the
+wakeup occurred and what, if anything, to do about it.
+
+Work queues are easier to use in many instances, but `wake()` may be
+useful if you already have your own external thread-safe queues and
+just need an efficient way to wake a connection to check them for
+data.
+
+## Using older versions of C++
+
+Before C++11 there was no standard support for threading in C++. You
+can use Proton with threads but with the following limitations.
+
+ * The container will not create threads, it will only use the single
+ thread that calls `proton::container::run()`.
+
+ * None of the Proton library classes are thread-safe, including
+ `proton::container` and `proton::work_queue`. You need an external
+ lock to use `proton::container` in multiple threads.
+
+The only exception is `proton::connection::wake()`, it *is*
+thread-safe even in older C++.
+
+You can implement your own `proton::container` using your own
+threading library, or ignore the container and embed the lower-level
+`proton::io::connection_driver` in an external poller. These
+approaches still use the same `proton::messaging_handler` callbacks,
+so you can reuse most of your application code. Note that this is an
+advanced undertaking. There are a few pointers in @ref io_page.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/docs/overview.md
----------------------------------------------------------------------
diff --git a/cpp/docs/overview.md b/cpp/docs/overview.md
new file mode 100644
index 0000000..7a299b8
--- /dev/null
+++ b/cpp/docs/overview.md
@@ -0,0 +1,109 @@
+# Overview {#overview_page}
+
+Qpid Proton's concepts and capabilities closely match those of its
+wire protocol, AMQP. See
+[the Qpid AMQP page](https://qpid.apache.org/amqp/index.html) and
+[the AMQP 1.0 spec](http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-overview-v1.0-os.html)
+for more information.
+
+## Key concepts
+
+A `proton::message` has a *body* (the main content), application
+properties where you can store additional data, and specific
+properties defined by AMQP.
+
+Messages are transferred over *links*. The sending end of a link is a
+`proton::sender`, and the receiving end is a `proton::receiver`.
+Links have a *source* and *target* address, as explained
+[below](#sources-and-targets).
+
+Links are grouped in a `proton::session`. Messages in the same session
+are sent sequentially, while those on different sessions can be
+interleaved. A large message being sent on one session does not block
+messages being sent on another session.
+
+Sessions belong to a `proton::connection`. If you don't need multiple
+sessions, a connection will create links directly using a default
+session.
+
+A `proton::delivery` represents the transfer of a message and allows
+the receiver to accept or reject it. The sender can use a
+`proton::tracker` to track the status of a sent message and find out
+if it was accepted.
+
+A 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
+[below](#delivery-guarantees).
+
+## The anatomy of a Proton application
+
+`proton::container` is the top-level object in a Proton application.
+A client uses `proton::container::connect()` to establish connections.
+A server uses `proton::container::listen()` to accept connections.
+
+Proton is an event-driven API. You implement a subclass of
+`proton::messaging_handler` and override functions to handle AMQP
+events, such as `on_container_open()` or `on_message()`. Each
+connection is associated with a handler for its events.
+`proton::container::run()` polls all connections and listeners and
+dispatches events to your handlers.
+
+A message body can be a string or byte sequence encoded any way you
+like. However, AMQP also provides standard, interoperable encodings
+for basic data types and structures such as maps and lists. You can
+use this encoding for your message bodies via `proton::value` and
+`proton::scalar`, which convert C++ types to their AMQP equivalents.
+
+## Sources and targets
+
+Every link has two addresses, *source* and *target*. The most common
+pattern for using these addresses is as follows.
+
+When a client creates a *receiver* link, it sets the *source*
+address. This means "I want to receive messages from this
+source". This is often referred to as "subscribing" to the
+source. When a client creates a *sender* link, it sets the *target*
+address. This means "I want to send to this target".
+
+In the case of a broker, the source or target usually refers to a
+queue or topic. In general they can refer to any AMQP-capable node.
+
+In the *request-response* pattern, a request message carries a
+*reply-to* address for the response message. This can be any AMQP
+address, but it is often useful to create a temporary address for the
+response message. The client creates a *receiver* with no source
+address and the *dynamic* flag set. The server generates a unique
+*source* address for the receiver, which is discarded when the link
+closes. The client uses this source address as the reply-to when it
+sends the request, so the response is delivered to the client's
+receiver.
+
+The @ref server_direct.cpp example shows how to implement a
+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.
+
+For *at-least-once*, the receiver accepts and settles the message on
+receipt. If the connection is lost before the sender is informed of
+the settlement, then the delivery is considered in-doubt and should be
+retried. This will ensure it eventually gets delivered (provided of
+course the connection and link can be reestablished). It may mean that
+it is delivered multiple times, however.
+
+Finally, for *exactly-once*, the receiver accepts the message but
+doesn't settle it. The sender settles once it is aware that the
+receiver accepted it. In this way the receiver retains knowledge of an
+accepted message until it is sure the sender knows it has been
+accepted. If the connection is lost before settlement, the receiver
+informs the sender of all the unsettled deliveries it knows about, and
+from this the sender can deduce which need to be redelivered. The
+sender likewise informs the receiver which deliveries it knows about,
+from which the receiver can deduce which have already been settled.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/docs/types.md
----------------------------------------------------------------------
diff --git a/cpp/docs/types.md b/cpp/docs/types.md
new file mode 100644
index 0000000..6c24d47
--- /dev/null
+++ b/cpp/docs/types.md
@@ -0,0 +1,86 @@
+# AMQP and C++ types {#types_page}
+
+An AMQP message body can hold binary data using any encoding you
+like. AMQP also defines its own encoding and types. The AMQP encoding
+is often used in message bodies because it is supported by AMQP
+libraries on many languages and platforms. You also need to use the
+AMQP types to set and examine message properties.
+
+## Scalar types
+
+Each type is identified by a proton::type_id.
+
+C++ type | AMQP type_id | Description
+--------------------|----------------------|-----------------------
+bool | proton::BOOLEAN | Boolean true or false
+uint8_t | proton::UBYTE | 8-bit unsigned byte
+int8_t | proton::BYTE | 8-bit signed byte
+uint16_t | proton::USHORT | 16-bit unsigned integer
+int16_t | proton::SHORT | 16-bit signed integer
+uint32_t | proton::UINT | 32-bit unsigned integer
+int32_t | proton::INT | 32-bit signed integer
+uint64_t | proton::ULONG | 64-bit unsigned integer
+int64_t | proton::LONG | 64-bit signed integer
+wchar_t | proton::CHAR | 32-bit unicode code point
+float | proton::FLOAT | 32-bit binary floating point
+double | proton::DOUBLE | 64-bit binary floating point
+proton::timestamp | proton::TIMESTAMP | 64-bit signed milliseconds since 00:00:00 (UTC), 1 January 1970.
+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
+proton::symbol | proton::SYMBOL | 7-bit ASCII encoded string
+proton::binary | proton::BINARY | Variable-length binary data
+
+## Holder types
+
+`proton::message::body()` and other message-related data can contain
+different types of data at runtime. There are two "holder" types
+provided to hold runtime typed data:
+
+ - `proton::scalar` can hold a scalar value of any type.
+ - `proton::value` can hold any AMQP value, scalar or compound.
+
+You can set the value in a holder by assignment, and use the
+`proton::get()` and `proton::coerce()` templates to extract data in a
+type-safe way. Holders also provide functions to query the type of
+value they contain.
+
+## Compound types
+
+C++ type | AMQP type_id | Description
+--------------------|----------------------|-----------------------
+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
+
+A `proton::value` containing a `proton::ARRAY` can convert to and from
+C++ sequences of the corresponding C++ type: `std::vector`,
+`std::deque`, `std::list`, and `std::forward_list`.
+
+`proton::LIST` converts to and from sequences of `proton::value` or
+`proton::scalar`, which can hold mixed types of data.
+
+`proton::MAP` converts to and from `std::map`, `std::unordered_map`,
+and sequences of `std::pair`.
+
+For example, you can decode a message body with any AMQP map as
+follows.
+
+ proton::message m = ...;
+ std::map<proton::value, proton::value> map;
+ proton::get(m.body(), map);
+
+You can encode a message body with a map of string keys and `uint64_t`
+values like this:
+
+ std::unordered_map<std::string, uint64_t> map;
+ map["foo"] = 123;
+ m.body() = map;
+
+## Include files
+
+`proton/types.hpp` includes all available type definitions and
+conversions. Alternatively, you can selectively include the `.hpp`
+files you want.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/docs/user.doxygen.in
----------------------------------------------------------------------
diff --git a/cpp/docs/user.doxygen.in b/cpp/docs/user.doxygen.in
new file mode 100644
index 0000000..2b2eda6
--- /dev/null
+++ b/cpp/docs/user.doxygen.in
@@ -0,0 +1,83 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License. You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied. See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+# Project options
+
+PROJECT_NAME = "Qpid Proton C++"
+PROJECT_NUMBER = @PN_VERSION_MAJOR@.@PN_VERSION_MINOR@.@PN_VERSION_POINT@
+OUTPUT_DIRECTORY = .
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = YES
+JAVADOC_AUTOBRIEF = YES
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+BUILTIN_STL_SUPPORT = YES
+INLINE_SIMPLE_STRUCTS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_COMPOUND_REFERENCE = YES
+HIDE_SCOPE_NAMES = YES
+MAX_INITIALIZER_LINES = 0
+ALPHABETICAL_INDEX = NO
+SORT_MEMBER_DOCS = NO
+
+# Redefine protected as private and strip out the PN_CPP_EXTERN macro
+
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = YES
+PREDEFINED = protected=private PN_CPP_DEPRECATED(x)= PN_CPP_EXTERN= PN_CPP_OVERRIDE= PN_CPP_HAS_CPP11=1 PN_CPP_HAS_SHARED_PTR=1 PN_CPP_HAS_UNIQUE_PTR=1 PN_CPP_HAS_LONG_LONG=1 PN_CPP_HAS_NULLPTR=1 PN_CPP_HAS_RVALUE_REFERENCES=1 PN_CPP_HAS_OVERRIDE=override PN_CPP_HAS_EXPLICIT_CONVERSIONS=1 PN_CPP_HAS_DEFAULTED_FUNCTIONS=1 PN_CPP_HAS_DELETED_FUNCTIONS=1 PN_CPP_HAS_STD_FUNCTION=1 PN_CPP_HAS_CHRONO=1 PN_CPP_SUPPORTS_THREADS=1
+EXCLUDE_SYMBOLS = internal internal::*
+
+# Configuration options related to warning and progress messages
+
+QUIET = YES
+WARNINGS = YES
+
+# Configuration options related to the input files
+
+INPUT = @CMAKE_SOURCE_DIR@/cpp/include \
+ @CMAKE_SOURCE_DIR@/cpp/docs \
+ @CMAKE_SOURCE_DIR@/cpp/examples
+FILE_PATTERNS = *.hpp *.md *.dox
+EXCLUDE_PATTERNS = @CMAKE_SOURCE_DIR@/cpp/examples/*.?pp \
+ @CMAKE_SOURCE_DIR@/cpp/include/proton/internal/*.hpp
+FULL_PATH_NAMES = YES
+RECURSIVE = YES
+STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@/cpp/include
+EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/cpp/examples
+EXAMPLE_RECURSIVE = YES
+
+# View and list options
+
+DISABLE_INDEX = YES
+GENERATE_TREEVIEW = YES
+GENERATE_TODOLIST = NO
+GENERATE_TESTLIST = NO
+GENERATE_BUGLIST = NO
+GENERATE_DEPRECATEDLIST = NO
+
+# Configuration options related to the output format
+
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+GENERATE_LATEX = NO
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt
new file mode 100644
index 0000000..a9bde0a
--- /dev/null
+++ b/cpp/examples/CMakeLists.txt
@@ -0,0 +1,138 @@
+#
+# 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.
+#
+cmake_minimum_required (VERSION 2.8.12)
+
+enable_language(CXX)
+
+set (ProtonCpp_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+find_package(ProtonCpp REQUIRED)
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+find_package(Threads)
+
+include_directories(${ProtonCpp_INCLUDE_DIRS})
+link_libraries(${ProtonCpp_LIBRARIES})
+add_definitions(${ProtonCpp_DEFINITIONS})
+
+
+macro (has_cxx_features result)
+set(${result} OFF)
+if (DEFINED CMAKE_CXX_COMPILE_FEATURES)
+ set(${result} ON)
+ foreach(feature ${ARGN})
+ list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_${feature} N)
+ if (N EQUAL -1)
+ set(${result} OFF)
+ break()
+ endif()
+ endforeach()
+endif()
+endmacro()
+
+set (BUILD_CPP_03 OFF CACHE BOOL "Compile as C++03 even when C++11 is available")
+# This effectively checks for cmake version 3.1 or later
+if (DEFINED CMAKE_CXX_COMPILE_FEATURES)
+ if (BUILD_CPP_03)
+ set(STD 98)
+ else ()
+ set(STD 11)
+ has_cxx_features(HAS_ENOUGH_CPP11 lambdas variadic_templates)
+ message(STATUS "Compiling C++11 examples: ${HAS_ENOUGH_CPP11}")
+ endif ()
+ set(CMAKE_CXX_STANDARD ${STD})
+ set(CMAKE_CXX_EXTENSIONS OFF)
+endif()
+
+# Single-threaded examples that work on C++03
+foreach(example
+ broker
+ helloworld
+ simple_connect
+ simple_recv
+ simple_send
+ reconnect_client
+ message_properties
+ scheduled_send_03
+ direct_recv
+ direct_send
+ client
+ server
+ server_direct
+ connection_options
+ queue_browser
+ colour_send
+ selected_recv
+ flow_control
+ ssl
+ ssl_client_cert
+ encode_decode)
+ add_executable(${example} ${example}.cpp)
+endforeach()
+
+if(HAS_ENOUGH_CPP11)
+ # Examples that require C++11
+ foreach(example
+ scheduled_send
+ service_bus)
+ add_executable(${example} ${example}.cpp)
+ endforeach()
+
+ # Examples that use threads directly
+ if (Threads_FOUND)
+ foreach(example
+ multithreaded_client
+ multithreaded_client_flow_control)
+ add_executable(${example} ${example}.cpp)
+ target_link_libraries(${example} ${CMAKE_THREAD_LIBS_INIT})
+ endforeach()
+ endif()
+endif()
+
+# Set result to a native search path - used by examples and binding tests.
+# args after result are directories or search paths.
+macro(set_search_path result)
+ set(${result} ${ARGN})
+ if (UNIX)
+ string(REPLACE ";" ":" ${result} "${${result}}") # native search path separators.
+ endif()
+ file(TO_NATIVE_PATH "${${result}}" ${result}) # native slash separators
+endmacro()
+
+# Add the tools directory for the 'proctest' module
+set_search_path(EXAMPLE_PYTHONPATH "${CMAKE_SOURCE_DIR}/tools/python" "$ENV{PYTHON_PATH}")
+set(EXAMPLE_ENV "PYTHONPATH=${EXAMPLE_PYTHONPATH}")
+
+# Add a test with the correct environment to find test executables and valgrind.
+macro(add_cpp_test name)
+ if(WIN32)
+ set(test_path "$<TARGET_FILE_DIR:broker>;$<TARGET_FILE_DIR:qpid-proton>;$<TARGET_FILE_DIR:qpid-proton-cpp>")
+ else(WIN32)
+ set(test_path "$<TARGET_FILE_DIR:broker>:$ENV{PATH}")
+ endif(WIN32)
+ add_test(
+ NAME ${name}
+ COMMAND ${PN_ENV_SCRIPT} ${EXAMPLE_ENV} "PATH=${test_path}" ${VALGRIND_ENV}
+ "HAS_CPP11=$<$<BOOL:${HAS_ENOUGH_CPP11}>:1>" -- ${ARGN}
+ )
+endmacro()
+
+add_cpp_test(cpp-example-container ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ContainerExampleTest)
+
+if (NOT SSL_IMPL STREQUAL none)
+add_cpp_test(cpp-example-container-ssl ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ContainerExampleSSLTest)
+endif()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/examples/ProtonCppConfig.cmake
----------------------------------------------------------------------
diff --git a/cpp/examples/ProtonCppConfig.cmake b/cpp/examples/ProtonCppConfig.cmake
new file mode 100644
index 0000000..e289ba4
--- /dev/null
+++ b/cpp/examples/ProtonCppConfig.cmake
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+# Note that this file is used *only* when building the examples within
+# the proton source tree not when the examples are installed separately
+# from it (for example in an OS distribution package).
+#
+# So if you find this file installed on your system something went wrong
+# with the packaging and/or package installation.
+#
+# For a packaged installation the equivalent file is created by the source
+# tree build and installed in the appropriate place for cmake on that system.
+
+set (ProtonCpp_VERSION ${PN_VERSION})
+set (ProtonCpp_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/c/include ${CMAKE_SOURCE_DIR}/cpp/include
+ ${CMAKE_BINARY_DIR}/cpp)
+set (ProtonCpp_LIBRARIES ${C_EXAMPLE_LINK_FLAGS} qpid-proton-cpp)
+set (ProtonCpp_DEFINITIONS ${CXX_EXAMPLE_FLAGS})
+set (ProtonCpp_FOUND True)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/examples/README.dox
----------------------------------------------------------------------
diff --git a/cpp/examples/README.dox b/cpp/examples/README.dox
new file mode 100644
index 0000000..cb25e48
--- /dev/null
+++ b/cpp/examples/README.dox
@@ -0,0 +1,139 @@
+// C++ examples list (doxygen format)
+//
+// For a tutorial-style description of the examples see tutorial.dox.
+// To build the full HTML tutorial and documentation, in your build directory do:
+//
+// make docs-cpp
+//
+// then open cpp/docs/html/tutorial.html in your browser.
+
+// DEVELOPER NOTE: If you add or modify examples, please add/update a short
+// description below and (if appropriate) extend/update tutorial.dox.
+
+/** @example helloworld.cpp
+
+Connects to a broker on 127.0.0.1:5672, establishes a subscription
+from the 'examples' node, and creates a sending link to the same
+node. Sends one message and receives it back.
+
+*/
+
+/** @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 message_properties.cpp
+
+Shows how to set and examine message properties.
+
+*/
+
+/** @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`.
+
+*/
+
+/// @cond INTERNAL
+/** @example encode_decode.cpp
+
+Shows how C++ data types can be converted to and from AMQP types.
+
+*/
+/// @endcond
+
+/** @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 broker.cpp
+
+A broker using the `proton::container`. You can use this to run other examples
+that require 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 scheduled_send.cpp
+
+Shows how to use proton::container::schedule to schedule a timed callback.
+This version uses std::function and so requires C++11 or better. For a C++03 compatible
+approach see @ref scheduled_send_03.cpp.
+
+*/
+
+/** @example scheduled_send_03.cpp
+
+Shows how to use proton::container::schedule to schedule a timed callback in a
+C++03 compatible way. See @ref scheduled_send.cpp for a more convenient approach
+using std::function if you have C++11.
+
+*/
+
+/** @example service_bus.cpp
+
+A working example for accessing Service Bus session-enabled queues.
+Also provides some general notes on Service Bus usage.
+
+*/
+
+/** @example multithreaded_client.cpp
+
+A multithreaded sender and receiver.
+
+__Requires C++11__
+
+*/
+
+/** @example multithreaded_client_flow_control.cpp
+
+A multithreaded sender and receiver enhanced for flow control.
+
+__Requires C++11__
+
+*/
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/examples/broker.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/broker.cpp b/cpp/examples/broker.cpp
new file mode 100644
index 0000000..65384b3
--- /dev/null
+++ b/cpp/examples/broker.cpp
@@ -0,0 +1,454 @@
+/*
+ * 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/connection.hpp>
+#include <proton/connection_options.hpp>
+#include <proton/container.hpp>
+#include <proton/delivery.hpp>
+#include <proton/error_condition.hpp>
+#include <proton/listen_handler.hpp>
+#include <proton/listener.hpp>
+#include <proton/message.hpp>
+#include <proton/messaging_handler.hpp>
+#include <proton/receiver_options.hpp>
+#include <proton/sender_options.hpp>
+#include <proton/source_options.hpp>
+#include <proton/target.hpp>
+#include <proton/target_options.hpp>
+#include <proton/tracker.hpp>
+#include <proton/transport.hpp>
+#include <proton/work_queue.hpp>
+
+#include <deque>
+#include <iostream>
+#include <map>
+#include <string>
+
+#if PN_CPP_HAS_STD_THREAD
+#include <thread>
+
+int hardware_concurrency() {return std::thread::hardware_concurrency();}
+#else
+int hardware_concurrency() {return 1;}
+#endif
+
+#include "fake_cpp11.hpp"
+
+// This is a simplified model for a message broker, that only allows for messages to go to a
+// single receiver.
+//
+// This broker is multithread safe and if compiled with C++11 with a multithreaded Proton
+// binding library will use as many threads as there are thread resources available (usually
+// cores)
+//
+// Queues are only created and never destroyed
+//
+// Broker Entities (that need to be individually serialised)
+// QueueManager - Creates new queues, finds queues
+// Queue - Queues msgs, records subscribers, sends msgs to subscribers
+// Connection - Receives Messages from network, sends messages to network.
+
+// Work
+// FindQueue(queueName, connection) - From a Connection to the QueueManager
+// This will create the queue if it doesn't already exist and send a BoundQueue
+// message back to the connection.
+// BoundQueue(queue) - From the QueueManager to a Connection
+//
+// QueueMsg(msg) - From a Connection (receiver) to a Queue
+// Subscribe(sender) - From a Connection (sender) to a Queue
+// Flow(sender, credit) - From a Connection (sender) to a Queue
+// Unsubscribe(sender) - From a Connection (sender) to a Queue
+//
+// SendMsg(msg) - From a Queue to a Connection (sender)
+// Unsubscribed() - From a Queue to a Connection (sender)
+
+
+// Simple debug output
+bool verbose;
+#define DOUT(x) do {if (verbose) {x};} while (false)
+
+class Queue;
+class Sender;
+
+typedef std::map<proton::sender, Sender*> senders;
+
+class Sender : public proton::messaging_handler {
+ friend class connection_handler;
+
+ proton::sender sender_;
+ senders& senders_;
+ proton::work_queue& work_queue_;
+ std::string queue_name_;
+ Queue* queue_;
+ int pending_credit_;
+
+ // Messaging handlers
+ void on_sendable(proton::sender &sender) OVERRIDE;
+ void on_sender_close(proton::sender &sender) OVERRIDE;
+
+public:
+ Sender(proton::sender s, senders& ss) :
+ sender_(s), senders_(ss), work_queue_(s.work_queue()), queue_(0), pending_credit_(0)
+ {}
+
+ bool add(proton::work f) {
+ return work_queue_.add(f);
+ }
+
+
+ void boundQueue(Queue* q, std::string qn);
+ void sendMsg(proton::message m) {
+ DOUT(std::cerr << "Sender: " << this << " sending\n";);
+ sender_.send(m);
+ }
+ void unsubscribed() {
+ DOUT(std::cerr << "Sender: " << this << " deleting\n";);
+ delete this;
+ }
+};
+
+// Queue - round robin subscriptions
+class Queue {
+ proton::work_queue work_queue_;
+ const std::string name_;
+ std::deque<proton::message> messages_;
+ typedef std::map<Sender*, int> subscriptions; // With credit
+ subscriptions subscriptions_;
+ subscriptions::iterator current_;
+
+ void tryToSend() {
+ DOUT(std::cerr << "Queue: " << this << " tryToSend: " << subscriptions_.size(););
+ // Starting at current_, send messages to subscriptions with credit:
+ // After each send try to find another subscription; Wrap around;
+ // Finish when we run out of messages or credit.
+ size_t outOfCredit = 0;
+ while (!messages_.empty() && outOfCredit<subscriptions_.size()) {
+ // If we got the end (or haven't started yet) start at the beginning
+ if (current_==subscriptions_.end()) {
+ current_=subscriptions_.begin();
+ }
+ // If we have credit send the message
+ DOUT(std::cerr << "(" << current_->second << ") ";);
+ if (current_->second>0) {
+ DOUT(std::cerr << current_->first << " ";);
+ current_->first->add(make_work(&Sender::sendMsg, current_->first, messages_.front()));
+ messages_.pop_front();
+ --current_->second;
+ ++current_;
+ } else {
+ ++outOfCredit;
+ }
+ }
+ DOUT(std::cerr << "\n";);
+ }
+
+public:
+ Queue(proton::container& c, const std::string& n) :
+ work_queue_(c), name_(n), current_(subscriptions_.end())
+ {}
+
+ bool add(proton::work f) {
+ return work_queue_.add(f);
+ }
+
+ void queueMsg(proton::message m) {
+ DOUT(std::cerr << "Queue: " << this << "(" << name_ << ") queueMsg\n";);
+ messages_.push_back(m);
+ tryToSend();
+ }
+ void flow(Sender* s, int c) {
+ DOUT(std::cerr << "Queue: " << this << "(" << name_ << ") flow: " << c << " to " << s << "\n";);
+ subscriptions_[s] = c;
+ tryToSend();
+ }
+ void subscribe(Sender* s) {
+ DOUT(std::cerr << "Queue: " << this << "(" << name_ << ") subscribe Sender: " << s << "\n";);
+ subscriptions_[s] = 0;
+ }
+ void unsubscribe(Sender* s) {
+ DOUT(std::cerr << "Queue: " << this << "(" << name_ << ") unsubscribe Sender: " << s << "\n";);
+ // If we're about to erase the current subscription move on
+ if (current_ != subscriptions_.end() && current_->first==s) ++current_;
+ subscriptions_.erase(s);
+ s->add(make_work(&Sender::unsubscribed, s));
+ }
+};
+
+// We have credit to send a message.
+void Sender::on_sendable(proton::sender &sender) {
+ if (queue_) {
+ queue_->add(make_work(&Queue::flow, queue_, this, sender.credit()));
+ } else {
+ pending_credit_ = sender.credit();
+ }
+}
+
+void Sender::on_sender_close(proton::sender &sender) {
+ if (queue_) {
+ queue_->add(make_work(&Queue::unsubscribe, queue_, this));
+ } else {
+ // TODO: Is it possible to be closed before we get the queue allocated?
+ // If so, we should have a way to mark the sender deleted, so we can delete
+ // on queue binding
+ }
+ senders_.erase(sender);
+}
+
+void Sender::boundQueue(Queue* q, std::string qn) {
+ DOUT(std::cerr << "Sender: " << this << " bound to Queue: " << q <<"(" << qn << ")\n";);
+ queue_ = q;
+ queue_name_ = qn;
+
+ q->add(make_work(&Queue::subscribe, q, this));
+ sender_.open(proton::sender_options()
+ .source((proton::source_options().address(queue_name_)))
+ .handler(*this));
+ if (pending_credit_>0) {
+ queue_->add(make_work(&Queue::flow, queue_, this, pending_credit_));
+ }
+ std::cout << "sending from " << queue_name_ << std::endl;
+}
+
+class Receiver : public proton::messaging_handler {
+ friend class connection_handler;
+
+ proton::receiver receiver_;
+ proton::work_queue& work_queue_;
+ Queue* queue_;
+ std::deque<proton::message> messages_;
+
+ // A message is received.
+ void on_message(proton::delivery &, proton::message &m) OVERRIDE {
+ messages_.push_back(m);
+
+ if (queue_) {
+ queueMsgs();
+ }
+ }
+
+ void queueMsgs() {
+ DOUT(std::cerr << "Receiver: " << this << " queueing " << messages_.size() << " msgs to: " << queue_ << "\n";);
+ while (!messages_.empty()) {
+ queue_->add(make_work(&Queue::queueMsg, queue_, messages_.front()));
+ messages_.pop_front();
+ }
+ }
+
+public:
+ Receiver(proton::receiver r) :
+ receiver_(r), work_queue_(r.work_queue()), queue_(0)
+ {}
+
+ bool add(proton::work f) {
+ return work_queue_.add(f);
+ }
+
+ void boundQueue(Queue* q, std::string qn) {
+ DOUT(std::cerr << "Receiver: " << this << " bound to Queue: " << q << "(" << qn << ")\n";);
+ queue_ = q;
+ receiver_.open(proton::receiver_options()
+ .source((proton::source_options().address(qn)))
+ .handler(*this));
+ std::cout << "receiving to " << qn << std::endl;
+
+ queueMsgs();
+ }
+};
+
+class QueueManager {
+ proton::container& container_;
+ proton::work_queue work_queue_;
+ typedef std::map<std::string, Queue*> queues;
+ queues queues_;
+ int next_id_; // Use to generate unique queue IDs.
+
+public:
+ QueueManager(proton::container& c) :
+ container_(c), work_queue_(c), next_id_(0)
+ {}
+
+ bool add(proton::work f) {
+ return work_queue_.add(f);
+ }
+
+ template <class T>
+ void findQueue(T& connection, std::string& qn) {
+ if (qn.empty()) {
+ // Dynamic queue creation
+ std::ostringstream os;
+ os << "_dynamic_" << next_id_++;
+ qn = os.str();
+ }
+ Queue* q = 0;
+ queues::iterator i = queues_.find(qn);
+ if (i==queues_.end()) {
+ q = new Queue(container_, qn);
+ queues_[qn] = q;
+ } else {
+ q = i->second;
+ }
+ connection.add(make_work(&T::boundQueue, &connection, q, qn));
+ }
+
+ void findQueueSender(Sender* s, std::string qn) {
+ findQueue(*s, qn);
+ }
+
+ void findQueueReceiver(Receiver* r, std::string qn) {
+ findQueue(*r, qn);
+ }
+};
+
+class connection_handler : public proton::messaging_handler {
+ QueueManager& queue_manager_;
+ senders senders_;
+
+public:
+ connection_handler(QueueManager& qm) :
+ queue_manager_(qm)
+ {}
+
+ void on_connection_open(proton::connection& c) OVERRIDE {
+ c.open(); // Accept the connection
+ }
+
+ // A sender sends messages from a queue to a subscriber.
+ void on_sender_open(proton::sender &sender) OVERRIDE {
+ std::string qn = sender.source().dynamic() ? "" : sender.source().address();
+ Sender* s = new Sender(sender, senders_);
+ senders_[sender] = s;
+ queue_manager_.add(make_work(&QueueManager::findQueueSender, &queue_manager_, s, qn));
+ }
+
+ // A receiver receives messages from a publisher to a queue.
+ void on_receiver_open(proton::receiver &receiver) OVERRIDE {
+ std::string qname = receiver.target().address();
+ if (qname == "shutdown") {
+ std::cout << "broker shutting down" << std::endl;
+ // Sending to the special "shutdown" queue stops the broker.
+ receiver.connection().container().stop(
+ proton::error_condition("shutdown", "stop broker"));
+ } else {
+ if (qname.empty()) {
+ DOUT(std::cerr << "ODD - trying to attach to a empty address\n";);
+ }
+ Receiver* r = new Receiver(receiver);
+ queue_manager_.add(make_work(&QueueManager::findQueueReceiver, &queue_manager_, r, qname));
+ }
+ }
+
+ void on_session_close(proton::session &session) OVERRIDE {
+ // Unsubscribe all senders that belong to session.
+ for (proton::sender_iterator i = session.senders().begin(); i != session.senders().end(); ++i) {
+ senders::iterator j = senders_.find(*i);
+ if (j == senders_.end()) continue;
+ Sender* s = j->second;
+ if (s->queue_) {
+ s->queue_->add(make_work(&Queue::unsubscribe, s->queue_, s));
+ }
+ senders_.erase(j);
+ }
+ }
+
+ void on_error(const proton::error_condition& e) OVERRIDE {
+ std::cerr << "error: " << e.what() << std::endl;
+ }
+
+ // The container calls on_transport_close() last.
+ void on_transport_close(proton::transport& t) OVERRIDE {
+ // Unsubscribe all senders.
+ for (proton::sender_iterator i = t.connection().senders().begin(); i != t.connection().senders().end(); ++i) {
+ senders::iterator j = senders_.find(*i);
+ if (j == senders_.end()) continue;
+ Sender* s = j->second;
+ if (s->queue_) {
+ s->queue_->add(make_work(&Queue::unsubscribe, s->queue_, s));
+ }
+ }
+ delete this; // All done.
+ }
+};
+
+class broker {
+ public:
+ broker(const std::string addr) :
+ container_("broker"), queues_(container_), listener_(queues_)
+ {
+ container_.listen(addr, listener_);
+ }
+
+ void run() {
+#if PN_CPP_SUPPORTS_THREADS
+ int threads = hardware_concurrency();
+ std::cout << "starting " << threads << " listening threads\n";
+ std::cout.flush();
+ container_.run(threads);
+#else
+ std::cout << "no thread support - starting 1 listening thread\n";
+ std::cout.flush();
+ container_.run();
+#endif
+ }
+
+ private:
+ struct listener : public proton::listen_handler {
+ listener(QueueManager& c) : queues_(c) {}
+
+ proton::connection_options on_accept(proton::listener&) OVERRIDE{
+ return proton::connection_options().handler(*(new connection_handler(queues_)));
+ }
+
+ void on_open(proton::listener& l) OVERRIDE {
+ std::cout << "broker listening on " << l.port() << std::endl;
+ }
+
+ void on_error(proton::listener&, const std::string& s) OVERRIDE {
+ std::cerr << "listen error: " << s << std::endl;
+ throw std::runtime_error(s);
+ }
+ QueueManager& queues_;
+ };
+
+ proton::container container_;
+ QueueManager queues_;
+ listener listener_;
+};
+
+int main(int argc, char **argv) {
+ // Command line options
+ std::string address("0.0.0.0");
+ example::options opts(argc, argv);
+
+ opts.add_flag(verbose, 'v', "verbose", "verbose (debugging) output");
+ opts.add_value(address, 'a', "address", "listen on URL", "URL");
+
+ try {
+ verbose = false;
+ opts.parse();
+ broker(address).run();
+ return 0;
+ } catch (const example::bad_option& e) {
+ std::cout << opts << std::endl << e.what() << std::endl;
+ } catch (const std::exception& e) {
+ std::cerr << "broker shutdown: " << e.what() << std::endl;
+ }
+ return 1;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/examples/client.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/client.cpp b/cpp/examples/client.cpp
new file mode 100644
index 0000000..a9d5dbe
--- /dev/null
+++ b/cpp/examples/client.cpp
@@ -0,0 +1,109 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "options.hpp"
+#include <proton/connection.hpp>
+#include <proton/container.hpp>
+#include <proton/delivery.hpp>
+#include <proton/message.hpp>
+#include <proton/messaging_handler.hpp>
+#include <proton/receiver_options.hpp>
+#include <proton/source_options.hpp>
+#include <proton/tracker.hpp>
+
+#include <iostream>
+#include <vector>
+
+#include "fake_cpp11.hpp"
+
+using proton::receiver_options;
+using proton::source_options;
+
+class client : public proton::messaging_handler {
+ private:
+ std::string url;
+ std::vector<std::string> requests;
+ proton::sender sender;
+ proton::receiver receiver;
+
+ public:
+ client(const std::string &u, const std::vector<std::string>& r) : url(u), requests(r) {}
+
+ void on_container_start(proton::container &c) OVERRIDE {
+ sender = c.open_sender(url);
+ // Create a receiver requesting a dynamically created queue
+ // for the message source.
+ receiver_options opts = receiver_options().source(source_options().dynamic(true));
+ receiver = sender.connection().open_receiver("", opts);
+ }
+
+ void send_request() {
+ proton::message req;
+ req.body(requests.front());
+ req.reply_to(receiver.source().address());
+ sender.send(req);
+ }
+
+ void on_receiver_open(proton::receiver &) OVERRIDE {
+ send_request();
+ }
+
+ void on_message(proton::delivery &d, proton::message &response) OVERRIDE {
+ if (requests.empty()) return; // Spurious extra message!
+
+ std::cout << requests.front() << " => " << response.body() << std::endl;
+ requests.erase(requests.begin());
+
+ if (!requests.empty()) {
+ send_request();
+ } else {
+ d.connection().close();
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ std::string url("127.0.0.1:5672/examples");
+ example::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 example::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/37136940/cpp/examples/colour_send.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/colour_send.cpp b/cpp/examples/colour_send.cpp
new file mode 100644
index 0000000..107b600
--- /dev/null
+++ b/cpp/examples/colour_send.cpp
@@ -0,0 +1,116 @@
+/*
+ *
+ * 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/connection.hpp>
+#include <proton/connection_options.hpp>
+#include <proton/container.hpp>
+#include <proton/message.hpp>
+#include <proton/message_id.hpp>
+#include <proton/messaging_handler.hpp>
+#include <proton/tracker.hpp>
+#include <proton/types.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <map>
+
+#include "fake_cpp11.hpp"
+
+class colour_send : public proton::messaging_handler {
+ private:
+ std::string url;
+ std::string user;
+ std::string password;
+ proton::sender sender;
+ int sent;
+ int confirmed;
+ int total;
+
+ public:
+ colour_send(const std::string &s, const std::string &u, const std::string &p, int c) :
+ url(s), user(u), password(p), sent(0), confirmed(0), total(c) {}
+
+ void on_container_start(proton::container &c) OVERRIDE {
+ proton::connection_options co;
+ if (!user.empty()) co.user(user);
+ if (!password.empty()) co.password(password);
+ sender = c.open_sender(url, co);
+ }
+
+ void on_sendable(proton::sender &s) OVERRIDE {
+ while (s.credit() && sent < total) {
+ proton::message msg;
+
+ std::string colour = sent % 2 ? "red" : "green";
+ msg.properties().put("colour", colour);
+ msg.id(sent + 1);
+ std::stringstream body;
+ body << colour << " " << (sent +1);
+ msg.body(body.str());
+
+ s.send(msg);
+ sent++;
+ }
+ }
+
+ void on_tracker_accept(proton::tracker &t) OVERRIDE {
+ confirmed++;
+
+ if (confirmed == total) {
+ std::cout << "all messages confirmed" << std::endl;
+ t.connection().close();
+ }
+ }
+
+ void on_transport_close(proton::transport &) OVERRIDE {
+ sent = confirmed;
+ }
+};
+
+int main(int argc, char **argv) {
+ std::string address("127.0.0.1:5672/examples");
+ std::string user;
+ std::string password;
+ int message_count = 100;
+ example::options opts(argc, argv);
+
+ opts.add_value(address, 'a', "address", "connect and send to URL", "URL");
+ opts.add_value(message_count, 'm', "messages", "send COUNT messages", "COUNT");
+ opts.add_value(user, 'u', "user", "authenticate as USER", "USER");
+ opts.add_value(password, 'p', "password", "authenticate with PASSWORD", "PASSWORD");
+
+ try {
+ opts.parse();
+
+ colour_send send(address, user, password, message_count);
+ proton::container(send).run();
+
+ return 0;
+ } catch (const example::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/37136940/cpp/examples/connection_options.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/connection_options.cpp b/cpp/examples/connection_options.cpp
new file mode 100644
index 0000000..df26100
--- /dev/null
+++ b/cpp/examples/connection_options.cpp
@@ -0,0 +1,76 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/connection.hpp>
+#include <proton/connection_options.hpp>
+#include <proton/container.hpp>
+#include <proton/messaging_handler.hpp>
+#include <proton/transport.hpp>
+
+#include <iostream>
+
+using proton::connection_options;
+
+#include "fake_cpp11.hpp"
+
+class handler_2 : public proton::messaging_handler {
+ void on_connection_open(proton::connection &c) OVERRIDE {
+ std::cout << "connection events going to handler_2" << std::endl;
+ std::cout << "connection max_frame_size: " << c.max_frame_size() <<
+ ", idle timeout: " << c.idle_timeout() << std::endl;
+ c.close();
+ }
+};
+
+class main_handler : public proton::messaging_handler {
+ private:
+ std::string url;
+ handler_2 conn_handler;
+
+ public:
+ main_handler(const std::string& u) : url(u) {}
+
+ void on_container_start(proton::container &c) OVERRIDE {
+ // Connection options for this connection. Merged with and overriding the container's
+ // client_connection_options() settings.
+ c.connect(url, connection_options().handler(conn_handler).max_frame_size(2468));
+ }
+
+ void on_connection_open(proton::connection &c) OVERRIDE {
+ std::cout << "unexpected connection event on main handler" << std::endl;
+ c.close();
+ }
+};
+
+int main(int argc, char **argv) {
+ try {
+ std::string url = argc > 1 ? argv[1] : "127.0.0.1:5672/examples";
+ main_handler handler(url);
+ proton::container container(handler);
+ // Global connection options for future connections on container.
+ container.client_connection_options(connection_options().max_frame_size(12345).idle_timeout(proton::duration(15000)));
+ container.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/37136940/cpp/examples/direct_recv.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/direct_recv.cpp b/cpp/examples/direct_recv.cpp
new file mode 100644
index 0000000..93ba06f
--- /dev/null
+++ b/cpp/examples/direct_recv.cpp
@@ -0,0 +1,101 @@
+/*
+ *
+ * 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/connection.hpp>
+#include <proton/container.hpp>
+#include <proton/delivery.hpp>
+#include <proton/message.hpp>
+#include <proton/message_id.hpp>
+#include <proton/messaging_handler.hpp>
+#include <proton/link.hpp>
+#include <proton/listen_handler.hpp>
+#include <proton/listener.hpp>
+#include <proton/value.hpp>
+
+#include <iostream>
+#include <map>
+
+#include "fake_cpp11.hpp"
+
+class direct_recv : public proton::messaging_handler {
+ private:
+ class listener_ready_handler : public proton::listen_handler {
+ void on_open(proton::listener& l) OVERRIDE {
+ std::cout << "listening on " << l.port() << std::endl;
+ }
+ };
+
+ std::string url;
+ proton::listener listener;
+ listener_ready_handler listen_handler;
+ int expected;
+ int received;
+
+ public:
+ direct_recv(const std::string &s, int c) : url(s), expected(c), received(0) {}
+
+ void on_container_start(proton::container &c) OVERRIDE {
+ listener = c.listen(url, listen_handler);
+ }
+
+ void on_message(proton::delivery &d, proton::message &msg) OVERRIDE {
+ if (proton::coerce<int>(msg.id()) < received) {
+ return; // Ignore duplicate
+ }
+
+ if (expected == 0 || received < expected) {
+ std::cout << msg.body() << std::endl;
+ received++;
+ }
+
+ if (received == expected) {
+ d.receiver().close();
+ d.connection().close();
+ listener.stop();
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ std::string address("127.0.0.1:5672/examples");
+ int message_count = 100;
+ example::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 example::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/37136940/cpp/examples/direct_send.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/direct_send.cpp b/cpp/examples/direct_send.cpp
new file mode 100644
index 0000000..79be34c
--- /dev/null
+++ b/cpp/examples/direct_send.cpp
@@ -0,0 +1,112 @@
+/*
+ *
+ * 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/connection.hpp>
+#include <proton/container.hpp>
+#include <proton/listen_handler.hpp>
+#include <proton/listener.hpp>
+#include <proton/message.hpp>
+#include <proton/message_id.hpp>
+#include <proton/messaging_handler.hpp>
+#include <proton/value.hpp>
+#include <proton/tracker.hpp>
+#include <proton/types.hpp>
+
+#include <iostream>
+#include <map>
+
+#include "fake_cpp11.hpp"
+
+class simple_send : public proton::messaging_handler {
+ private:
+ class listener_ready_handler : public proton::listen_handler {
+ void on_open(proton::listener& l) OVERRIDE {
+ std::cout << "listening on " << l.port() << std::endl;
+ }
+ };
+
+ std::string url;
+ proton::listener listener;
+ listener_ready_handler listen_handler;
+ 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_container_start(proton::container &c) OVERRIDE {
+ listener = c.listen(url, listen_handler);
+ }
+
+ void on_sendable(proton::sender &sender) OVERRIDE {
+ while (sender.credit() && sent < total) {
+ proton::message msg;
+ std::map<std::string, int> m;
+ m["sequence"] = sent + 1;
+
+ msg.id(sent + 1);
+ msg.body(m);
+
+ sender.send(msg);
+ sent++;
+ }
+ }
+
+ void on_tracker_accept(proton::tracker &t) OVERRIDE {
+ confirmed++;
+
+ if (confirmed == total) {
+ std::cout << "all messages confirmed" << std::endl;
+ t.connection().close();
+ listener.stop();
+ }
+ }
+
+ void on_transport_close(proton::transport &) OVERRIDE {
+ sent = confirmed;
+ }
+};
+
+int main(int argc, char **argv) {
+ std::string address("127.0.0.1:5672/examples");
+ int message_count = 100;
+ example::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 example::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/37136940/cpp/examples/encode_decode.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/encode_decode.cpp b/cpp/examples/encode_decode.cpp
new file mode 100644
index 0000000..cd6169a
--- /dev/null
+++ b/cpp/examples/encode_decode.cpp
@@ -0,0 +1,251 @@
+/*
+ * 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/types.hpp>
+#include <proton/codec/encoder.hpp>
+#include <proton/codec/decoder.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+
+// 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 from a decoder in terms of their simple components.
+void print(proton::value&);
+
+// Some helper templates to print map and std::vector results.
+namespace std {
+template<class T, class U> ostream& operator<<(ostream& o, const std::pair<T,U>& p) {
+ return o << p.first << ":" << p.second;
+}
+template<class T> ostream& operator<<(ostream& o, const std::vector<T>& v) {
+ o << "[ ";
+ ostream_iterator<T> oi(o, " ");
+ copy(v.begin(), v.end(), oi);
+ return o << "]";
+}
+template<class T> ostream& operator<<(ostream& o, const std::list<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<std::pair<K,T> > oi(o, " ");
+ copy(m.begin(), m.end(), oi);
+ return o << "}";
+}
+}
+
+// Insert/extract native C++ containers with uniform type values.
+static void uniform_containers() {
+ std::cout << std::endl << "== Array, list and map of uniform type." << std::endl;
+ proton::value v;
+
+ std::vector<int> a;
+ a.push_back(1);
+ a.push_back(2);
+ a.push_back(3);
+ // By default a C++ container is encoded as an AMQP array.
+ v = a;
+ print(v);
+ std::list<int> a1;
+ proton::get(v, a1);
+ std::cout << a1 << std::endl;
+
+ // You can specify that a container should be encoded as an AMQP list instead.
+ v = proton::codec::encoder::list(a1);
+ print(v);
+ std::cout << proton::get<std::vector<int> >(v) << std::endl;
+
+ // C++ map types (types with key_type, mapped_type) convert to an AMQP map by default.
+ std::map<std::string, int> m;
+ m["one"] = 1;
+ m["two"] = 2;
+ v = m;
+ print(v);
+ std::cout << proton::get<std::map<std::string, int> >(v) << std::endl;
+
+ // A sequence of pairs encodes as an AMQP MAP, which lets you control the encoded order.
+ std::vector<std::pair<std::string, int> > pairs;
+ pairs.push_back(std::make_pair("z", 3));
+ pairs.push_back(std::make_pair("a", 4));
+ v = pairs;
+ print(v);
+
+ // You can also decode an AMQP map as a sequence of pairs to preserve encode order.
+ std::vector<std::pair<std::string, int> > pairs2;
+ proton::codec::decoder d(v);
+ d >> pairs2;
+ std::cout << pairs2 << std::endl;
+
+ // A vector of proton::value is normally encoded as a mixed-type AMQP LIST,
+ // but you can encoded it as an array provided all the values match the array type.
+ std::vector<proton::value> vv;
+ vv.push_back(proton::value("a"));
+ vv.push_back(proton::value("b"));
+ vv.push_back(proton::value("c"));
+ v = vv;
+ print(v);
+}
+
+// Containers with mixed types use value to represent arbitrary AMQP types.
+static void mixed_containers() {
+ std::cout << std::endl << "== List and map of mixed type values." << std::endl;
+ proton::value v;
+
+ std::vector<proton::value> l;
+ l.push_back(proton::value(42));
+ l.push_back(proton::value(std::string("foo")));
+ // By default, a sequence of proton::value is treated as an AMQP list.
+ v = l;
+ print(v);
+ std::vector<proton::value> l2 = proton::get<std::vector<proton::value> >(v);
+ std::cout << l2 << std::endl;
+
+ std::map<proton::value, proton::value> m;
+ m[proton::value("five")] = proton::value(5);
+ m[proton::value(4)] = proton::value("four"); v = m;
+ print(v);
+ typedef std::map<proton::value, proton::value> value_map;
+ value_map m2(proton::get<value_map>(v));
+ std::cout << m2 << std::endl;
+}
+
+// Insert using stream operators (see print_next for example of extracting with stream ops.)
+static void insert_stream_operators() {
+ std::cout << std::endl << "== Insert with stream operators." << std::endl;
+ proton::value v;
+
+ // Create an array of INT with values [1, 2, 3]
+ proton::codec::encoder e(v);
+ e << proton::codec::start::array(proton::INT)
+ << int32_t(1) << int32_t(2) << int32_t(3)
+ << proton::codec::finish();
+ print(v);
+
+ // Create a mixed-type list of the values [42, 0, "x"].
+ proton::codec::encoder e2(v);
+ e2 << proton::codec::start::list()
+ << int32_t(42) << false << proton::symbol("x")
+ << proton::codec::finish();
+ print(v);
+
+ // Create a map { "k1":42, "k2": false }
+ proton::codec::encoder e3(v);
+ e3 << proton::codec::start::map()
+ << "k1" << int32_t(42)
+ << proton::symbol("k2") << false
+ << proton::codec::finish();
+ print(v);
+}
+
+int main(int, char**) {
+ try {
+ uniform_containers();
+ mixed_containers();
+ insert_stream_operators();
+ return 0;
+ } catch (const std::exception& e) {
+ std::cerr << std::endl << "error: " << e.what() << std::endl;
+ }
+ return 1;
+}
+
+// print_next prints the next value from values by recursively descending into complex values.
+//
+// NOTE this is for example purposes only: There is a built in ostream operator<< for values.
+//
+//
+static void print_next(proton::codec::decoder& d) {
+ proton::type_id type = d.next_type();
+ proton::codec::start s;
+ switch (type) {
+ case proton::ARRAY: {
+ d >> s;
+ std::cout << "array<" << s.element;
+ if (s.is_described) {
+ std::cout << ", descriptor=";
+ print_next(d);
+ }
+ std::cout << ">[";
+ for (size_t i = 0; i < s.size; ++i) {
+ if (i) std::cout << ", ";
+ print_next(d);
+ }
+ std::cout << "]";
+ d >> proton::codec::finish();
+ break;
+ }
+ case proton::LIST: {
+ d >> s;
+ std::cout << "list[";
+ for (size_t i = 0; i < s.size; ++i) {
+ if (i) std::cout << ", ";
+ print_next(d);
+ }
+ std::cout << "]";
+ d >> proton::codec::finish();
+ break;
+ }
+ case proton::MAP: {
+ d >> s;
+ std::cout << "map{";
+ for (size_t i = 0; i < s.size/2; ++i) {
+ if (i) std::cout << ", ";
+ print_next(d);
+ std::cout << ":"; // key:value
+ print_next(d);
+ }
+ std::cout << "}";
+ d >> proton::codec::finish();
+ break;
+ }
+ case proton::DESCRIBED: {
+ d >> s;
+ std::cout << "described(";
+ print_next(d); // Descriptor
+ print_next(d); // value
+ d >> proton::codec::finish();
+ break;
+ }
+ default:
+ // A simple type. We could continue the switch for all AMQP types but
+ // we will take a short cut and extract to another value and print that.
+ proton::value v2;
+ d >> v2;
+ std::cout << type << "(" << v2 << ")";
+ }
+}
+
+// Print a value, for example purposes. Normal code can use operator<<
+void print(proton::value& v) {
+ proton::codec::decoder d(v);
+ d.rewind();
+ while (d.more()) {
+ print_next(d);
+ if (d.more()) std::cout << ", ";
+ }
+ std::cout << std::endl;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/examples/example_test.py
----------------------------------------------------------------------
diff --git a/cpp/examples/example_test.py b/cpp/examples/example_test.py
new file mode 100644
index 0000000..b9f0621
--- /dev/null
+++ b/cpp/examples/example_test.py
@@ -0,0 +1,266 @@
+#
+# 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, re, inspect
+from proctest import *
+from random import randrange
+from subprocess import Popen, PIPE, STDOUT, call
+from copy import copy
+import platform
+from os.path import dirname as dirname
+from threading import Thread, Event
+from string import Template
+
+createdSASLDb = False
+
+def _cyrusSetup(conf_dir):
+ """Write out simple SASL config.tests
+ """
+ saslpasswd = os.getenv('SASLPASSWD')
+ if saslpasswd:
+ t = Template("""sasldb_path: ${db}
+mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN ANONYMOUS
+""")
+ abs_conf_dir = os.path.abspath(conf_dir)
+ call(args=['rm','-rf',abs_conf_dir])
+ os.mkdir(abs_conf_dir)
+ db = os.path.join(abs_conf_dir,'proton.sasldb')
+ conf = os.path.join(abs_conf_dir,'proton-server.conf')
+ f = open(conf, 'w')
+ f.write(t.substitute(db=db))
+ f.close()
+
+ cmd_template = Template("echo password | ${saslpasswd} -c -p -f ${db} -u proton user")
+ cmd = cmd_template.substitute(db=db, saslpasswd=saslpasswd)
+ call(args=cmd, shell=True)
+
+ os.environ['PN_SASL_CONFIG_PATH'] = abs_conf_dir
+ global createdSASLDb
+ createdSASLDb = True
+
+# Globally initialize Cyrus SASL configuration
+_cyrusSetup('sasl-conf')
+
+def wait_listening(proc):
+ m = proc.wait_re(".*listening on ([0-9]+)$")
+ return m.group(1), m.group(0)+"\n" # Return (port, line)
+
+class BrokerTestCase(ProcTestCase):
+ """
+ ExampleTest that starts a broker in setUpClass and kills it in tearDownClass.
+ Subclasses must set `broker_exe` class variable with the name of the broker executable.
+ """
+ @classmethod
+ def setUpClass(cls):
+ cls.broker = None # In case Proc throws, create the attribute.
+ cls.broker = Proc([cls.broker_exe, "-a", "//:0"])
+ cls.port, line = wait_listening(cls.broker)
+ cls.addr = "//:%s/example" % cls.port
+
+ @classmethod
+ def tearDownClass(cls):
+ if cls.broker:
+ cls.broker.kill()
+
+ def tearDown(self):
+ b = type(self).broker
+ if b and b.poll() != None: # Broker crashed
+ type(self).setUpClass() # Start another for the next test.
+ raise ProcError(b, "broker crash")
+ super(BrokerTestCase, self).tearDown()
+
+
+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 recv_expect():
+ return "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
+
+class ContainerExampleTest(BrokerTestCase):
+ """Run the container examples, verify they behave as expected."""
+
+ broker_exe = "broker"
+
+ def test_helloworld(self):
+ self.assertMultiLineEqual('Hello World!\n', self.proc(["helloworld", self.addr]).wait_exit())
+
+ def test_simple_send_recv(self):
+ self.assertMultiLineEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit())
+ self.assertMultiLineEqual(recv_expect(), self.proc(["simple_recv", "-a", self.addr]).wait_exit())
+
+ def test_simple_recv_send(self):
+ # Start receiver first, then run sender"""
+ recv = self.proc(["simple_recv", "-a", self.addr])
+ self.assertMultiLineEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit())
+ self.assertMultiLineEqual(recv_expect(), recv.wait_exit())
+
+
+ def test_simple_send_direct_recv(self):
+ recv = self.proc(["direct_recv", "-a", "//:0"])
+ port, line = wait_listening(recv)
+ addr = "//:%s/examples" % port
+ self.assertMultiLineEqual("all messages confirmed\n",
+ self.proc(["simple_send", "-a", addr]).wait_exit())
+ self.assertMultiLineEqual(line+recv_expect(), recv.wait_exit())
+
+ def test_simple_recv_direct_send(self):
+ send = self.proc(["direct_send", "-a", "//:0"])
+ port, line = wait_listening(send)
+ addr = "//:%s/examples" % port
+ self.assertMultiLineEqual(recv_expect(), self.proc(["simple_recv", "-a", addr]).wait_exit())
+ self.assertMultiLineEqual(line+"all messages confirmed\n", send.wait_exit())
+
+ def test_request_response(self):
+ server = self.proc(["server", self.addr, "example"]) # self.addr has the connection info
+ server.wait_re("connected")
+ self.assertMultiLineEqual(CLIENT_EXPECT,
+ self.proc(["client", "-a", self.addr]).wait_exit())
+
+ def test_request_response_direct(self):
+ server = self.proc(["server_direct", "-a", "//:0"])
+ port, line = wait_listening(server);
+ addr = "//:%s/examples" % port
+ self.assertMultiLineEqual(CLIENT_EXPECT, self.proc(["client", "-a", addr]).wait_exit())
+
+ def test_flow_control(self):
+ want="""success: Example 1: simple credit
+success: Example 2: basic drain
+success: Example 3: drain without credit
+success: Example 4: high/low watermark
+"""
+ self.assertMultiLineEqual(want, self.proc(["flow_control", "--quiet"]).wait_exit())
+
+ def test_encode_decode(self):
+ want="""
+== Array, list and map of uniform type.
+array<int>[int(1), int(2), int(3)]
+[ 1 2 3 ]
+list[int(1), int(2), int(3)]
+[ 1 2 3 ]
+map{string(one):int(1), string(two):int(2)}
+{ one:1 two:2 }
+map{string(z):int(3), string(a):int(4)}
+[ z:3 a:4 ]
+list[string(a), string(b), string(c)]
+
+== List and map of mixed type values.
+list[int(42), string(foo)]
+[ 42 foo ]
+map{int(4):string(four), string(five):int(5)}
+{ 4:four five:5 }
+
+== Insert with stream operators.
+array<int>[int(1), int(2), int(3)]
+list[int(42), boolean(0), symbol(x)]
+map{string(k1):int(42), symbol(k2):boolean(0)}
+"""
+ self.maxDiff = None
+ self.assertMultiLineEqual(want, self.proc(["encode_decode"]).wait_exit())
+
+ def test_scheduled_send_03(self):
+ # Output should be a bunch of "send" lines but can't guarantee exactly how many.
+ out = self.proc(["scheduled_send_03", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split()
+ self.assertTrue(len(out) > 0);
+ self.assertEqual(["send"]*len(out), out)
+
+ @unittest.skipUnless(os.getenv('HAS_CPP11'), "not a C++11 build")
+ def test_scheduled_send(self):
+ out = self.proc(["scheduled_send", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split()
+ self.assertTrue(len(out) > 0);
+ self.assertEqual(["send"]*len(out), out)
+
+ def test_message_properties(self):
+ expect="""using put/get: short=123 string=foo symbol=sym
+using coerce: short(as long)=123
+props[short]=123
+props[string]=foo
+props[symbol]=sym
+short=42 string=bar
+expected conversion_error: "unexpected type, want: uint got: int"
+expected conversion_error: "unexpected type, want: uint got: string"
+"""
+ self.assertMultiLineEqual(expect, self.proc(["message_properties"]).wait_exit())
+
+ @unittest.skipUnless(os.getenv('HAS_CPP11'), "not a C++11 build")
+ def test_multithreaded_client(self):
+ got = self.proc(["multithreaded_client", self.addr, "examples", "10"], helgrind=True).wait_exit()
+ self.maxDiff = None
+ self.assertRegexpMatches(got, "10 messages sent and received");
+
+# @unittest.skipUnless(os.getenv('HAS_CPP11'), "not a C++11 build")
+ @unittest.skip("Test is unstable, will enable when fixed")
+ def test_multithreaded_client_flow_control(self):
+ got = self.proc(["multithreaded_client_flow_control", self.addr, "examples", "10", "2"], helgrind=True).wait_exit()
+ self.maxDiff = None
+ self.assertRegexpMatches(got, "20 messages sent and received");
+
+class ContainerExampleSSLTest(BrokerTestCase):
+ """Run the SSL container examples, verify they behave as expected."""
+
+ broker_exe = "broker"
+ valgrind = False # Disable for all tests, including inherited
+
+ def setUp(self):
+ super(ContainerExampleSSLTest, self).setUp()
+
+ def tearDown(self):
+ super(ContainerExampleSSLTest, self).tearDown()
+
+ def ssl_certs_dir(self):
+ """Absolute path to the test SSL certificates"""
+ return os.path.join(dirname(sys.argv[0]), "ssl-certs")
+
+ def test_ssl(self):
+ # SSL without SASL, VERIFY_PEER_NAME
+ # Disable valgrind when using OpenSSL
+ out = self.proc(["ssl", "-c", self.ssl_certs_dir()]).wait_exit()
+ expect = "Server certificate identity CN=test_server\nHello World!"
+ self.assertIn(expect, out)
+
+ def test_ssl_no_name(self):
+ # VERIFY_PEER
+ # Disable valgrind when using OpenSSL
+ out = self.proc(["ssl", "-c", self.ssl_certs_dir(), "-v", "noname"], valgrind=False).wait_exit()
+ expect = "Outgoing client connection connected via SSL. Server certificate identity CN=test_server\nHello World!"
+ self.assertIn(expect, out)
+
+ def test_ssl_bad_name(self):
+ # VERIFY_PEER
+ out = self.proc(["ssl", "-c", self.ssl_certs_dir(), "-v", "fail"]).wait_exit()
+ expect = "Expected failure of connection with wrong peer name"
+ self.assertIn(expect, out)
+
+ def test_ssl_client_cert(self):
+ # SSL with SASL EXTERNAL
+ expect="""Inbound client certificate identity CN=test_client
+Outgoing client connection connected via SSL. Server certificate identity CN=test_server
+Hello World!
+"""
+ # Disable valgrind when using OpenSSL
+ out = self.proc(["ssl_client_cert", self.ssl_certs_dir()]).wait_exit()
+ self.assertIn(expect, out)
+
+if __name__ == "__main__":
+ unittest.main()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/cpp/examples/fake_cpp11.hpp
----------------------------------------------------------------------
diff --git a/cpp/examples/fake_cpp11.hpp b/cpp/examples/fake_cpp11.hpp
new file mode 100644
index 0000000..03daa3b
--- /dev/null
+++ b/cpp/examples/fake_cpp11.hpp
@@ -0,0 +1,34 @@
+#ifndef FAKE_CPP11_HPP
+#define FAKE_CPP11_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.
+ */
+
+/// These definitions allow us to use some new C++11 features in previous compilers
+///
+/// It is strongly recommended not to copy this - just use C++11/C++14 instead!
+
+#if __cplusplus < 201103L
+#define OVERRIDE
+#else
+#define OVERRIDE override
+#endif
+
+
+#endif // FAKE_CPP11_HPP
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org