qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From acon...@apache.org
Subject [6/7] qpid-proton git commit: PROTON-865: C++ reactor binding for proton.
Date Fri, 04 Sep 2015 19:14:33 GMT
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/go/event/broker.go
----------------------------------------------------------------------
diff --git a/examples/go/event/broker.go b/examples/go/event/broker.go
deleted file mode 100644
index 9720843..0000000
--- a/examples/go/event/broker.go
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-*/
-
-//
-// This is a simple AMQP broker implemented using the event-handler interface.
-//
-// It maintains a set of named in-memory queues of messages. Clients can send
-// messages to queues or subscribe to receive messages from them.
-//
-//
-
-package main
-
-import (
-	"container/list"
-	"flag"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"log"
-	"net"
-	"os"
-	"path"
-	"qpid.apache.org/proton"
-	"qpid.apache.org/proton/event"
-	"sync"
-)
-
-// Command-line flags
-var addr = flag.String("addr", ":amqp", "Listening address")
-var verbose = flag.Int("verbose", 1, "Output level, 0 means none, higher means more")
-var full = flag.Bool("full", false, "Print full message not just body.")
-
-func main() {
-	flag.Usage = func() {
-		fmt.Fprintf(os.Stderr, `
-Usage: %s
-A simple broker-like demo. Queues are created automatically for sender or receiver addrsses.
-`, os.Args[0])
-		flag.PrintDefaults()
-	}
-	flag.Parse()
-	b := newBroker()
-	err := b.listen(*addr)
-	fatalIf(err)
-}
-
-// queue is a structure representing a queue.
-type queue struct {
-	name      string              // Name of queue
-	messages  *list.List          // List of event.Message
-	consumers map[event.Link]bool // Set of consumer links
-}
-
-type logLink event.Link // Wrapper to print links in format for logging
-
-func (ll logLink) String() string {
-	l := event.Link(ll)
-	return fmt.Sprintf("%s[%p]", l.Name(), l.Session().Connection().Pump())
-}
-
-func (q *queue) subscribe(link event.Link) {
-	debug.Printf("link %s subscribed to queue %s", logLink(link), q.name)
-	q.consumers[link] = true
-}
-
-func (q *queue) unsubscribe(link event.Link) {
-	debug.Printf("link %s unsubscribed from queue %s", logLink(link), q.name)
-	delete(q.consumers, link)
-}
-
-func (q *queue) empty() bool {
-	return len(q.consumers) == 0 && q.messages.Len() == 0
-}
-
-func (q *queue) push(context *event.Pump, message proton.Message) {
-	q.messages.PushBack(message)
-	q.pop(context)
-}
-
-func (q *queue) popTo(context *event.Pump, link event.Link) bool {
-	if q.messages.Len() != 0 && link.Credit() > 0 {
-		message := q.messages.Remove(q.messages.Front()).(proton.Message)
-		debug.Printf("link %s <- queue %s: %s", logLink(link), q.name, formatMessage{message})
-		// The first return parameter is an event.Delivery.
-		// The Deliver can be used to track message status, e.g. so we can re-delver on failure.
-		// This demo broker doesn't do that.
-		linkPump := link.Session().Connection().Pump()
-		if context == linkPump {
-			if context == nil {
-				log.Fatal("pop in nil context")
-			}
-			link.Send(message) // link is in the current pump, safe to call Send() direct
-		} else {
-			linkPump.Inject <- func() { // Inject to link's pump
-				link.Send(message) // FIXME aconway 2015-05-04: error handlig
-			}
-		}
-		return true
-	}
-	return false
-}
-
-func (q *queue) pop(context *event.Pump) (popped bool) {
-	for c, _ := range q.consumers {
-		popped = popped || q.popTo(context, c)
-	}
-	return
-}
-
-// broker implements event.MessagingHandler and reacts to events by moving messages on or off queues.
-type broker struct {
-	queues map[string]*queue
-	lock   sync.Mutex // FIXME aconway 2015-05-04: un-golike, better broker coming...
-}
-
-func newBroker() *broker {
-	return &broker{queues: make(map[string]*queue)}
-}
-
-func (b *broker) getQueue(name string) *queue {
-	q := b.queues[name]
-	if q == nil {
-		debug.Printf("Create queue %s", name)
-		q = &queue{name, list.New(), make(map[event.Link]bool)}
-		b.queues[name] = q
-	}
-	return q
-}
-
-func (b *broker) unsubscribe(l event.Link) {
-	if l.IsSender() {
-		q := b.queues[l.RemoteSource().Address()]
-		if q != nil {
-			q.unsubscribe(l)
-			if q.empty() {
-				debug.Printf("Delete queue %s", q.name)
-				delete(b.queues, q.name)
-			}
-		}
-	}
-}
-
-func (b *broker) HandleMessagingEvent(t event.MessagingEventType, e event.Event) error {
-	// FIXME aconway 2015-05-04: locking is un-golike, better example coming soon.
-	// Needed because the same handler is used for multiple connections concurrently
-	// and the queue data structures are not thread safe.
-	b.lock.Lock()
-	defer b.lock.Unlock()
-
-	switch t {
-
-	case event.MLinkOpening:
-		if e.Link().IsSender() {
-			q := b.getQueue(e.Link().RemoteSource().Address())
-			q.subscribe(e.Link())
-		}
-
-	case event.MLinkDisconnected, event.MLinkClosing:
-		b.unsubscribe(e.Link())
-
-	case event.MSendable:
-		q := b.getQueue(e.Link().RemoteSource().Address())
-		q.popTo(e.Connection().Pump(), e.Link())
-
-	case event.MMessage:
-		m, err := event.DecodeMessage(e)
-		fatalIf(err)
-		qname := e.Link().RemoteTarget().Address()
-		debug.Printf("link %s -> queue %s: %s", logLink(e.Link()), qname, formatMessage{m})
-		b.getQueue(qname).push(e.Connection().Pump(), m)
-	}
-	return nil
-}
-
-func (b *broker) listen(addr string) (err error) {
-	// Use the standard Go "net" package to listen for connections.
-	info.Printf("Listening on %s", addr)
-	listener, err := net.Listen("tcp", addr)
-	if err != nil {
-		return err
-	}
-	defer listener.Close()
-	for {
-		conn, err := listener.Accept()
-		if err != nil {
-			info.Printf("Accept error: %s", err)
-			continue
-		}
-		pump, err := event.NewPump(conn, event.NewMessagingDelegator(b))
-		fatalIf(err)
-		info.Printf("Accepted %s[%p]", pump, pump)
-		pump.Server()
-		go func() {
-			pump.Run()
-			if pump.Error == nil {
-				info.Printf("Closed %s", pump)
-			} else {
-				info.Printf("Closed %s: %s", pump, pump.Error)
-			}
-		}()
-	}
-}
-
-// Logging
-func logger(prefix string, level int, w io.Writer) *log.Logger {
-	if *verbose >= level {
-		return log.New(w, prefix, 0)
-	}
-	return log.New(ioutil.Discard, "", 0)
-}
-
-var info, debug *log.Logger
-
-func init() {
-	flag.Parse()
-	name := path.Base(os.Args[0])
-	log.SetFlags(0)
-	log.SetPrefix(fmt.Sprintf("%s: ", name))                      // Log errors on stderr.
-	info = logger(fmt.Sprintf("%s: ", name), 1, os.Stdout)        // Log info on stdout.
-	debug = logger(fmt.Sprintf("%s debug: ", name), 2, os.Stderr) // Log debug on stderr.
-}
-
-// Simple error handling for demo.
-func fatalIf(err error) {
-	if err != nil {
-		log.Fatal(err)
-	}
-}
-
-type formatMessage struct{ m proton.Message }
-
-func (fm formatMessage) String() string {
-	if *full {
-		return fmt.Sprintf("%#v", fm.m)
-	} else {
-		return fmt.Sprintf("%#v", fm.m.Body())
-	}
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/go/receive.go
----------------------------------------------------------------------
diff --git a/examples/go/receive.go b/examples/go/receive.go
deleted file mode 100644
index fc1c85a..0000000
--- a/examples/go/receive.go
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-*/
-
-package main
-
-import (
-	"flag"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"log"
-	"math"
-	"net"
-	"os"
-	"path"
-	"qpid.apache.org/proton"
-	"qpid.apache.org/proton/messaging"
-	"sync"
-	"time"
-)
-
-// Command-line flags
-var verbose = flag.Int("verbose", 1, "Output level, 0 means none, higher means more")
-var count = flag.Int64("count", 0, "Stop after receiving this many messages. 0 means unlimited.")
-var timeout = flag.Int64("time", 0, "Stop after this many seconds. 0 means unlimited.")
-var full = flag.Bool("full", false, "Print full message not just body.")
-
-func main() {
-	// Parse flags and arguments, print usage message on error.
-	flag.Usage = func() {
-		fmt.Fprintf(os.Stderr, `
-Usage: %s url [url ...]
-Receive messages from all the listed URLs concurrently and print them.
-`, os.Args[0])
-		flag.PrintDefaults()
-	}
-	flag.Parse()
-	urls := flag.Args() // Non-flag arguments are URLs to receive from
-	if len(urls) == 0 {
-		flag.Usage()
-		fmt.Fprintf(os.Stderr, "No URL provided")
-		os.Exit(1)
-	}
-	duration := time.Duration(*timeout) * time.Second
-	if duration == 0 {
-		duration = time.Duration(math.MaxInt64) // Not forever, but 290 years is close enough.
-	}
-	if *count == 0 {
-		*count = math.MaxInt64
-	}
-
-	// Create a goroutine for each URL that receives messages and sends them to
-	// the messages channel. main() receives and prints them.
-
-	messages := make(chan proton.Message) // Channel for messages from goroutines to main()
-	stop := make(chan struct{})           // Closing this channel means the program is stopping.
-
-	var wait sync.WaitGroup // Used by main() to wait for all goroutines to end.
-
-	wait.Add(len(urls)) // Wait for one goroutine per URL.
-
-	// Arrange to close all connections on exit
-	connections := make([]*messaging.Connection, len(urls))
-	defer func() {
-		for _, c := range connections {
-			if c != nil {
-				c.Close()
-			}
-		}
-	}()
-
-	for i, urlStr := range urls {
-		debug.Printf("Connecting to %s", urlStr)
-		go func(urlStr string) {
-			defer wait.Done()                   // Notify main() that this goroutine is done.
-			url, err := proton.ParseURL(urlStr) // Like net/url.Parse() but with AMQP defaults.
-			fatalIf(err)
-
-			// Open a standard Go net.Conn for the AMQP connection
-			conn, err := net.Dial("tcp", url.Host) // Note net.URL.Host is actually "host:port"
-			fatalIf(err)
-
-			pc, err := messaging.Connect(conn) // This is our AMQP connection.
-			fatalIf(err)
-			connections[i] = pc
-
-			// For convenience a proton.Connection provides a DefaultSession()
-			// pc.Receiver() is equivalent to pc.DefaultSession().Receiver()
-			r, err := pc.Receiver(url.Path)
-			fatalIf(err)
-
-			for {
-				var m proton.Message
-				select { // Receive a message or stop.
-				case m = <-r.Receive:
-				case <-stop: // The program is stopping.
-					return
-				}
-				select { // Send m to main() or stop
-				case messages <- m: // Send m to main()
-				case <-stop: // The program is stopping.
-					return
-				}
-			}
-		}(urlStr)
-	}
-	info.Printf("Listening")
-
-	// time.After() returns a channel that will close when the timeout is up.
-	timer := time.After(duration)
-
-	// main() prints each message and checks for count or timeout being exceeded.
-	for i := int64(0); i < *count; i++ {
-		select {
-		case m := <-messages:
-			debug.Print(formatMessage{m})
-		case <-timer: // Timeout has expired
-			i = 0
-		}
-	}
-	info.Printf("Received %d messages", *count)
-	close(stop) // Signal all goroutines to stop.
-	wait.Wait() // Wait for all goroutines to finish.
-}
-
-// Logging
-func logger(prefix string, level int, w io.Writer) *log.Logger {
-	if *verbose >= level {
-		return log.New(w, prefix, 0)
-	}
-	return log.New(ioutil.Discard, "", 0)
-}
-
-var info, debug *log.Logger
-
-func init() {
-	flag.Parse()
-	name := path.Base(os.Args[0])
-	log.SetFlags(0)                                               // Use default logger for errors.
-	log.SetPrefix(fmt.Sprintf("%s: ", name))                      // Log errors on stderr.
-	info = logger(fmt.Sprintf("%s: ", name), 1, os.Stdout)        // Log info on stdout.
-	debug = logger(fmt.Sprintf("%s debug: ", name), 2, os.Stderr) // Log debug on stderr.
-}
-
-// Simple error handling for demo.
-func fatalIf(err error) {
-	if err != nil {
-		log.Fatal(err)
-	}
-}
-
-type formatMessage struct{ m proton.Message }
-
-func (fm formatMessage) String() string {
-	if *full {
-		return fmt.Sprintf("%#v", fm.m)
-	} else {
-		return fmt.Sprintf("%#v", fm.m.Body())
-	}
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/examples/go/send.go
----------------------------------------------------------------------
diff --git a/examples/go/send.go b/examples/go/send.go
deleted file mode 100644
index 46603bf..0000000
--- a/examples/go/send.go
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-*/
-
-package main
-
-import (
-	"flag"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"log"
-	"math"
-	"net"
-	"os"
-	"path"
-	"qpid.apache.org/proton"
-	"qpid.apache.org/proton/messaging"
-	"sync"
-)
-
-// Command-line flags
-var verbose = flag.Int("verbose", 1, "Output level, 0 means none, higher means more")
-var count = flag.Int64("count", 1, "Send this may messages per address. 0 means unlimited.")
-
-// Ack associates an info string with an acknowledgement
-type Ack struct {
-	ack  messaging.Acknowledgement
-	info string
-}
-
-func main() {
-	// Parse flags and arguments, print usage message on error.
-	flag.Usage = func() {
-		fmt.Fprintf(os.Stderr, `
-Usage: %s url [url ...]
-Send messages to all the listed URLs concurrently.
-To each URL, send the string "path-n" where n is the message number.
-`, os.Args[0])
-		flag.PrintDefaults()
-	}
-	flag.Parse()
-	urls := flag.Args() // Non-flag arguments are URLs to receive from
-	if len(urls) == 0 {
-		flag.Usage()
-		fmt.Fprintf(os.Stderr, "No URL provided\n")
-		os.Exit(1)
-	}
-	if *count == 0 {
-		*count = math.MaxInt64
-	}
-
-	// Create a channel to receive all the acknowledgements
-	acks := make(chan Ack)
-
-	// Create a goroutine for each URL that sends messages.
-	var wait sync.WaitGroup // Used by main() to wait for all goroutines to end.
-	wait.Add(len(urls))     // Wait for one goroutine per URL.
-
-	// Arrange to close all connections on exit
-	connections := make([]*messaging.Connection, len(urls))
-	defer func() {
-		for _, c := range connections {
-			c.Close()
-		}
-	}()
-
-	for i, urlStr := range urls {
-		url, err := proton.ParseURL(urlStr) // Like net/url.Parse() but with AMQP defaults.
-		fatalIf(err)
-		debug.Printf("Connecting to %v", url)
-
-		// Open a standard Go net.Conn for the AMQP connection
-		conn, err := net.Dial("tcp", url.Host) // Note net.URL.Host is actually "host:port"
-		fatalIf(err)
-
-		pc, err := messaging.Connect(conn) // This is our AMQP connection using conn.
-		fatalIf(err)
-		connections[i] = pc
-
-		// Start a goroutine to send to urlStr
-		go func(urlStr string) {
-			defer wait.Done() // Notify main() that this goroutine is done.
-
-			// FIXME aconway 2015-04-29: sessions, default sessions, senders...
-			// Create a sender using the path of the URL as the AMQP target address
-			s, err := pc.Sender(url.Path)
-			fatalIf(err)
-
-			for i := int64(0); i < *count; i++ {
-				m := proton.NewMessage()
-				body := fmt.Sprintf("%v-%v", url.Path, i)
-				m.SetBody(body)
-				ack, err := s.Send(m)
-				fatalIf(err)
-				acks <- Ack{ack, body}
-			}
-		}(urlStr)
-	}
-
-	// Wait for all the acknowledgements
-	expect := int(*count) * len(urls)
-	debug.Printf("Started senders, expect %v acknowledgements", expect)
-	for i := 0; i < expect; i++ {
-		ack, ok := <-acks
-		if !ok {
-			info.Fatalf("acks channel closed after only %d acks\n", i)
-		}
-		d := <-ack.ack
-		debug.Printf("acknowledgement[%v] %v", i, ack.info)
-		if d != messaging.Accepted {
-			info.Printf("Unexpected disposition %v", d)
-		}
-	}
-	info.Printf("Received all %v acknowledgements", expect)
-	wait.Wait() // Wait for all goroutines to finish.
-}
-
-// Logging
-func logger(prefix string, level int, w io.Writer) *log.Logger {
-	if *verbose >= level {
-		return log.New(w, prefix, 0)
-	}
-	return log.New(ioutil.Discard, "", 0)
-}
-
-var info, debug *log.Logger
-
-func init() {
-	flag.Parse()
-	name := path.Base(os.Args[0])
-	log.SetFlags(0)                                               // Use default logger for errors.
-	log.SetPrefix(fmt.Sprintf("%s: ", name))                      // Log errors on stderr.
-	info = logger(fmt.Sprintf("%s: ", name), 1, os.Stdout)        // Log info on stdout.
-	debug = logger(fmt.Sprintf("%s debug: ", name), 2, os.Stderr) // Log debug on stderr.
-}
-
-// Simple error handling for demo.
-func fatalIf(err error) {
-	if err != nil {
-		log.Fatal(err)
-	}
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 46cf60e..9bcaa6e 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -217,6 +217,8 @@ if (CMAKE_COMPILER_IS_GNUCC)
     set (WERROR "-Werror")
   endif (ENABLE_WARNING_ERROR)
   set (COMPILE_WARNING_FLAGS "${WERROR} -Wall -pedantic-errors")
+  # C++ allow "%z" format specifier and variadic macros
+  set (CXX_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-format -Wno-variadic-macros" CACHE STRING "C++ warning flags")
   if (NOT BUILD_WITH_CXX)
     set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wstrict-prototypes")
     set (COMPILE_LANGUAGE_FLAGS "-std=c99")
@@ -231,8 +233,7 @@ if (CMAKE_COMPILER_IS_GNUCC)
       set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wc++-compat -Wvla -Wsign-compare -Wwrite-strings")
     endif (${GCC_VERSION} VERSION_LESS "4.3.0")
   else (NOT BUILD_WITH_CXX)
-    # allow "%z" format specifier and variadic macros
-    set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-format -Wno-variadic-macros")
+    set (COMPILE_WARNING_FLAGS "${CXX_WARNING_FLAGS}")
   endif (NOT BUILD_WITH_CXX)
 
   if (ENABLE_UNDEFINED_ERROR)
@@ -262,10 +263,7 @@ macro (pn_absolute_install_dir NAME VALUE PREFIX)
   get_filename_component(${NAME} ${${NAME}} ABSOLUTE)
 endmacro()
 
-if (SWIG_FOUND)
-  add_subdirectory(bindings)
-endif (SWIG_FOUND)
-
+add_subdirectory(bindings)
 add_subdirectory(docs/api)
 add_subdirectory(docs/man)
 add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c)
@@ -448,20 +446,6 @@ install (FILES
   ${CMAKE_CURRENT_BINARY_DIR}/ProtonConfigVersion.cmake
   DESTINATION ${LIB_INSTALL_DIR}/cmake/Proton)
 
-# CTest
-
-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)
-
 # c tests:
 
 add_subdirectory(src/tests)
@@ -521,28 +505,28 @@ if (BUILD_PYTHON)
   # platforms will be supported. Since `setup.py` will skip
   # the build for non linux plaforms, it doesn't make sense
   # to try to run them.
-  if (CMAKE_SYSTEM_NAME STREQUAL Linux)
-   find_program(TOX_EXE "tox")
-   mark_as_advanced(TOX_EXE)
-   if (TOX_EXE)
-     to_native_path ("${py_path}" py_path)
-     add_test (NAME python-tox-test
-               WORKING_DIRECTORY ${py_src}
-               COMMAND ${env_py}
-                 "PATH=${py_path}" "QPID_PROTON_SRC=${CMAKE_CURRENT_SOURCE_DIR}/../"
-                 "CLASSPATH=${CMAKE_BINARY_DIR}/proton-j/proton-j.jar"
-                 "SASLPASSWD=${SASLPASSWD_EXE}"
-                 "SWIG=${SWIG_EXECUTABLE}"
-                 ${VALGRIND_ENV}
-                 ${TOX_EXE})
-     set_tests_properties(python-tox-test
-                          PROPERTIES
-                          PASS_REGULAR_EXPRESSION "Totals: .* ignored, 0 failed"
-                          FAIL_REGULAR_EXPRESSION "ERROR:[ ]+py[0-9]*: commands failed")
-   else (TOX_EXE)
-     message(STATUS "The tox tool is not available - skipping the python-tox-tests")
-   endif (TOX_EXE)
-  endif (CMAKE_SYSTEM_NAME STREQUAL Linux)
+  option(TOX_TEST "Enable muti-version python testing with TOX" ON)
+  if (CMAKE_SYSTEM_NAME STREQUAL Linux AND TOX_TEST)
+     find_program(TOX_EXE "tox")
+     if (TOX_EXE)
+         to_native_path ("${py_path}" py_path)
+         add_test (NAME python-tox-test
+		   WORKING_DIRECTORY ${py_src}
+                   COMMAND ${env_py}
+		   "PATH=${py_path}" "QPID_PROTON_SRC=${CMAKE_CURRENT_SOURCE_DIR}/../"
+                   "CLASSPATH=${CMAKE_BINARY_DIR}/proton-j/proton-j.jar"
+                   "SASLPASSWD=${SASLPASSWD_EXE}"
+                   "SWIG=${SWIG_EXECUTABLE}"
+                   ${VALGRIND_ENV}
+                   ${TOX_EXE})
+         set_tests_properties(python-tox-test
+                              PROPERTIES
+                              PASS_REGULAR_EXPRESSION "Totals: .* ignored, 0 failed"
+                              FAIL_REGULAR_EXPRESSION "ERROR:[ ]+py[0-9]*: commands failed")
+     else (TOX_EXE)
+         message(STATUS "The tox tool is not available - skipping the python-tox-tests")
+     endif (TOX_EXE)
+  endif (CMAKE_SYSTEM_NAME STREQUAL Linux AND TOX_TEST)
 
 endif (BUILD_PYTHON)
 
@@ -589,6 +573,3 @@ if (BUILD_JAVASCRIPT)
   add_test (javascript-codec ${env_py} node ${pn_test_root}/javascript/codec.js)
   add_test (javascript-message ${env_py} node ${pn_test_root}/javascript/message.js)
 endif (BUILD_JAVASCRIPT)
-
-# build examples to make sure they still work
-add_subdirectory(../examples ../examples)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/CMakeLists.txt b/proton-c/bindings/CMakeLists.txt
index 41a7882..693e533 100644
--- a/proton-c/bindings/CMakeLists.txt
+++ b/proton-c/bindings/CMakeLists.txt
@@ -17,91 +17,13 @@
 # under the License.
 #
 
-include(UseSWIG)
+# Add bindings that do not require swig here - the directory name must be the same as the binding name
+# See below for swig bindings
+set(BINDINGS javascript cpp)
 
-# Add any new bindings here - the directory name must be the same as the binding name
-set (BINDINGS python ruby php perl javascript)
-
-# All swig modules should include ${PROTON_HEADERS} in SWIG_MODULE_<name>_EXTRA_DEPS
-file(GLOB PROTON_HEADERS "${CMAKE_SOURCE_DIR}/proton-c/include/proton/*.h")
-
-# If swig version is 3.0 or greater then we can build some additional bindings
-if (${SWIG_VERSION} VERSION_GREATER 3.0 OR ${SWIG_VERSION} VERSION_EQUAL 3.0)
-  set (BINDINGS
-    ${BINDINGS}
-    node
-    )
-endif()
-
-set (BINDING_DEPS qpid-proton)
-
-# Add a block here to detect the prerequisites to build each language binding:
+# Prerequisites for javascript.
 #
-# If the prerequisites for the binding are present set a variable called
-# DEFAULT_{uppercase name of binding} to ON
-
-# Prerequisites for Python wrapper (must be same version as python):
-find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT)
-if (PYTHONLIBS_FOUND)
-  set (DEFAULT_PYTHON ON)
-endif (PYTHONLIBS_FOUND)
-
-# Prerequisites for Ruby:
-find_program(GEM_EXE "gem")
-mark_as_advanced(GEM_EXE)
-macro(CheckRubyGem varname gemname)
-  execute_process(COMMAND ${GEM_EXE} list --local ${gemname}
-    OUTPUT_VARIABLE CHECK_OUTPUT)
-
-  set (${varname} OFF)
-
-  if (CHECK_OUTPUT MATCHES "${gemname}[ ]+\(.*\)")
-    message(STATUS "Found Ruby gem: ${gemname}")
-    set (${varname} ON)
-  else()
-    message(STATUS "Missing Ruby gem dependency: ${gemname}")
-    set (${varname} OFF)
-  endif()
-endmacro()
-
-find_package(Ruby)
-if (RUBY_FOUND)
-  set (DEFAULT_RUBY ON)
-
-  CheckRubyGem("HAS_RUBY_GEM_RSPEC"     "rspec")
-  CheckRubyGem("HAS_RUBY_GEM_SIMPLECOV" "simplecov")
-
-  if (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV)
-    set (DEFAULT_RUBY_TESTING ON CACHE INTERNAL "")
-  else()
-    message(STATUS "Skipping Ruby bindings due to missing dependencies...")
-    set (DEFAULT_RUBY_TESTING OFF CACHE INTERNAL "")
-    set (DEFAULT_RUBY OFF)
-  endif (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV)
-endif (RUBY_FOUND)
-
-# Prerequites for PHP:
-# For now, assume PHP support if the 'php-config' tool is present.
-# @todo: allow user to specify which php-config if multiple PHP sources installed!
-find_program(PHP_CONFIG_EXE php-config)
-if (PHP_CONFIG_EXE)
-  find_program(PHP_EXE php)
-  mark_as_advanced (PHP_EXE)
-  if (PHP_EXE)
-    set (DEFAULT_PHP ON)
-  endif (PHP_EXE)
-endif (PHP_CONFIG_EXE)
-mark_as_advanced (PHP_CONFIG_EXE)
-
-# Prerequisites for Perl:
-include(ProtonFindPerl)
-if (PERLLIBS_FOUND)
-  set (DEFAULT_PERL ON)
-endif (PERLLIBS_FOUND)
-
-# Prerequisites for the javascript "binding":
-# This is somewhat different to the other language bindings in that it does not use swig. It uses a C/C++ to
-# JavaScript cross-compiler called emscripten (https://github.com/kripken/emscripten). Emscripten takes C/C++
+# It uses a C/C++ to JavaScript cross-compiler called emscripten (https://github.com/kripken/emscripten). Emscripten takes C/C++
 # and compiles it into a highly optimisable subset of JavaScript called asm.js (http://asmjs.org/) that can be
 # aggressively optimised and run at near-native speed (usually between 1.5 to 10 times slower than native C/C++).
 find_package(Emscripten)
@@ -109,6 +31,93 @@ if (EMSCRIPTEN_FOUND)
   set (DEFAULT_JAVASCRIPT ON)
 endif (EMSCRIPTEN_FOUND)
 
+# Prerequisites for C++
+if (CMAKE_CXX_COMPILER)
+  set (DEFAULT_CPP ON)
+endif (CMAKE_CXX_COMPILER)
+
+if(SWIG_FOUND)
+  # Add any new swig bindings here - the directory name must be the same as the binding name
+  list(APPEND BINDINGS python ruby php perl)
+
+  include(UseSWIG)
+
+  # All swig modules should include ${PROTON_HEADERS} in SWIG_MODULE_<name>_EXTRA_DEPS
+  file(GLOB PROTON_HEADERS "${CMAKE_SOURCE_DIR}/proton-c/include/proton/*.h")
+  # All swig modules should include ${BINDING_DEPS} in swig_link_libraries
+  set (BINDING_DEPS qpid-proton)
+
+  # If swig version is 3.0 or greater then we can build some additional bindings
+  if (${SWIG_VERSION} VERSION_GREATER 3.0 OR ${SWIG_VERSION} VERSION_EQUAL 3.0)
+    list(APPEND SWIG_BINDINGS node)
+  endif()
+
+  # Add a block here to detect the prerequisites to build each language binding:
+  #
+  # If the prerequisites for the binding are present set a variable called
+  # DEFAULT_{uppercase name of binding} to ON
+
+  # Prerequisites for Python wrapper:
+  find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT)
+  if (PYTHONLIBS_FOUND)
+    set (DEFAULT_PYTHON ON)
+  endif (PYTHONLIBS_FOUND)
+
+  # Prerequisites for Ruby:
+  find_program(GEM_EXE "gem")
+  mark_as_advanced(GEM_EXE)
+  macro(CheckRubyGem varname gemname)
+    execute_process(COMMAND ${GEM_EXE} list --local ${gemname}
+      OUTPUT_VARIABLE CHECK_OUTPUT)
+
+    set (${varname} OFF)
+
+    if (CHECK_OUTPUT MATCHES "${gemname}[ ]+\(.*\)")
+      message(STATUS "Found Ruby gem: ${gemname}")
+      set (${varname} ON)
+    else()
+      message(STATUS "Missing Ruby gem dependency: ${gemname}")
+      set (${varname} OFF)
+    endif()
+  endmacro()
+
+  find_package(Ruby)
+  if (RUBY_FOUND)
+    set (DEFAULT_RUBY ON)
+
+    CheckRubyGem("HAS_RUBY_GEM_RSPEC"     "rspec")
+    CheckRubyGem("HAS_RUBY_GEM_SIMPLECOV" "simplecov")
+
+    if (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV)
+      set (DEFAULT_RUBY_TESTING ON CACHE INTERNAL "")
+    else()
+      message(STATUS "Skipping Ruby bindings due to missing dependencies...")
+      set (DEFAULT_RUBY_TESTING OFF CACHE INTERNAL "")
+      set (DEFAULT_RUBY OFF)
+    endif (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV)
+  endif (RUBY_FOUND)
+
+  # Prerequites for PHP:
+  # For now, assume PHP support if the 'php-config' tool is present.
+  # @todo: allow user to specify which php-config if multiple PHP sources installed!
+  find_program(PHP_CONFIG_EXE php-config)
+  if (PHP_CONFIG_EXE)
+    find_program(PHP_EXE php)
+    mark_as_advanced (PHP_EXE)
+    if (PHP_EXE)
+      set (DEFAULT_PHP ON)
+    endif (PHP_EXE)
+  endif (PHP_CONFIG_EXE)
+  mark_as_advanced (PHP_CONFIG_EXE)
+
+  # Prerequisites for Perl:
+  include(ProtonFindPerl)
+  if (PERLLIBS_FOUND)
+    set (DEFAULT_PERL ON)
+  endif (PERLLIBS_FOUND)
+
+endif()
+
 # Shouldn't need to modify below here when adding new language binding
 foreach(BINDING ${BINDINGS})
   string(TOUPPER ${BINDING} UBINDING)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
new file mode 100644
index 0000000..df770fa
--- /dev/null
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -0,0 +1,151 @@
+#
+# 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(CheckCXXSourceCompiles)
+
+# Check compiler capabilities.
+set(CMAKE_REQUIRED_FLAGS "${CXX_WARNING_FLAGS}")
+check_cxx_source_compiles("long long ll; int main(int, char**) { return 0; }" HAS_LONG_LONG)
+if (HAS_LONG_LONG)
+  add_definitions(-DPN_HAS_LONG_LONG=1)
+endif()
+check_cxx_source_compiles("#include <memory>\nstd::shared_ptr<int> i; std::unique_ptr<int> u; int main(int, char**) { return 0; }" HAS_STD_PTR)
+if (HAS_STD_PTR)
+  add_definitions(-DPN_HAS_STD_PTR=1)
+endif()
+
+# Check for boost
+find_path(BOOST_INCLUDE_DIR boost/shared_ptr.hpp PATH_SUFFIXES include)
+if (BOOST_INCLUDE_DIR)
+  add_definitions(-DPN_HAS_BOOST=1)
+endif()
+
+include_directories(
+  "${CMAKE_SOURCE_DIR}/proton-c/include"
+  "${CMAKE_CURRENT_SOURCE_DIR}/include"
+  "${CMAKE_CURRENT_SOURCE_DIR}/src")
+
+set(qpid-proton-cpp-source
+  src/acceptor.cpp
+  src/blocking_connection.cpp
+  src/blocking_connection_impl.cpp
+  src/blocking_fetcher.cpp
+  src/blocking_link.cpp
+  src/blocking_receiver.cpp
+  src/blocking_sender.cpp
+  src/connection.cpp
+  src/connector.cpp
+  src/container.cpp
+  src/container_impl.cpp
+  src/contexts.cpp
+  src/data.cpp
+  src/decoder.cpp
+  src/delivery.cpp
+  src/duration.cpp
+  src/encoder.cpp
+  src/endpoint.cpp
+  src/error.cpp
+  src/event.cpp
+  src/facade.cpp
+  src/handler.cpp
+  src/link.cpp
+  src/message.cpp
+  src/messaging_adapter.cpp
+  src/messaging_event.cpp
+  src/messaging_handler.cpp
+  src/proton_bits.cpp
+  src/proton_event.cpp
+  src/proton_handler.cpp
+  src/reactor.cpp
+  src/receiver.cpp
+  src/sender.cpp
+  src/session.cpp
+  src/sync_request_response.cpp
+  src/terminus.cpp
+  src/transport.cpp
+  src/types.cpp
+  src/url.cpp
+  src/uuid.cpp
+  )
+
+
+set_source_files_properties (
+  ${qpid-proton-cpp-source}
+  PROPERTIES
+  COMPILE_FLAGS "${CXX_WARNING_FLAGS}"
+  )
+
+add_library(qpid-proton-cpp SHARED ${qpid-proton-cpp-source})
+
+target_link_libraries (qpid-proton-cpp ${PLATFORM_LIBS} qpid-proton)
+
+set_target_properties (
+  qpid-proton-cpp
+  PROPERTIES
+  LINKER_LANGUAGE CXX
+  VERSION   "${PN_LIB_SOMAJOR}.${PN_LIB_SOMINOR}"
+  SOVERSION "${PN_LIB_SOMAJOR}"
+  LINK_FLAGS "${CATCH_UNDEFINED}"
+  )
+
+## Test
+if (ENABLE_VALGRIND AND VALGRIND_EXE)
+  set(memcheck-cmd ${VALGRIND_EXE} --error-exitcode=1 --quiet --leak-check=full --trace-children=yes)
+endif ()
+
+macro(add_cpp_test test)
+  add_executable (${test} src/${test}.cpp)
+  target_link_libraries (${test} qpid-proton qpid-proton-cpp)
+  if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+    add_test (NAME cpp_${test}
+      COMMAND ${env_py}
+      "PATH=$<TARGET_FILE_DIR:qpid-proton>"
+      $<TARGET_FILE:${test}> ${ARGN})
+  else ()
+    add_test (NAME cpp_${test} COMMAND ${memcheck-cmd} ${CMAKE_CURRENT_BINARY_DIR}/${test} ${ARGN})
+  endif ()
+endmacro(add_cpp_test)
+
+add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests)
+add_cpp_test(conversion_test ${CMAKE_SOURCE_DIR}/tests)
+
+## Install
+
+install(TARGETS qpid-proton-cpp
+  EXPORT  proton
+  ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
+  LIBRARY DESTINATION ${LIB_INSTALL_DIR})
+
+# Install windows qpid-proton-cpp pdb files
+if (MSVC)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpid-proton${CMAKE_DEBUG_POSTFIX}.pdb
+    DESTINATION bin
+    CONFIGURATIONS Debug
+    OPTIONAL)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/qpid-proton.pdb
+    DESTINATION bin
+    CONFIGURATIONS RelWithDebInfo
+    OPTIONAL)
+endif (MSVC)
+
+# Install header files
+file(GLOB headers "include/proton/cpp/*.h")
+install (FILES ${headers} DESTINATION ${INCLUDE_INSTALL_DIR}/proton/cpp)
+
+add_subdirectory(docs)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/README.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/README.md b/proton-c/bindings/cpp/README.md
new file mode 100644
index 0000000..d84813b
--- /dev/null
+++ b/proton-c/bindings/cpp/README.md
@@ -0,0 +1,40 @@
+# C++ binding for proton.
+
+This is a C++ binding for the proton API.
+
+The documentation includes a tutorial and API documentation.
+
+To generate the documentation go to your build directory, run `make docs-cpp`
+and open `proton-c/bindings/cpp/docs/html/index.html` in a browser.
+
+# TO DO
+
+Tests
+- Interop/type testing: proton/tests/interop, new interop suite
+- More unit testing, measured code coverage.
+- Test examples against AM-Q and qpidd.
+
+Bugs
+- Error handling:
+  - examples exit silently on broker exit/not running, core on no-such-queue (e.g. with qpidd)
+  - TODO/FIXME notes in code.
+- const correctness: consistent use of const where semantically appropriate in C++ APIs.
+
+Features
+- SASL/SSL support with interop tests.
+- Reconnection
+- Browsing
+- Selectors
+- AMQP described types and arrays, full support and tests.
+- Durable subscriptions & demos (see python changes)
+- Transactions
+- Heartbeats
+
+# Nice to have
+
+- C++11 lambda version of handlers.
+- Helpers (or at least doc) for multi-threaded use (container per connection)
+- Usable support for decimal types.
+- Expose endpoint conditions as C++ proton::condition error class.
+- Selectables and 3rd party event loop support
+- More efficient shared_ptr (single family per proton object.)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/445f8873/proton-c/bindings/cpp/docs/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/docs/CMakeLists.txt b/proton-c/bindings/cpp/docs/CMakeLists.txt
new file mode 100644
index 0000000..9c2d0d4
--- /dev/null
+++ b/proton-c/bindings/cpp/docs/CMakeLists.txt
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+find_package(Doxygen)
+if (DOXYGEN_FOUND)
+  configure_file (${CMAKE_CURRENT_SOURCE_DIR}/user.doxygen.in
+                  ${CMAKE_CURRENT_BINARY_DIR}/user.doxygen)
+  add_custom_target (docs-cpp COMMAND ${DOXYGEN_EXECUTABLE} user.doxygen)
+  add_dependencies (docs docs-cpp)
+  # HTML files are generated to ./html - put those in the install.
+  install (DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html/"
+           DESTINATION "${PROTON_SHARE}/docs/api-cpp"
+           COMPONENT documentation
+           ${OPTIONAL_ARG})
+endif (DOXYGEN_FOUND)
+
+set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES html)

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

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


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


Mime
View raw message