summaryrefslogtreecommitdiff
path: root/qpid/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/cpp')
-rw-r--r--qpid/cpp/bindings/qmf/Makefile.am10
-rw-r--r--qpid/cpp/bindings/qmf/python/Makefile.am9
-rw-r--r--qpid/cpp/bindings/qmf/python/python.i120
-rw-r--r--qpid/cpp/bindings/qmf/python/qmf.py854
-rw-r--r--qpid/cpp/bindings/qmf/qmfengine.i30
-rw-r--r--qpid/cpp/bindings/qmf/ruby/Makefile.am4
-rw-r--r--qpid/cpp/bindings/qmf/ruby/qmf.rb1131
-rw-r--r--qpid/cpp/bindings/qmf/ruby/ruby.i42
-rw-r--r--qpid/cpp/bindings/qmf/tests/Makefile.am8
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/agent_ruby.rb111
-rw-r--r--qpid/cpp/bindings/qmf/tests/python_agent.py192
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/python_console.py99
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/ruby_console.rb61
-rwxr-xr-xqpid/cpp/bindings/qmf/tests/run_interop_tests64
-rw-r--r--qpid/cpp/configure.ac2
-rw-r--r--qpid/cpp/docs/api/doxygen_mainpage.h2
-rw-r--r--qpid/cpp/docs/api/user.doxygen.in4
-rw-r--r--qpid/cpp/examples/CMakeLists.txt1
-rw-r--r--qpid/cpp/examples/Makefile.am2
-rw-r--r--qpid/cpp/examples/messaging/CMakeLists.txt32
-rw-r--r--qpid/cpp/examples/messaging/Makefile.am54
-rw-r--r--qpid/cpp/examples/messaging/client.cpp76
-rw-r--r--qpid/cpp/examples/messaging/map_receiver.cpp54
-rw-r--r--qpid/cpp/examples/messaging/map_sender.cpp66
-rw-r--r--qpid/cpp/examples/messaging/queue_listener.cpp82
-rw-r--r--qpid/cpp/examples/messaging/queue_receiver.cpp65
-rw-r--r--qpid/cpp/examples/messaging/queue_sender.cpp65
-rw-r--r--qpid/cpp/examples/messaging/server.cpp76
-rw-r--r--qpid/cpp/examples/messaging/topic_listener.cpp82
-rw-r--r--qpid/cpp/examples/messaging/topic_receiver.cpp66
-rw-r--r--qpid/cpp/examples/messaging/topic_sender.cpp78
-rw-r--r--qpid/cpp/include/qmf/Agent.h287
-rw-r--r--qpid/cpp/include/qmf/AgentObject.h95
-rw-r--r--qpid/cpp/include/qmf/Connection.h125
-rw-r--r--qpid/cpp/include/qmf/ConnectionSettings.h143
-rw-r--r--qpid/cpp/include/qmf/QmfImportExport.h33
-rw-r--r--qpid/cpp/include/qpid/client/Connection.h14
-rw-r--r--qpid/cpp/include/qpid/client/amqp0_10/Codecs.h61
-rw-r--r--qpid/cpp/include/qpid/framing/FieldTable.h9
-rw-r--r--qpid/cpp/include/qpid/framing/FieldValue.h120
-rw-r--r--qpid/cpp/include/qpid/framing/List.h77
-rw-r--r--qpid/cpp/include/qpid/framing/Uuid.h27
-rw-r--r--qpid/cpp/include/qpid/management/Manageable.h2
-rw-r--r--qpid/cpp/include/qpid/messaging/Address.h58
-rw-r--r--qpid/cpp/include/qpid/messaging/Codec.h44
-rw-r--r--qpid/cpp/include/qpid/messaging/Connection.h67
-rw-r--r--qpid/cpp/include/qpid/messaging/Filter.h48
-rw-r--r--qpid/cpp/include/qpid/messaging/Message.h88
-rw-r--r--qpid/cpp/include/qpid/messaging/MessageContent.h90
-rw-r--r--qpid/cpp/include/qpid/messaging/MessageListener.h49
-rw-r--r--qpid/cpp/include/qpid/messaging/Receiver.h115
-rw-r--r--qpid/cpp/include/qpid/messaging/Sender.h57
-rw-r--r--qpid/cpp/include/qpid/messaging/Session.h99
-rw-r--r--qpid/cpp/include/qpid/messaging/Variant.h167
-rwxr-xr-xqpid/cpp/include/qpid/sys/windows/Condition.h1
-rwxr-xr-xqpid/cpp/include/qpid/sys/windows/Mutex.h1
-rw-r--r--qpid/cpp/src/CMakeLists.txt68
-rw-r--r--qpid/cpp/src/Makefile.am56
-rw-r--r--qpid/cpp/src/qmf.mk29
-rw-r--r--qpid/cpp/src/qmf/AgentEngine.cpp (renamed from qpid/cpp/src/qmf/Agent.cpp)330
-rw-r--r--qpid/cpp/src/qmf/AgentEngine.h (renamed from qpid/cpp/src/qmf/Agent.h)29
-rw-r--r--qpid/cpp/src/qmf/ConnectionSettingsImpl.cpp323
-rw-r--r--qpid/cpp/src/qmf/ConnectionSettingsImpl.h60
-rw-r--r--qpid/cpp/src/qmf/Console.h82
-rw-r--r--qpid/cpp/src/qmf/ConsoleEngine.cpp886
-rw-r--r--qpid/cpp/src/qmf/ConsoleEngine.h200
-rw-r--r--qpid/cpp/src/qmf/Object.h2
-rw-r--r--qpid/cpp/src/qmf/ObjectId.h1
-rw-r--r--qpid/cpp/src/qmf/ObjectIdImpl.cpp5
-rw-r--r--qpid/cpp/src/qmf/ObjectImpl.cpp6
-rw-r--r--qpid/cpp/src/qmf/Protocol.cpp52
-rw-r--r--qpid/cpp/src/qmf/Protocol.h67
-rw-r--r--qpid/cpp/src/qmf/ResilientConnection.cpp76
-rw-r--r--qpid/cpp/src/qmf/ResilientConnection.h17
-rw-r--r--qpid/cpp/src/qmf/Schema.h23
-rw-r--r--qpid/cpp/src/qmf/SchemaImpl.cpp460
-rw-r--r--qpid/cpp/src/qmf/SchemaImpl.h40
-rw-r--r--qpid/cpp/src/qmf/SequenceManager.cpp50
-rw-r--r--qpid/cpp/src/qmf/SequenceManager.h52
-rw-r--r--qpid/cpp/src/qmf/Value.h2
-rw-r--r--qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp4
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/Connection.cpp6
-rw-r--r--qpid/cpp/src/qpid/broker/Daemon.cpp2
-rw-r--r--qpid/cpp/src/qpid/broker/Exchange.cpp19
-rw-r--r--qpid/cpp/src/qpid/broker/Exchange.h2
-rw-r--r--qpid/cpp/src/qpid/broker/Link.cpp5
-rw-r--r--qpid/cpp/src/qpid/broker/SessionAdapter.cpp6
-rw-r--r--qpid/cpp/src/qpid/client/Demux.h21
-rw-r--r--qpid/cpp/src/qpid/client/Results.cpp1
-rw-r--r--qpid/cpp/src/qpid/client/SessionImpl.cpp14
-rw-r--r--qpid/cpp/src/qpid/client/SessionImpl.h12
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp461
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.h68
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp299
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/CodecsInternal.h41
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.cpp48
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.h50
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp181
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h69
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp244
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.h91
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/MessageSink.h52
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/MessageSource.h47
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp64
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h46
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp190
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h165
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp98
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h118
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp375
-rw-r--r--qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h202
-rw-r--r--qpid/cpp/src/qpid/cluster/UpdateClient.cpp2
-rw-r--r--qpid/cpp/src/qpid/framing/FieldTable.cpp20
-rw-r--r--qpid/cpp/src/qpid/framing/FieldValue.cpp35
-rw-r--r--qpid/cpp/src/qpid/framing/List.cpp83
-rw-r--r--qpid/cpp/src/qpid/framing/Uuid.cpp31
-rw-r--r--qpid/cpp/src/qpid/management/Manageable.cpp2
-rw-r--r--qpid/cpp/src/qpid/management/ManagementAgent.cpp4
-rw-r--r--qpid/cpp/src/qpid/messaging/Address.cpp49
-rw-r--r--qpid/cpp/src/qpid/messaging/Connection.cpp90
-rw-r--r--qpid/cpp/src/qpid/messaging/ConnectionImpl.h45
-rw-r--r--qpid/cpp/src/qpid/messaging/Filter.cpp39
-rw-r--r--qpid/cpp/src/qpid/messaging/Message.cpp70
-rw-r--r--qpid/cpp/src/qpid/messaging/MessageImpl.cpp205
-rw-r--r--qpid/cpp/src/qpid/messaging/MessageImpl.h134
-rw-r--r--qpid/cpp/src/qpid/messaging/Receiver.cpp51
-rw-r--r--qpid/cpp/src/qpid/messaging/ReceiverImpl.h52
-rw-r--r--qpid/cpp/src/qpid/messaging/Sender.cpp44
-rw-r--r--qpid/cpp/src/qpid/messaging/SenderImpl.h44
-rw-r--r--qpid/cpp/src/qpid/messaging/Session.cpp117
-rw-r--r--qpid/cpp/src/qpid/messaging/SessionImpl.h65
-rw-r--r--qpid/cpp/src/qpid/messaging/Variant.cpp603
-rw-r--r--qpid/cpp/src/qpid/sys/Timer.cpp5
-rw-r--r--qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp26
-rw-r--r--qpid/cpp/src/qpid/sys/uuid.h (renamed from qpid/cpp/include/qpid/sys/uuid.h)0
-rw-r--r--qpid/cpp/src/qpid/sys/windows/uuid.h (renamed from qpid/cpp/include/qpid/sys/windows/uuid.h)0
-rw-r--r--qpid/cpp/src/qpidd.cpp2
-rw-r--r--qpid/cpp/src/tests/CMakeLists.txt2
-rw-r--r--qpid/cpp/src/tests/FieldTable.cpp32
-rw-r--r--qpid/cpp/src/tests/Makefile.am9
-rw-r--r--qpid/cpp/src/tests/MessagingSessionTests.cpp360
-rw-r--r--qpid/cpp/src/tests/Variant.cpp157
-rwxr-xr-xqpid/cpp/src/tests/cli_tests.py22
-rw-r--r--qpid/cpp/src/tests/cluster_python_tests_failing.txt1
-rwxr-xr-xqpid/cpp/src/tests/federation.py79
-rw-r--r--qpid/cpp/src/tests/qpid_stream.cpp163
-rw-r--r--qpid/cpp/src/tests/txtest.cpp9
148 files changed, 12682 insertions, 1308 deletions
diff --git a/qpid/cpp/bindings/qmf/Makefile.am b/qpid/cpp/bindings/qmf/Makefile.am
index 68312a4208..eebb4b94de 100644
--- a/qpid/cpp/bindings/qmf/Makefile.am
+++ b/qpid/cpp/bindings/qmf/Makefile.am
@@ -20,6 +20,14 @@
if HAVE_SWIG
EXTRA_DIST = qmfengine.i
-SUBDIRS = ruby tests
+SUBDIRS = tests
+
+if HAVE_RUBY_DEVEL
+SUBDIRS += ruby
+endif
+
+if HAVE_PYTHON_DEVEL
+SUBDIRS += python
+endif
endif
diff --git a/qpid/cpp/bindings/qmf/python/Makefile.am b/qpid/cpp/bindings/qmf/python/Makefile.am
index 7b3f4d3be7..f51d26bfad 100644
--- a/qpid/cpp/bindings/qmf/python/Makefile.am
+++ b/qpid/cpp/bindings/qmf/python/Makefile.am
@@ -35,11 +35,12 @@ pylibdir = $(PYTHON_LIB)
lib_LTLIBRARIES = _qmfengine.la
-_qmfengine_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)"
-_qmfengine_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfcommon.la
+#_qmfengine_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)"
+#_qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".so"
+_qmfengine_la_LDFLAGS = -avoid-version -module -shared
+_qmfengine_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfagent.la
_qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(srcdir)/qmf -I$(PYTHON_INC)
-_qmfengine_la_SOURCES = \
- qmfengine.cpp
+nodist__qmfengine_la_SOURCES = qmfengine.cpp
CLEANFILES = $(generated_file_list)
diff --git a/qpid/cpp/bindings/qmf/python/python.i b/qpid/cpp/bindings/qmf/python/python.i
index ea14efd4dd..5e25d155f9 100644
--- a/qpid/cpp/bindings/qmf/python/python.i
+++ b/qpid/cpp/bindings/qmf/python/python.i
@@ -19,17 +19,125 @@
%module qmfengine
-// These are probably wrong.. just to get it to compile for now.
-%typemap (in) void *
-{
- $1 = (void *) $input;
+
+/* unsigned32 Convert from Python --> C */
+%typemap(in) uint32_t {
+ if (PyInt_Check($input)) {
+ $1 = (uint32_t) PyInt_AsUnsignedLongMask($input);
+ } else if (PyLong_Check($input)) {
+ $1 = (uint32_t) PyLong_AsUnsignedLong($input);
+ } else {
+ SWIG_exception_fail(SWIG_ValueError, "unknown integer type");
+ }
+}
+
+/* unsinged32 Convert from C --> Python */
+%typemap(out) uint32_t {
+ $result = PyInt_FromLong((long)$1);
+}
+
+
+/* unsigned16 Convert from Python --> C */
+%typemap(in) uint16_t {
+ if (PyInt_Check($input)) {
+ $1 = (uint16_t) PyInt_AsUnsignedLongMask($input);
+ } else if (PyLong_Check($input)) {
+ $1 = (uint16_t) PyLong_AsUnsignedLong($input);
+ } else {
+ SWIG_exception_fail(SWIG_ValueError, "unknown integer type");
+ }
+}
+
+/* unsigned16 Convert from C --> Python */
+%typemap(out) uint16_t {
+ $result = PyInt_FromLong((long)$1);
+}
+
+
+/* signed32 Convert from Python --> C */
+%typemap(in) int32_t {
+ if (PyInt_Check($input)) {
+ $1 = (int32_t) PyInt_AsLong($input);
+ } else if (PyLong_Check($input)) {
+ $1 = (int32_t) PyLong_AsLong($input);
+ } else {
+ SWIG_exception_fail(SWIG_ValueError, "unknown integer type");
+ }
+}
+
+/* signed32 Convert from C --> Python */
+%typemap(out) int32_t {
+ $result = PyInt_FromLong((long)$1);
+}
+
+
+/* unsigned64 Convert from Python --> C */
+%typemap(in) uint64_t {
+%#ifdef HAVE_LONG_LONG
+ if (PyLong_Check($input)) {
+ $1 = (uint64_t)PyLong_AsUnsignedLongLong($input);
+ } else if (PyInt_Check($input)) {
+ $1 = (uint64_t)PyInt_AsUnsignedLongLongMask($input);
+ } else
+%#endif
+ {
+ SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - uint64_t input too large");
+ }
+}
+
+/* unsigned64 Convert from C --> Python */
+%typemap(out) uint64_t {
+%#ifdef HAVE_LONG_LONG
+ $result = PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)$1);
+%#else
+ SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - uint64_t output too large");
+%#endif
+}
+
+/* signed64 Convert from Python --> C */
+%typemap(in) int64_t {
+%#ifdef HAVE_LONG_LONG
+ if (PyLong_Check($input)) {
+ $1 = (int64_t)PyLong_AsLongLong($input);
+ } else if (PyInt_Check($input)) {
+ $1 = (int64_t)PyInt_AsLong($input);
+ } else
+%#endif
+ {
+ SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - int64_t input too large");
+ }
+}
+
+/* signed64 Convert from C --> Python */
+%typemap(out) int64_t {
+%#ifdef HAVE_LONG_LONG
+ $result = PyLong_FromLongLong((PY_LONG_LONG)$1);
+%#else
+ SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - int64_t output too large");
+%#endif
}
-%typemap (out) void *
-{
+
+/* Convert from Python --> C */
+%typemap(in) void * {
+ $1 = (void *)$input;
+}
+
+/* Convert from C --> Python */
+%typemap(out) void * {
$result = (PyObject *) $1;
+ Py_INCREF($result);
+}
+
+%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT64) uint64_t {
+ $1 = PyLong_Check($input) ? 1 : 0;
}
+%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT32) uint32_t {
+ $1 = PyInt_Check($input) ? 1 : 0;
+}
+
+
%include "../qmfengine.i"
diff --git a/qpid/cpp/bindings/qmf/python/qmf.py b/qpid/cpp/bindings/qmf/python/qmf.py
new file mode 100644
index 0000000000..265f204852
--- /dev/null
+++ b/qpid/cpp/bindings/qmf/python/qmf.py
@@ -0,0 +1,854 @@
+#
+# 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.
+#
+import sys
+import socket
+import os
+from threading import Thread
+from threading import RLock
+import qmfengine
+from qmfengine import (ACCESS_READ_CREATE, ACCESS_READ_ONLY, ACCESS_READ_WRITE)
+from qmfengine import (CLASS_EVENT, CLASS_OBJECT)
+from qmfengine import (DIR_IN, DIR_IN_OUT, DIR_OUT)
+from qmfengine import (TYPE_ABSTIME, TYPE_ARRAY, TYPE_BOOL, TYPE_DELTATIME,
+ TYPE_DOUBLE, TYPE_FLOAT, TYPE_INT16, TYPE_INT32, TYPE_INT64,
+ TYPE_INT8, TYPE_LIST, TYPE_LSTR, TYPE_MAP, TYPE_OBJECT,
+ TYPE_REF, TYPE_SSTR, TYPE_UINT16, TYPE_UINT32, TYPE_UINT64,
+ TYPE_UINT8, TYPE_UUID)
+
+
+ ##==============================================================================
+ ## CONNECTION
+ ##==============================================================================
+
+class ConnectionSettings:
+ #attr_reader :impl
+ def __init__(self, url=None):
+ if url:
+ self.impl = qmfengine.ConnectionSettings(url)
+ else:
+ self.impl = qmfengine.ConnectionSettings()
+
+
+ def set_attr(self, key, val):
+ if type(val) == str:
+ _v = qmfengine.Value(TYPE_LSTR)
+ _v.setString(val)
+ elif type(val) == bool:
+ _v = qmfengine.Value(TYPE_BOOL)
+ _v.setBool(val)
+ elif type(val) == int:
+ _v = qmfengine.Value(TYPE_UINT32)
+ _v.setUint(val)
+ else:
+ raise ArgumentError("Value for attribute '%s' has unsupported type: %s" % ( key, type(val)))
+
+ self.impl.setAttr(key, _v)
+
+
+
+class ConnectionHandler:
+ def conn_event_connected(self): None
+ def conn_event_disconnected(self, error): None
+ def sess_event_session_closed(self, context, error): None
+ def sess_event_recv(self, context, message): None
+
+
+
+class Connection(Thread):
+ def __init__(self, settings):
+ Thread.__init__(self)
+ self._lock = RLock()
+ self.impl = qmfengine.ResilientConnection(settings.impl)
+ self._sockEngine, self._sock = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+ self.impl.setNotifyFd(self._sockEngine.fileno())
+ self._new_conn_handlers = []
+ self._conn_handlers = []
+ self.start()
+
+
+ def add_conn_handler(self, handler):
+ self._lock.acquire()
+ try:
+ self._new_conn_handlers.append(handler)
+ finally:
+ self._lock.release()
+ self._sockEngine.send("x")
+
+
+ def run(self):
+ eventImpl = qmfengine.ResilientConnectionEvent()
+ connected = False
+ new_handlers = []
+ bt_count = 0
+
+ while True:
+ # print "Waiting for socket data"
+ self._sock.recv(1)
+
+ self._lock.acquire()
+ try:
+ new_handlers = self._new_conn_handlers
+ self._new_conn_handlers = []
+ finally:
+ self._lock.release()
+
+ for nh in new_handlers:
+ self._conn_handlers.append(nh)
+ if connected:
+ nh.conn_event_connected()
+
+ new_handlers = []
+
+ valid = self.impl.getEvent(eventImpl)
+ while valid:
+ try:
+ if eventImpl.kind == qmfengine.ResilientConnectionEvent.CONNECTED:
+ connected = True
+ for h in self._conn_handlers:
+ h.conn_event_connected()
+
+ elif eventImpl.kind == qmfengine.ResilientConnectionEvent.DISCONNECTED:
+ connected = False
+ for h in self._conn_handlers:
+ h.conn_event_disconnected(eventImpl.errorText)
+
+ elif eventImpl.kind == qmfengine.ResilientConnectionEvent.SESSION_CLOSED:
+ eventImpl.sessionContext.handler.sess_event_session_closed(eventImpl.sessionContext, eventImpl.errorText)
+
+ elif eventImpl.kind == qmfengine.ResilientConnectionEvent.RECV:
+ eventImpl.sessionContext.handler.sess_event_recv(eventImpl.sessionContext, eventImpl.message)
+
+ except:
+ import traceback
+ print "Event Exception:", sys.exc_info()
+ if bt_count < 2:
+ traceback.print_exc()
+ traceback.print_stack()
+ bt_count += 1
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(eventImpl)
+
+
+
+class Session:
+ def __init__(self, conn, label, handler):
+ self._conn = conn
+ self._label = label
+ self.handler = handler
+ self.handle = qmfengine.SessionHandle()
+ result = self._conn.impl.createSession(label, self, self.handle)
+
+
+ def __del__(self):
+ self._conn.impl.destroySession(self.handle)
+
+
+
+ ##==============================================================================
+ ## OBJECTS
+ ##==============================================================================
+
+class QmfObject:
+ # attr_reader :impl, :object_class
+ def __init__(self, cls):
+ self.object_class = cls
+ self.impl = qmfengine.Object(self.object_class.impl)
+
+
+ def __del__(self):
+ self.impl.destroy()
+
+
+ def object_id(self):
+ return ObjectId(self.impl.getObjectId())
+
+
+ def set_object_id(self, oid):
+ self.impl.setObjectId(oid.impl)
+
+
+ def get_attr(self, name):
+ val = self._value(name)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.asUint()
+ elif vType == TYPE_UINT16: return val.asUint()
+ elif vType == TYPE_UINT32: return val.asUint()
+ elif vType == TYPE_UINT64: return val.asUint64()
+ elif vType == TYPE_SSTR: return val.asString()
+ elif vType == TYPE_LSTR: return val.asString()
+ elif vType == TYPE_ABSTIME: return val.asInt64()
+ elif vType == TYPE_DELTATIME: return val.asUint64()
+ elif vType == TYPE_REF: return val.asObjectId()
+ elif vType == TYPE_BOOL: return val.asBool()
+ elif vType == TYPE_FLOAT: return val.asFloat()
+ elif vType == TYPE_DOUBLE: return val.asDouble()
+ elif vType == TYPE_UUID: return val.asUuid()
+ elif vType == TYPE_INT8: return val.asInt()
+ elif vType == TYPE_INT16: return val.asInt()
+ elif vType == TYPE_INT32: return val.asInt()
+ elif vType == TYPE_INT64: return val.asInt64()
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ print "Unsupported type for get_attr?", val.getType()
+ return None
+
+
+ def set_attr(self, name, v):
+ val = self._value(name)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.setUint(v)
+ elif vType == TYPE_UINT16: return val.setUint(v)
+ elif vType == TYPE_UINT32: return val.setUint(v)
+ elif vType == TYPE_UINT64: return val.setUint64(v)
+ elif vType == TYPE_SSTR:
+ if v: return val.setString(v)
+ else: return val.setString('')
+ elif vType == TYPE_LSTR:
+ if v: return val.setString(v)
+ else: return val.setString('')
+ elif vType == TYPE_ABSTIME: return val.setInt64(v)
+ elif vType == TYPE_DELTATIME: return val.setUint64(v)
+ elif vType == TYPE_REF: return val.setObjectId(v.impl)
+ elif vType == TYPE_BOOL: return val.setBool(v)
+ elif vType == TYPE_FLOAT: return val.setFloat(v)
+ elif vType == TYPE_DOUBLE: return val.setDouble(v)
+ elif vType == TYPE_UUID: return val.setUuid(v)
+ elif vType == TYPE_INT8: return val.setInt(v)
+ elif vType == TYPE_INT16: return val.setInt(v)
+ elif vType == TYPE_INT32: return val.setInt(v)
+ elif vType == TYPE_INT64: return val.setInt64(v)
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ print "Unsupported type for get_attr?", val.getType()
+ return None
+
+
+ def __getitem__(self, name):
+ return self.get_attr(name)
+
+
+ def __setitem__(self, name, value):
+ self.set_attr(name, value)
+
+
+ def inc_attr(self, name, by=1):
+ self.set_attr(name, self.get_attr(name) + by)
+
+
+ def dec_attr(self, name, by=1):
+ self.set_attr(name, self.get_attr(name) - by)
+
+
+ def _value(self, name):
+ val = self.impl.getValue(name)
+ if not val:
+ raise ArgumentError("Attribute '%s' not defined for class %s" % (name, self.object_class.impl.getName()))
+ return val
+
+
+
+class ConsoleObject(QmfObject):
+ # attr_reader :current_time, :create_time, :delete_time
+ def __init__(self, cls):
+ QmfObject.__init__(self, cls)
+
+
+ def update(self): pass
+ def mergeUpdate(self, newObject): pass
+ def is_deleted(self):
+ return self.delete_time > 0
+ def index(self): pass
+ def method_missing(self, name, *args): pass
+
+
+
+class ObjectId:
+ def __init__(self, impl=None):
+ if impl:
+ self.impl = impl
+ else:
+ self.impl = qmfengine.ObjectId()
+
+
+ def object_num_high(self):
+ return self.impl.getObjectNumHi()
+
+
+ def object_num_low(self):
+ return self.impl.getObjectNumLo()
+
+
+ def __eq__(self, other):
+ if self.__class__ != other.__class__: return False
+ return (self.impl.getObjectNumHi() == other.impl.getObjectNumHi() and
+ self.impl.getObjectNumLo() == other.impl.getObjectNumLo())
+
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+
+
+class Arguments:
+ def __init__(self, map):
+ self.map = map
+ self._by_hash = {}
+ key_count = self.map.keyCount()
+ a = 0
+ while a < key_count:
+ self._by_hash[self.map.key(a)] = self.by_key(self.map.key(a))
+ a += 1
+
+
+ def __getitem__(self, key):
+ return self._by_hash[key]
+
+
+ def __setitem__(self, key, value):
+ self._by_hash[key] = value
+ self.set(key, value)
+
+
+ def __iter__(self):
+ return _by_hash.__iter__
+
+
+ def by_key(self, key):
+ val = self.map.byKey(key)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.asUint()
+ elif vType == TYPE_UINT16: return val.asUint()
+ elif vType == TYPE_UINT32: return val.asUint()
+ elif vType == TYPE_UINT64: return val.asUint64()
+ elif vType == TYPE_SSTR: return val.asString()
+ elif vType == TYPE_LSTR: return val.asString()
+ elif vType == TYPE_ABSTIME: return val.asInt64()
+ elif vType == TYPE_DELTATIME: return val.asUint64()
+ elif vType == TYPE_REF: return val.asObjectId()
+ elif vType == TYPE_BOOL: return val.asBool()
+ elif vType == TYPE_FLOAT: return val.asFloat()
+ elif vType == TYPE_DOUBLE: return val.asDouble()
+ elif vType == TYPE_UUID: return val.asUuid()
+ elif vType == TYPE_INT8: return val.asInt()
+ elif vType == TYPE_INT16: return val.asInt()
+ elif vType == TYPE_INT32: return val.asInt()
+ elif vType == TYPE_INT64: return val.asInt64()
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ print "Unsupported Type for Get?", val.getType()
+ return None
+
+
+ def set(self, key, value):
+ val = self.map.byKey(key)
+ vType = val.getType()
+ if vType == TYPE_UINT8: return val.setUint(value)
+ elif vType == TYPE_UINT16: return val.setUint(value)
+ elif vType == TYPE_UINT32: return val.setUint(value)
+ elif vType == TYPE_UINT64: return val.setUint64(value)
+ elif vType == TYPE_SSTR:
+ if value:
+ return val.setString(value)
+ else:
+ return val.setString('')
+ elif vType == TYPE_LSTR:
+ if value:
+ return val.setString(value)
+ else:
+ return val.setString('')
+ elif vType == TYPE_ABSTIME: return val.setInt64(value)
+ elif vType == TYPE_DELTATIME: return val.setUint64(value)
+ elif vType == TYPE_REF: return val.setObjectId(value.impl)
+ elif vType == TYPE_BOOL: return val.setBool(value)
+ elif vType == TYPE_FLOAT: return val.setFloat(value)
+ elif vType == TYPE_DOUBLE: return val.setDouble(value)
+ elif vType == TYPE_UUID: return val.setUuid(value)
+ elif vType == TYPE_INT8: return val.setInt(value)
+ elif vType == TYPE_INT16: return val.setInt(value)
+ elif vType == TYPE_INT32: return val.setInt(value)
+ elif vType == TYPE_INT64: return val.setInt64(value)
+ else:
+ # when TYPE_MAP
+ # when TYPE_OBJECT
+ # when TYPE_LIST
+ # when TYPE_ARRAY
+ print "Unsupported Type for Set?", val.getType()
+ return None
+
+
+
+class Query:
+ def __init__(self, i=None):
+ if i:
+ self.impl = i
+ else:
+ self.impl = qmfengine.Query()
+
+
+ def package_name(self): return self.impl.getPackage()
+ def class_name(self): return self.impl.getClass()
+ def object_id(self):
+ _objid = self.impl.getObjectId()
+ if _objid:
+ return ObjectId(_objid)
+ else:
+ return None
+ OPER_AND = qmfengine.Query.OPER_AND
+ OPER_OR = qmfengine.Query.OPER_OR
+
+
+
+ ##==============================================================================
+ ## SCHEMA
+ ##==============================================================================
+
+
+
+class SchemaArgument:
+ #attr_reader :impl
+ def __init__(self, name, typecode, kwargs={}):
+ self.impl = qmfengine.SchemaArgument(name, typecode)
+ if kwargs.has_key("dir"): self.impl.setDirection(kwargs["dir"])
+ if kwargs.has_key("unit"): self.impl.setUnit(kwargs["unit"])
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+
+class SchemaMethod:
+ # attr_reader :impl
+ def __init__(self, name, kwargs={}):
+ self.impl = qmfengine.SchemaMethod(name)
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+ self._arguments = []
+
+
+ def add_argument(self, arg):
+ self._arguments.append(arg)
+ self.impl.addArgument(arg.impl)
+
+
+class SchemaProperty:
+ #attr_reader :impl
+ def __init__(self, name, typecode, kwargs={}):
+ self.impl = qmfengine.SchemaProperty(name, typecode)
+ if kwargs.has_key("access"): self.impl.setAccess(kwargs["access"])
+ if kwargs.has_key("index"): self.impl.setIndex(kwargs["index"])
+ if kwargs.has_key("optional"): self.impl.setOptional(kwargs["optional"])
+ if kwargs.has_key("unit"): self.impl.setUnit(kwargs["unit"])
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+ def name(self):
+ return self.impl.getName()
+
+
+
+class SchemaStatistic:
+ # attr_reader :impl
+ def __init__(self, name, typecode, kwargs={}):
+ self.impl = qmfengine.SchemaStatistic(name, typecode)
+ if kwargs.has_key("unit"): self.impl.setUnit(kwargs["unit"])
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+
+
+
+class SchemaClassKey:
+ #attr_reader :impl
+ def __init__(self, i):
+ self.impl = i
+
+
+ def get_package(self):
+ self.impl.getPackageName()
+
+
+ def get_class(self):
+ self.impl.getClassName()
+
+
+
+class SchemaObjectClass:
+ # attr_reader :impl
+ def __init__(self, package, name, kwargs={}):
+ self.impl = qmfengine.SchemaObjectClass(package, name)
+ self._properties = []
+ self._statistics = []
+ self._methods = []
+
+
+ def add_property(self, prop):
+ self._properties.append(prop)
+ self.impl.addProperty(prop.impl)
+
+
+ def add_statistic(self, stat):
+ self._statistics.append(stat)
+ self.impl.addStatistic(stat.impl)
+
+
+ def add_method(self, meth):
+ self._methods.append(meth)
+ self.impl.addMethod(meth.impl)
+
+
+ def name(self):
+ return self.impl.getName()
+
+
+ def properties(self):
+ return self._properties
+
+
+class SchemaEventClass:
+ # attr_reader :impl
+ def __init__(self, package, name, kwargs={}):
+ self.impl = qmfengine.SchemaEventClass(package, name)
+ if kwargs.has_key("desc"): self.impl.setDesc(kwargs["desc"])
+ self._arguments = []
+
+
+ def add_argument(self, arg):
+ self._arguments.append(arg)
+ self.impl.addArgument(arg.impl)
+
+
+
+ ##==============================================================================
+ ## CONSOLE
+ ##==============================================================================
+
+
+
+class ConsoleHandler:
+ def agent_added(self, agent): pass
+ def agent_deleted(self, agent): pass
+ def new_package(self, package): pass
+ def new_class(self, class_key): pass
+ def object_update(self, obj, hasProps, hasStats): pass
+ def event_received(self, event): pass
+ def agent_heartbeat(self, agent, timestamp): pass
+ def method_response(self, resp): pass
+ def broker_info(self, broker): pass
+
+
+
+class Console:
+ # attr_reader :impl
+ def initialize(handler=None, kwargs={}):
+ self._handler = handler
+ self.impl = qmfengine.ConsoleEngine()
+ self._event = qmfengine.ConsoleEvent()
+ self._broker_list = []
+
+
+ def add_connection(self, conn):
+ broker = Broker(self, conn)
+ self._broker_list.append(broker)
+ return broker
+
+
+ def del_connection(self, broker): pass
+
+
+ def get_packages(self): pass
+
+
+ def get_classes(self, package): pass
+
+
+ def get_schema(self, class_key): pass
+
+
+ def bind_package(self, package): pass
+
+
+ def bind_class(self, kwargs = {}): pass
+
+
+ def get_agents(self, broker=None): pass
+
+
+ def get_objects(self, query, kwargs = {}): pass
+
+
+ def start_sync(self, query): pass
+
+
+ def touch_sync(self, sync): pass
+
+
+ def end_sync(self, sync): pass
+
+
+ def do_console_events(self):
+ count = 0
+ valid = self.impl.getEvent(self._event)
+ while valid:
+ count += 1
+ print "Console Event:", self._event.kind
+ if self._event.kind == qmfengine.ConsoleEvent.AGENT_ADDED:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.AGENT_DELETED:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.NEW_PACKAGE:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.NEW_CLASS:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.OBJECT_UPDATE:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.EVENT_RECEIVED:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.AGENT_HEARTBEAT:
+ pass
+ elif self._event.kind == qmfengine.ConsoleEvent.METHOD_RESPONSE:
+ pass
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(self._event)
+ return count
+
+
+
+class Broker(ConnectionHandler):
+ # attr_reader :impl
+ def __init__(self, console, conn):
+ self._console = console
+ self._conn = conn
+ self._session = None
+ self._event = qmfengine.BrokerEvent()
+ self._xmtMessage = qmfengine.Message()
+ self.impl = qmfengine.BrokerProxy(self._console.impl)
+ self._console.impl.addConnection(self.impl, self)
+ self._conn.add_conn_handler(self)
+
+
+ def do_broker_events(self):
+ count = 0
+ valid = self.impl.getEvent(self._event)
+ while valid:
+ count += 1
+ print "Broker Event: ", self._event.kind
+ if self._event.kind == qmfengine.BrokerEvent.BROKER_INFO:
+ pass
+ elif self._event.kind == qmfengine.BrokerEvent.DECLARE_QUEUE:
+ self._conn.impl.declareQueue(self._session.handle, self._event.name)
+ elif self._event.kind == qmfengine.BrokerEvent.DELETE_QUEUE:
+ self._conn.impl.deleteQueue(self._session.handle, self._event.name)
+ elif self._event.kind == qmfengine.BrokerEvent.BIND:
+ self._conn.impl.bind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey)
+ elif self._event.kind == qmfengine.BrokerEvent.UNBIND:
+ self._conn.impl.unbind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey)
+ elif self._event.kind == qmfengine.BrokerEvent.SETUP_COMPLETE:
+ self.impl.startProtocol()
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(self._event)
+
+ return count
+
+
+ def do_broker_messages(self):
+ count = 0
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+ while valid:
+ count += 1
+ self._conn.impl.sendMessage(self._session.handle, self._xmtMessage)
+ self.impl.popXmt()
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+
+ return count
+
+
+ def do_events(self):
+ while True:
+ ccnt = self._console.do_console_events()
+ bcnt = do_broker_events()
+ mcnt = do_broker_messages()
+ if ccnt == 0 and bcnt == 0 and mcnt == 0:
+ break;
+
+
+ def conn_event_connected(self):
+ print "Console Connection Established..."
+ self._session = Session(self._conn, "qmfc-%s.%d" % (socket.gethostname(), os.getpid()), self)
+ self.impl.sessionOpened(self._session.handle)
+ self.do_events()
+
+
+ def conn_event_disconnected(self, error):
+ print "Console Connection Lost"
+ pass
+
+
+ def sess_event_session_closed(self, context, error):
+ print "Console Session Lost"
+ self.impl.sessionClosed()
+
+
+ def sess_event_recv(self, context, message):
+ self.impl.handleRcvMessage(message)
+ self.do_events()
+
+
+
+ ##==============================================================================
+ ## AGENT
+ ##==============================================================================
+
+
+
+class AgentHandler:
+ def get_query(self, context, query, userId): None
+ def method_call(self, context, name, object_id, args, userId): None
+
+
+
+class Agent(ConnectionHandler):
+ def __init__(self, handler, label=""):
+ if label == "":
+ self._agentLabel = "rb-%s.%d" % (socket.gethostname(), os.getpid())
+ else:
+ self._agentLabel = label
+ self._conn = None
+ self._handler = handler
+ self.impl = qmfengine.AgentEngine(self._agentLabel)
+ self._event = qmfengine.AgentEvent()
+ self._xmtMessage = qmfengine.Message()
+
+
+ def set_connection(self, conn):
+ self._conn = conn
+ self._conn.add_conn_handler(self)
+
+
+ def register_class(self, cls):
+ self.impl.registerClass(cls.impl)
+
+
+ def alloc_object_id(self, low = 0, high = 0):
+ return ObjectId(self.impl.allocObjectId(low, high))
+
+
+ def query_response(self, context, obj):
+ self.impl.queryResponse(context, obj.impl)
+
+
+ def query_complete(self, context):
+ self.impl.queryComplete(context)
+
+
+ def method_response(self, context, status, text, arguments):
+ self.impl.methodResponse(context, status, text, arguments.map)
+
+
+ def do_agent_events(self):
+ count = 0
+ valid = self.impl.getEvent(self._event)
+ while valid:
+ count += 1
+ if self._event.kind == qmfengine.AgentEvent.GET_QUERY:
+ self._handler.get_query(self._event.sequence,
+ Query(self._event.query),
+ self._event.authUserId)
+
+ elif self._event.kind == qmfengine.AgentEvent.START_SYNC:
+ pass
+ elif self._event.kind == qmfengine.AgentEvent.END_SYNC:
+ pass
+ elif self._event.kind == qmfengine.AgentEvent.METHOD_CALL:
+ args = Arguments(self._event.arguments)
+ self._handler.method_call(self._event.sequence, self._event.name,
+ ObjectId(self._event.objectId),
+ args, self._event.authUserId)
+
+ elif self._event.kind == qmfengine.AgentEvent.DECLARE_QUEUE:
+ self._conn.impl.declareQueue(self._session.handle, self._event.name)
+
+ elif self._event.kind == qmfengine.AgentEvent.DELETE_QUEUE:
+ self._conn.impl.deleteQueue(self._session.handle, self._event.name)
+
+ elif self._event.kind == qmfengine.AgentEvent.BIND:
+ self._conn.impl.bind(self._session.handle, self._event.exchange,
+ self._event.name, self._event.bindingKey)
+
+ elif self._event.kind == qmfengine.AgentEvent.UNBIND:
+ self._conn.impl.unbind(self._session.handle, self._event.exchange,
+ self._event.name, self._event.bindingKey)
+
+ elif self._event.kind == qmfengine.AgentEvent.SETUP_COMPLETE:
+ self.impl.startProtocol()
+
+ self.impl.popEvent()
+ valid = self.impl.getEvent(self._event)
+ return count
+
+
+ def do_agent_messages(self):
+ count = 0
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+ while valid:
+ count += 1
+ self._conn.impl.sendMessage(self._session.handle, self._xmtMessage)
+ self.impl.popXmt()
+ valid = self.impl.getXmtMessage(self._xmtMessage)
+ return count
+
+
+ def do_events(self):
+ while True:
+ ecnt = self.do_agent_events()
+ mcnt = self.do_agent_messages()
+ if ecnt == 0 and mcnt == 0:
+ break
+
+
+ def conn_event_connected(self):
+ print "Agent Connection Established..."
+ self._session = Session(self._conn,
+ "qmfa-%s.%d" % (socket.gethostname(), os.getpid()),
+ self)
+ self.impl.newSession()
+ self.do_events()
+
+
+ def conn_event_disconnected(self, error):
+ print "Agent Connection Lost"
+ pass
+
+
+ def sess_event_session_closed(self, context, error):
+ print "Agent Session Lost"
+ pass
+
+
+ def sess_event_recv(self, context, message):
+ self.impl.handleRcvMessage(message)
+ self.do_events()
+
+
diff --git a/qpid/cpp/bindings/qmf/qmfengine.i b/qpid/cpp/bindings/qmf/qmfengine.i
index 3c67d92031..d3500c9b8f 100644
--- a/qpid/cpp/bindings/qmf/qmfengine.i
+++ b/qpid/cpp/bindings/qmf/qmfengine.i
@@ -19,24 +19,24 @@
%{
-#include "Agent.h"
-#include <ResilientConnection.h>
+#include "qmf/AgentEngine.h"
+#include "qmf/ConsoleEngine.h"
+#include "qmf/ResilientConnection.h"
%}
-
-%include <Query.h>
-%include <Message.h>
-%include <Agent.h>
-%include <ResilientConnection.h>
-%include <Typecode.h>
-%include <Schema.h>
-%include <Value.h>
-%include <ObjectId.h>
-%include <Object.h>
-
-%include <qpid/client/ClientImportExport.h>
-%include <qpid/client/ConnectionSettings.h>
+%include <qmf/QmfImportExport.h>
+%include <qmf/Query.h>
+%include <qmf/Message.h>
+%include <qmf/AgentEngine.h>
+%include <qmf/ConsoleEngine.h>
+%include <qmf/ConnectionSettings.h>
+%include <qmf/ResilientConnection.h>
+%include <qmf/Typecode.h>
+%include <qmf/Schema.h>
+%include <qmf/Value.h>
+%include <qmf/ObjectId.h>
+%include <qmf/Object.h>
%inline {
diff --git a/qpid/cpp/bindings/qmf/ruby/Makefile.am b/qpid/cpp/bindings/qmf/ruby/Makefile.am
index 532fdb6875..0537dd1cd8 100644
--- a/qpid/cpp/bindings/qmf/ruby/Makefile.am
+++ b/qpid/cpp/bindings/qmf/ruby/Makefile.am
@@ -19,7 +19,7 @@
if HAVE_RUBY_DEVEL
-INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src/qmf -I$(top_srcdir)/src -I$(top_builddir)/src
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src
EXTRA_DIST = ruby.i
BUILT_SOURCES = qmfengine.cpp
@@ -36,7 +36,7 @@ rubylibarchdir = $(RUBY_LIB_ARCH)
rubylibarch_LTLIBRARIES = qmfengine.la
qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)"
-qmfengine_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfcommon.la
+qmfengine_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfagent.la
qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH)
nodist_qmfengine_la_SOURCES = qmfengine.cpp
diff --git a/qpid/cpp/bindings/qmf/ruby/qmf.rb b/qpid/cpp/bindings/qmf/ruby/qmf.rb
index 7ee447c675..21fbf6c157 100644
--- a/qpid/cpp/bindings/qmf/ruby/qmf.rb
+++ b/qpid/cpp/bindings/qmf/ruby/qmf.rb
@@ -20,517 +20,846 @@
require 'qmfengine'
require 'thread'
require 'socket'
+require 'monitor'
module Qmf
- # Pull all the TYPE_* constants into Qmf namespace. Maybe there's an easier way?
- Qmfengine.constants.each do |c|
- if c.index('TYPE_') == 0 or c.index('ACCESS_') == 0 or c.index('DIR_') == 0
- const_set(c, Qmfengine.const_get(c))
- end
+ # Pull all the TYPE_* constants into Qmf namespace. Maybe there's an easier way?
+ Qmfengine.constants.each do |c|
+ if c.index('TYPE_') == 0 or c.index('ACCESS_') == 0 or c.index('DIR_') == 0 or c.index('CLASS_') == 0
+ const_set(c, Qmfengine.const_get(c))
end
+ end
+
+ ##==============================================================================
+ ## CONNECTION
+ ##==============================================================================
- class ConnectionSettings < Qmfengine::ConnectionSettings
+ class ConnectionSettings
+ attr_reader :impl
+
+ def initialize(url = nil)
+ if url
+ @impl = Qmfengine::ConnectionSettings.new(url)
+ else
+ @impl = Qmfengine::ConnectionSettings.new()
+ end
end
- class ConnectionEvent
- def conn_event_connected(); end
- def conn_event_disconnected(error); end
- def conn_event_session_closed(context, error); end
- def conn_event_recv(context, message); end
+ def set_attr(key, val)
+ if val.class == String
+ v = Qmfengine::Value.new(TYPE_LSTR)
+ v.setString(val)
+ elsif val.class == TrueClass or val.class == FalseClass
+ v = Qmfengine::Value.new(TYPE_BOOL)
+ v.setBool(val)
+ elsif val.class == Fixnum
+ v = Qmfengine::Value.new(TYPE_UINT32)
+ v.setUint(val)
+ else
+ raise ArgumentError, "Value for attribute '#{key}' has unsupported type: #{val.class}"
+ end
+
+ @impl.setAttr(key, v)
end
+ end
- class Query
- attr_reader :impl
- def initialize(i)
- @impl = i
- end
+ class ConnectionHandler
+ def conn_event_connected(); end
+ def conn_event_disconnected(error); end
+ def sess_event_session_closed(context, error); end
+ def sess_event_recv(context, message); end
+ end
- def package_name
- @impl.getPackage
- end
+ class Connection
+ include MonitorMixin
- def class_name
- @impl.getClass
- end
+ attr_reader :impl
- def object_id
- objid = @impl.getObjectId
- if objid.class == NilClass
- return nil
- end
- return ObjectId.new(objid)
+ def initialize(settings)
+ super()
+ @impl = Qmfengine::ResilientConnection.new(settings.impl)
+ @sockEngine, @sock = Socket::socketpair(Socket::PF_UNIX, Socket::SOCK_STREAM, 0)
+ @impl.setNotifyFd(@sockEngine.fileno)
+ @new_conn_handlers = []
+ @conn_handlers = []
+
+ @thread = Thread.new do
+ run
end
end
- class AgentHandler
- def get_query(context, query, userId); end
- def method_call(context, name, object_id, args, userId); end
+ def add_conn_handler(handler)
+ synchronize do
+ @new_conn_handlers << handler
+ end
+ @sockEngine.write("x")
end
- class Connection
- attr_reader :impl
+ def run()
+ eventImpl = Qmfengine::ResilientConnectionEvent.new
+ connected = nil
+ new_handlers = nil
+ bt_count = 0
- def initialize(settings, event_handler = nil, delay_min = 1, delay_max = 128, delay_factor = 2)
- @impl = Qmfengine::ResilientConnection.new(settings, delay_min, delay_max, delay_factor)
- @sockEngine, @sock = Socket::socketpair(Socket::PF_UNIX, Socket::SOCK_STREAM, 0)
- @impl.setNotifyFd(@sockEngine.fileno)
- @new_conn_handlers = Array.new
- @conn_handlers = Array.new
- @sess_handlers = Array.new
+ while :true
+ @sock.read(1)
- @thread = Thread.new do
- run
+ synchronize do
+ new_handlers = @new_conn_handlers
+ @new_conn_handlers = []
end
- end
-
- def add_conn_handler(handler)
- @new_conn_handlers.push(handler)
- @sockEngine.write("x")
- end
- def add_sess_handler(handler)
- @sess_handlers.push(handler)
- end
-
- def run()
- event = Qmfengine::ResilientConnectionEvent.new
- connected = nil
- while :true
- @sock.read(1)
+ new_handlers.each do |nh|
+ @conn_handlers << nh
+ nh.conn_event_connected() if connected
+ end
+ new_handlers = nil
- @new_conn_handlers.each do |nh|
- @conn_handlers.push(nh)
- nh.conn_event_connected() if connected
- end
- @new_conn_handlers = Array.new
-
- valid = @impl.getEvent(event)
- while valid
- begin
- case event.kind
- when Qmfengine::ResilientConnectionEvent::CONNECTED
- connected = :true
- @conn_handlers.each { |h| h.conn_event_connected() }
- when Qmfengine::ResilientConnectionEvent::DISCONNECTED
- connected = nil
- @conn_handlers.each { |h| h.conn_event_disconnected(event.errorText) }
- when Qmfengine::ResilientConnectionEvent::SESSION_CLOSED
- event.sessionContext.handler.sess_event_session_closed(event.sessionContext, event.errorText)
- when Qmfengine::ResilientConnectionEvent::RECV
- event.sessionContext.handler.sess_event_recv(event.sessionContext, event.message)
- end
- rescue Exception => ex
- puts "Event Exception: #{ex}"
+ valid = @impl.getEvent(eventImpl)
+ while valid
+ begin
+ case eventImpl.kind
+ when Qmfengine::ResilientConnectionEvent::CONNECTED
+ connected = :true
+ @conn_handlers.each { |h| h.conn_event_connected() }
+ when Qmfengine::ResilientConnectionEvent::DISCONNECTED
+ connected = nil
+ @conn_handlers.each { |h| h.conn_event_disconnected(eventImpl.errorText) }
+ when Qmfengine::ResilientConnectionEvent::SESSION_CLOSED
+ eventImpl.sessionContext.handler.sess_event_session_closed(eventImpl.sessionContext, eventImpl.errorText)
+ when Qmfengine::ResilientConnectionEvent::RECV
+ eventImpl.sessionContext.handler.sess_event_recv(eventImpl.sessionContext, eventImpl.message)
+ end
+ rescue Exception => ex
+ puts "Event Exception: #{ex}"
+ if bt_count < 2
puts ex.backtrace
+ bt_count += 1
end
- @impl.popEvent
- valid = @impl.getEvent(event)
end
+ @impl.popEvent
+ valid = @impl.getEvent(eventImpl)
end
end
end
+ end
- class Session
- attr_reader :handle, :handler
+ class Session
+ attr_reader :handle, :handler
- def initialize(conn, label, handler)
- @conn = conn
- @label = label
- @handler = handler
- @handle = Qmfengine::SessionHandle.new
- @conn.add_sess_handler(@handler)
- result = @conn.impl.createSession(label, self, @handle)
- end
+ def initialize(conn, label, handler)
+ @conn = conn
+ @label = label
+ @handler = handler
+ @handle = Qmfengine::SessionHandle.new
+ result = @conn.impl.createSession(label, self, @handle)
end
- class ObjectId
- attr_reader :impl
- def initialize(impl=nil)
- if impl
- @impl = impl
- else
- @impl = Qmfengine::ObjectId.new
- end
- end
- def object_num_high
- return @impl.getObjectNumHi
- end
- def object_num_low
- return @impl.getObjectNumLo
- end
+ def destroy()
+ @conn.impl.destroySession(@handle)
end
+ end
- class Arguments
- attr_reader :map
- def initialize(map)
- @map = map
- @by_hash = {}
- key_count = @map.keyCount
- a = 0
- while a < key_count
- @by_hash[@map.key(a)] = by_key(@map.key(a))
- a += 1
- end
- end
+ ##==============================================================================
+ ## OBJECTS
+ ##==============================================================================
- def [] (key)
- return @by_hash[key]
- end
+ class QmfObject
+ attr_reader :impl, :object_class
+ def initialize(cls)
+ @object_class = cls
+ @impl = Qmfengine::Object.new(@object_class.impl)
+ end
- def []= (key, value)
- @by_hash[key] = value
- set(key, value)
- end
+ def destroy
+ @impl.destroy
+ end
- def each
- @by_hash.each { |k, v| yield(k, v) }
- end
+ def object_id
+ return ObjectId.new(@impl.getObjectId)
+ end
- def by_key(key)
- val = @map.byKey(key)
- case val.getType
- when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
- when TYPE_UINT64 then val.asUint64
- when TYPE_SSTR, TYPE_LSTR then val.asString
- when TYPE_ABSTIME then val.asInt64
- when TYPE_DELTATIME then val.asUint64
- when TYPE_REF then val.asObjectId
- when TYPE_BOOL then val.asBool
- when TYPE_FLOAT then val.asFloat
- when TYPE_DOUBLE then val.asDouble
- when TYPE_UUID then val.asUuid
- when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
- when TYPE_INT64 then val.asInt64
- when TYPE_MAP
- when TYPE_OBJECT
- when TYPE_LIST
- when TYPE_ARRAY
- end
- end
+ def set_object_id(oid)
+ @impl.setObjectId(oid.impl)
+ end
- def set(key, value)
- val = @map.byKey(key)
- case val.getType
- when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(value)
- when TYPE_UINT64 then val.setUint64(value)
- when TYPE_SSTR, TYPE_LSTR then value ? val.setString(value) : val.setString('')
- when TYPE_ABSTIME then val.setInt64(value)
- when TYPE_DELTATIME then val.setUint64(value)
- when TYPE_REF then val.setObjectId(value.impl)
- when TYPE_BOOL then value ? val.setBool(value) : val.setBool(0)
- when TYPE_FLOAT then val.setFloat(value)
- when TYPE_DOUBLE then val.setDouble(value)
- when TYPE_UUID then val.setUuid(value)
- when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(value)
- when TYPE_INT64 then val.setInt64(value)
- when TYPE_MAP
- when TYPE_OBJECT
- when TYPE_LIST
- when TYPE_ARRAY
- end
+ def get_attr(name)
+ val = value(name)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
+ when TYPE_UINT64 then val.asUint64
+ when TYPE_SSTR, TYPE_LSTR then val.asString
+ when TYPE_ABSTIME then val.asInt64
+ when TYPE_DELTATIME then val.asUint64
+ when TYPE_REF then val.asObjectId
+ when TYPE_BOOL then val.asBool
+ when TYPE_FLOAT then val.asFloat
+ when TYPE_DOUBLE then val.asDouble
+ when TYPE_UUID then val.asUuid
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
+ when TYPE_INT64 then val.asInt64
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
end
end
- class Agent
- def initialize(handler, label="")
- if label == ""
- @agentLabel = "rb-%s.%d" % [Socket.gethostname, Process::pid]
- else
- @agentLabel = label
- end
- @conn = nil
- @handler = handler
- @impl = Qmfengine::Agent.new(@agentLabel)
- @event = Qmfengine::AgentEvent.new
- @xmtMessage = Qmfengine::Message.new
+ def set_attr(name, v)
+ val = value(name)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(v)
+ when TYPE_UINT64 then val.setUint64(v)
+ when TYPE_SSTR, TYPE_LSTR then v ? val.setString(v) : val.setString('')
+ when TYPE_ABSTIME then val.setInt64(v)
+ when TYPE_DELTATIME then val.setUint64(v)
+ when TYPE_REF then val.setObjectId(v.impl)
+ when TYPE_BOOL then v ? val.setBool(v) : val.setBool(0)
+ when TYPE_FLOAT then val.setFloat(v)
+ when TYPE_DOUBLE then val.setDouble(v)
+ when TYPE_UUID then val.setUuid(v)
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(v)
+ when TYPE_INT64 then val.setInt64(v)
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
end
+ end
- def set_connection(conn)
- @conn = conn
- @conn.add_conn_handler(self)
- end
+ def [](name)
+ get_attr(name)
+ end
- def register_class(cls)
- @impl.registerClass(cls.impl)
- end
+ def []=(name, value)
+ set_attr(name, value)
+ end
- def alloc_object_id(low = 0, high = 0)
- ObjectId.new(@impl.allocObjectId(low, high))
- end
+ def inc_attr(name, by=1)
+ set_attr(name, get_attr(name) + by)
+ end
- def query_response(context, object)
- @impl.queryResponse(context, object.impl)
- end
+ def dec_attr(name, by=1)
+ set_attr(name, get_attr(name) - by)
+ end
- def query_complete(context)
- @impl.queryComplete(context)
+ private
+ def value(name)
+ val = @impl.getValue(name.to_s)
+ if val.nil?
+ raise ArgumentError, "Attribute '#{name}' not defined for class #{@object_class.impl.getName}"
end
+ return val
+ end
+ end
- def method_response(context, status, text, arguments)
- @impl.methodResponse(context, status, text, arguments.map)
- end
+ class ConsoleObject < QmfObject
+ attr_reader :current_time, :create_time, :delete_time
- def do_agent_events()
- count = 0
- valid = @impl.getEvent(@event)
- while valid
- count += 1
- case @event.kind
- when Qmfengine::AgentEvent::GET_QUERY
- @handler.get_query(@event.sequence, Query.new(@event.query), @event.authUserId)
- when Qmfengine::AgentEvent::START_SYNC
- when Qmfengine::AgentEvent::END_SYNC
- when Qmfengine::AgentEvent::METHOD_CALL
- args = Arguments.new(@event.arguments)
- @handler.method_call(@event.sequence, @event.name, ObjectId.new(@event.objectId),
- args, @event.authUserId)
- when Qmfengine::AgentEvent::DECLARE_QUEUE
- @conn.impl.declareQueue(@session.handle, @event.name)
- when Qmfengine::AgentEvent::DELETE_QUEUE
- @conn.impl.deleteQueue(@session.handle, @event.name)
- when Qmfengine::AgentEvent::BIND
- @conn.impl.bind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
- when Qmfengine::AgentEvent::UNBIND
- @conn.impl.unbind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
- when Qmfengine::AgentEvent::SETUP_COMPLETE
- @impl.startProtocol()
- end
- @impl.popEvent
- valid = @impl.getEvent(@event)
- end
- return count
- end
+ def initialize(cls)
+ super(cls)
+ end
- def do_agent_messages()
- count = 0
- valid = @impl.getXmtMessage(@xmtMessage)
- while valid
- count += 1
- @conn.impl.sendMessage(@session.handle, @xmtMessage)
- @impl.popXmt
- valid = @impl.getXmtMessage(@xmtMessage)
- end
- return count
- end
+ def update()
+ end
- def do_events()
- begin
- ecnt = do_agent_events
- mcnt = do_agent_messages
- end until ecnt == 0 and mcnt == 0
- end
+ def mergeUpdate(newObject)
+ end
- def conn_event_connected()
- puts "Agent Connection Established..."
- @session = Session.new(@conn, "qmfa-%s.%d" % [Socket.gethostname, Process::pid], self)
- @impl.newSession
- do_events
- end
+ def deleted?()
+ @delete_time > 0
+ end
- def conn_event_disconnected(error)
- puts "Agent Connection Lost"
- end
+ def index()
+ end
- def sess_event_session_closed(context, error)
- puts "Agent Session Lost"
- end
+ def method_missing(name, *args)
+ end
+ end
- def sess_event_recv(context, message)
- @impl.handleRcvMessage(message)
- do_events
+ class ObjectId
+ attr_reader :impl
+ def initialize(impl=nil)
+ if impl
+ @impl = impl
+ else
+ @impl = Qmfengine::ObjectId.new
end
end
- class SchemaArgument
- attr_reader :impl
- def initialize(name, typecode, kwargs={})
- @impl = Qmfengine::SchemaArgument.new(name, typecode)
- @impl.setDirection(kwargs[:dir]) if kwargs.include?(:dir)
- @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
- @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
- end
+ def object_num_high
+ return @impl.getObjectNumHi
end
- class SchemaMethod
- attr_reader :impl
- def initialize(name, kwargs={})
- @impl = Qmfengine::SchemaMethod.new(name)
- @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
- @arguments = []
- end
+ def object_num_low
+ return @impl.getObjectNumLo
+ end
- def add_argument(arg)
- @arguments << arg
- @impl.addArgument(arg.impl)
+ def ==(other)
+ return (@impl.getObjectNumHi == other.impl.getObjectNumHi) &&
+ (@impl.getObjectNumLo == other.impl.getObjectNumLo)
+ end
+ end
+
+ class Arguments
+ attr_reader :map
+ def initialize(map)
+ @map = map
+ @by_hash = {}
+ key_count = @map.keyCount
+ a = 0
+ while a < key_count
+ @by_hash[@map.key(a)] = by_key(@map.key(a))
+ a += 1
end
end
- class SchemaProperty
- attr_reader :impl
- def initialize(name, typecode, kwargs={})
- @impl = Qmfengine::SchemaProperty.new(name, typecode)
- @impl.setAccess(kwargs[:access]) if kwargs.include?(:access)
- @impl.setIndex(kwargs[:index]) if kwargs.include?(:index)
- @impl.setOptional(kwargs[:optional]) if kwargs.include?(:optional)
- @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
- @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ def [] (key)
+ return @by_hash[key]
+ end
+
+ def []= (key, value)
+ @by_hash[key] = value
+ set(key, value)
+ end
+
+ def each
+ @by_hash.each { |k, v| yield(k, v) }
+ end
+
+ def by_key(key)
+ val = @map.byKey(key)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
+ when TYPE_UINT64 then val.asUint64
+ when TYPE_SSTR, TYPE_LSTR then val.asString
+ when TYPE_ABSTIME then val.asInt64
+ when TYPE_DELTATIME then val.asUint64
+ when TYPE_REF then val.asObjectId
+ when TYPE_BOOL then val.asBool
+ when TYPE_FLOAT then val.asFloat
+ when TYPE_DOUBLE then val.asDouble
+ when TYPE_UUID then val.asUuid
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
+ when TYPE_INT64 then val.asInt64
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
end
+ end
- def name
- @impl.getName
+ def set(key, value)
+ val = @map.byKey(key)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(value)
+ when TYPE_UINT64 then val.setUint64(value)
+ when TYPE_SSTR, TYPE_LSTR then value ? val.setString(value) : val.setString('')
+ when TYPE_ABSTIME then val.setInt64(value)
+ when TYPE_DELTATIME then val.setUint64(value)
+ when TYPE_REF then val.setObjectId(value.impl)
+ when TYPE_BOOL then value ? val.setBool(value) : val.setBool(0)
+ when TYPE_FLOAT then val.setFloat(value)
+ when TYPE_DOUBLE then val.setDouble(value)
+ when TYPE_UUID then val.setUuid(value)
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(value)
+ when TYPE_INT64 then val.setInt64(value)
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
end
end
+ end
- class SchemaStatistic
- attr_reader :impl
- def initialize(name, typecode, kwargs={})
- @impl = Qmfengine::SchemaStatistic.new(name, typecode)
- @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
- @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ class Query
+ attr_reader :impl
+ def initialize(i)
+ @impl = i
+ end
+
+ def package_name
+ @impl.getPackage
+ end
+
+ def class_name
+ @impl.getClass
+ end
+
+ def object_id
+ objid = @impl.getObjectId
+ if objid.class == NilClass
+ return nil
end
+ return ObjectId.new(objid)
+ end
+ end
+
+ ##==============================================================================
+ ## SCHEMA
+ ##==============================================================================
+
+ class SchemaArgument
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ @impl = Qmfengine::SchemaArgument.new(name, typecode)
+ @impl.setDirection(kwargs[:dir]) if kwargs.include?(:dir)
+ @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+ end
+
+ class SchemaMethod
+ attr_reader :impl
+ def initialize(name, kwargs={})
+ @impl = Qmfengine::SchemaMethod.new(name)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ @arguments = []
+ end
+
+ def add_argument(arg)
+ @arguments << arg
+ @impl.addArgument(arg.impl)
+ end
+ end
+
+ class SchemaProperty
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ @impl = Qmfengine::SchemaProperty.new(name, typecode)
+ @impl.setAccess(kwargs[:access]) if kwargs.include?(:access)
+ @impl.setIndex(kwargs[:index]) if kwargs.include?(:index)
+ @impl.setOptional(kwargs[:optional]) if kwargs.include?(:optional)
+ @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+
+ def name
+ @impl.getName
+ end
+ end
+
+ class SchemaStatistic
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ @impl = Qmfengine::SchemaStatistic.new(name, typecode)
+ @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
end
+ end
- class SchemaObjectClass
- attr_reader :impl
- def initialize(package, name, kwargs={})
+ class SchemaClassKey
+ attr_reader :impl
+ def initialize(i)
+ @impl = i
+ end
+
+ def get_package()
+ @impl.getPackageName()
+ end
+
+ def get_class()
+ @impl.getClassName()
+ end
+ end
+
+ class SchemaObjectClass
+ attr_reader :impl
+ def initialize(package='', name='', kwargs={})
+ @properties = []
+ @statistics = []
+ @methods = []
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ else
@impl = Qmfengine::SchemaObjectClass.new(package, name)
- @properties = []
- @statistics = []
- @methods = []
end
+ end
- def add_property(prop)
- @properties << prop
- @impl.addProperty(prop.impl)
- end
+ def add_property(prop)
+ @properties << prop
+ @impl.addProperty(prop.impl)
+ end
- def add_statistic(stat)
- @statistics << stat
- @impl.addStatistic(stat.impl)
- end
+ def add_statistic(stat)
+ @statistics << stat
+ @impl.addStatistic(stat.impl)
+ end
- def add_method(meth)
- @methods << meth
- @impl.addMethod(meth.impl)
- end
+ def add_method(meth)
+ @methods << meth
+ @impl.addMethod(meth.impl)
+ end
- def name
- @impl.getName
- end
+ def name
+ @impl.getClassKey.getClassName
+ end
- def properties
- unless @properties
- @properties = []
- @impl.getPropertyCount.times do |i|
- @properties << @impl.getProperty(i)
- end
+ def properties
+ unless @properties
+ @properties = []
+ @impl.getPropertyCount.times do |i|
+ @properties << @impl.getProperty(i)
end
- return @properties
end
+ return @properties
end
-
- class SchemaEventClass
- attr_reader :impl
- def initialize(package, name, kwargs={})
+ end
+
+ class SchemaEventClass
+ attr_reader :impl
+ def initialize(package='', name='', kwargs={})
+ @arguments = []
+ if kwargs.include?(:impl)
+ @impl = kwargs[:impl]
+ else
@impl = Qmfengine::SchemaEventClass.new(package, name)
@impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
- @arguments = []
end
+ end
- def add_argument(arg)
- @arguments << arg
- @impl.addArgument(arg.impl)
- end
+ def add_argument(arg)
+ @arguments << arg
+ @impl.addArgument(arg.impl)
end
- class QmfObject
- attr_reader :impl, :object_class
- def initialize(cls)
- @object_class = cls
- @impl = Qmfengine::Object.new(@object_class.impl)
- end
+ def name
+ @impl.getClassKey.getClassName
+ end
+ end
+
+ ##==============================================================================
+ ## CONSOLE
+ ##==============================================================================
+
+ class ConsoleHandler
+ def agent_added(agent); end
+ def agent_deleted(agent); end
+ def new_package(package); end
+ def new_class(class_key); end
+ def object_update(object, hasProps, hasStats); end
+ def event_received(event); end
+ def agent_heartbeat(agent, timestamp); end
+ def method_response(resp); end
+ def broker_info(broker); end
+ end
+
+ class Console
+ attr_reader :impl
+
+ def initialize(handler = nil, kwargs={})
+ @handler = handler
+ @impl = Qmfengine::ConsoleEngine.new
+ @event = Qmfengine::ConsoleEvent.new
+ @broker_list = []
+ end
- def destroy
- @impl.destroy
- end
+ def add_connection(conn)
+ broker = Broker.new(self, conn)
+ @broker_list << broker
+ return broker
+ end
- def object_id
- return ObjectId.new(@impl.getObjectId)
- end
+ def del_connection(broker)
+ end
- def set_object_id(oid)
- @impl.setObjectId(oid.impl)
+ def get_packages()
+ plist = []
+ count = @impl.packageCount
+ for i in 0...count
+ plist << @impl.getPackageName(i)
end
+ return plist
+ end
- def get_attr(name)
- val = value(name)
- case val.getType
- when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
- when TYPE_UINT64 then val.asUint64
- when TYPE_SSTR, TYPE_LSTR then val.asString
- when TYPE_ABSTIME then val.asInt64
- when TYPE_DELTATIME then val.asUint64
- when TYPE_REF then val.asObjectId
- when TYPE_BOOL then val.asBool
- when TYPE_FLOAT then val.asFloat
- when TYPE_DOUBLE then val.asDouble
- when TYPE_UUID then val.asUuid
- when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
- when TYPE_INT64 then val.asInt64
- when TYPE_MAP
- when TYPE_OBJECT
- when TYPE_LIST
- when TYPE_ARRAY
+ def get_classes(package, kind=CLASS_OBJECT)
+ clist = []
+ count = @impl.classCount(package)
+ for i in 0...count
+ key = @impl.getClass(package, i)
+ class_kind = @impl.getClassKind(key)
+ if class_kind == kind
+ if kind == CLASS_OBJECT
+ clist << SchemaObjectClass.new('', '', :impl => @impl.getObjectClass(key))
+ elsif kind == CLASS_EVENT
+ clist << SchemaEventClass.new('', '', :impl => @impl.getEventClass(key))
+ end
end
end
- def set_attr(name, v)
- val = value(name)
- case val.getType
- when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(v)
- when TYPE_UINT64 then val.setUint64(v)
- when TYPE_SSTR, TYPE_LSTR then v ? val.setString(v) : val.setString('')
- when TYPE_ABSTIME then val.setInt64(v)
- when TYPE_DELTATIME then val.setUint64(v)
- when TYPE_REF then val.setObjectId(v.impl)
- when TYPE_BOOL then v ? val.setBool(v) : val.setBool(0)
- when TYPE_FLOAT then val.setFloat(v)
- when TYPE_DOUBLE then val.setDouble(v)
- when TYPE_UUID then val.setUuid(v)
- when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(v)
- when TYPE_INT64 then val.setInt64(v)
- when TYPE_MAP
- when TYPE_OBJECT
- when TYPE_LIST
- when TYPE_ARRAY
+ return clist
+ end
+
+ def get_schema(class_key)
+ end
+
+ def bind_package(package)
+ end
+
+ def bind_class(kwargs = {})
+ end
+
+ def get_agents(broker = nil)
+ end
+
+ def get_objects(query, kwargs = {})
+ end
+
+ def start_sync(query)
+ end
+
+ def touch_sync(sync)
+ end
+
+ def end_sync(sync)
+ end
+
+ def do_console_events()
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ puts "Console Event: #{@event.kind}"
+ case @event.kind
+ when Qmfengine::ConsoleEvent::AGENT_ADDED
+ when Qmfengine::ConsoleEvent::AGENT_DELETED
+ when Qmfengine::ConsoleEvent::NEW_PACKAGE
+ when Qmfengine::ConsoleEvent::NEW_CLASS
+ when Qmfengine::ConsoleEvent::OBJECT_UPDATE
+ when Qmfengine::ConsoleEvent::EVENT_RECEIVED
+ when Qmfengine::ConsoleEvent::AGENT_HEARTBEAT
+ when Qmfengine::ConsoleEvent::METHOD_RESPONSE
end
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
end
+ return count
+ end
+ end
+
+ class Broker < ConnectionHandler
+ include MonitorMixin
+ attr_reader :impl
+
+ def initialize(console, conn)
+ super()
+ @console = console
+ @conn = conn
+ @session = nil
+ @cv = new_cond
+ @stable = nil
+ @event = Qmfengine::BrokerEvent.new
+ @xmtMessage = Qmfengine::Message.new
+ @impl = Qmfengine::BrokerProxy.new(@console.impl)
+ @console.impl.addConnection(@impl, self)
+ @conn.add_conn_handler(self)
+ end
- def [](name)
- get_attr(name)
+ def waitForStable(timeout = nil)
+ synchronize do
+ return if @stable
+ if timeout
+ unless @cv.wait(timeout) { @stable }
+ raise "Timed out waiting for broker connection to become stable"
+ end
+ else
+ while not @stable
+ @cv.wait
+ end
+ end
end
+ end
- def []=(name, value)
- set_attr(name, value)
+ def do_broker_events()
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ puts "Broker Event: #{@event.kind}"
+ case @event.kind
+ when Qmfengine::BrokerEvent::BROKER_INFO
+ when Qmfengine::BrokerEvent::DECLARE_QUEUE
+ @conn.impl.declareQueue(@session.handle, @event.name)
+ when Qmfengine::BrokerEvent::DELETE_QUEUE
+ @conn.impl.deleteQueue(@session.handle, @event.name)
+ when Qmfengine::BrokerEvent::BIND
+ @conn.impl.bind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::BrokerEvent::UNBIND
+ @conn.impl.unbind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::BrokerEvent::SETUP_COMPLETE
+ @impl.startProtocol
+ when Qmfengine::BrokerEvent::STABLE
+ synchronize do
+ @stable = :true
+ @cv.signal
+ end
+ end
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
end
+ return count
+ end
- def inc_attr(name, by=1)
- set_attr(name, get_attr(name) + by)
+ def do_broker_messages()
+ count = 0
+ valid = @impl.getXmtMessage(@xmtMessage)
+ while valid
+ count += 1
+ @conn.impl.sendMessage(@session.handle, @xmtMessage)
+ @impl.popXmt
+ valid = @impl.getXmtMessage(@xmtMessage)
end
+ return count
+ end
+
+ def do_events()
+ begin
+ ccnt = @console.do_console_events
+ bcnt = do_broker_events
+ mcnt = do_broker_messages
+ end until ccnt == 0 and bcnt == 0 and mcnt == 0
+ end
- def dec_attr(name, by=1)
- set_attr(name, get_attr(name) - by)
+ def conn_event_connected()
+ puts "Console Connection Established..."
+ @session = Session.new(@conn, "qmfc-%s.%d" % [Socket.gethostname, Process::pid], self)
+ @impl.sessionOpened(@session.handle)
+ do_events
+ end
+
+ def conn_event_disconnected(error)
+ puts "Console Connection Lost"
+ end
+
+ def sess_event_session_closed(context, error)
+ puts "Console Session Lost"
+ @impl.sessionClosed()
+ end
+
+ def sess_event_recv(context, message)
+ @impl.handleRcvMessage(message)
+ do_events
+ end
+ end
+
+ ##==============================================================================
+ ## AGENT
+ ##==============================================================================
+
+ class AgentHandler
+ def get_query(context, query, userId); end
+ def method_call(context, name, object_id, args, userId); end
+ end
+
+ class Agent < ConnectionHandler
+ def initialize(handler, label="")
+ if label == ""
+ @agentLabel = "rb-%s.%d" % [Socket.gethostname, Process::pid]
+ else
+ @agentLabel = label
+ end
+ @conn = nil
+ @handler = handler
+ @impl = Qmfengine::AgentEngine.new(@agentLabel)
+ @event = Qmfengine::AgentEvent.new
+ @xmtMessage = Qmfengine::Message.new
+ end
+
+ def set_connection(conn)
+ @conn = conn
+ @conn.add_conn_handler(self)
+ end
+
+ def register_class(cls)
+ @impl.registerClass(cls.impl)
+ end
+
+ def alloc_object_id(low = 0, high = 0)
+ ObjectId.new(@impl.allocObjectId(low, high))
+ end
+
+ def query_response(context, object)
+ @impl.queryResponse(context, object.impl)
+ end
+
+ def query_complete(context)
+ @impl.queryComplete(context)
+ end
+
+ def method_response(context, status, text, arguments)
+ @impl.methodResponse(context, status, text, arguments.map)
+ end
+
+ def do_agent_events()
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ case @event.kind
+ when Qmfengine::AgentEvent::GET_QUERY
+ @handler.get_query(@event.sequence, Query.new(@event.query), @event.authUserId)
+ when Qmfengine::AgentEvent::START_SYNC
+ when Qmfengine::AgentEvent::END_SYNC
+ when Qmfengine::AgentEvent::METHOD_CALL
+ args = Arguments.new(@event.arguments)
+ @handler.method_call(@event.sequence, @event.name, ObjectId.new(@event.objectId),
+ args, @event.authUserId)
+ when Qmfengine::AgentEvent::DECLARE_QUEUE
+ @conn.impl.declareQueue(@session.handle, @event.name)
+ when Qmfengine::AgentEvent::DELETE_QUEUE
+ @conn.impl.deleteQueue(@session.handle, @event.name)
+ when Qmfengine::AgentEvent::BIND
+ @conn.impl.bind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::AgentEvent::UNBIND
+ @conn.impl.unbind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::AgentEvent::SETUP_COMPLETE
+ @impl.startProtocol()
+ end
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
end
+ return count
+ end
- private
- def value(name)
- val = @impl.getValue(name.to_s)
- if val.nil?
- raise ArgumentError, "Attribute '#{name}' not defined for class #{@object_class.impl.getName}"
- end
- return val
+ def do_agent_messages()
+ count = 0
+ valid = @impl.getXmtMessage(@xmtMessage)
+ while valid
+ count += 1
+ @conn.impl.sendMessage(@session.handle, @xmtMessage)
+ @impl.popXmt
+ valid = @impl.getXmtMessage(@xmtMessage)
end
+ return count
+ end
+
+ def do_events()
+ begin
+ ecnt = do_agent_events
+ mcnt = do_agent_messages
+ end until ecnt == 0 and mcnt == 0
+ end
+
+ def conn_event_connected()
+ puts "Agent Connection Established..."
+ @session = Session.new(@conn, "qmfa-%s.%d" % [Socket.gethostname, Process::pid], self)
+ @impl.newSession
+ do_events
+ end
+
+ def conn_event_disconnected(error)
+ puts "Agent Connection Lost"
+ end
+
+ def sess_event_session_closed(context, error)
+ puts "Agent Session Lost"
+ end
+
+ def sess_event_recv(context, message)
+ @impl.handleRcvMessage(message)
+ do_events
end
+ end
end
diff --git a/qpid/cpp/bindings/qmf/ruby/ruby.i b/qpid/cpp/bindings/qmf/ruby/ruby.i
index a8a2a87a97..b7fed403bd 100644
--- a/qpid/cpp/bindings/qmf/ruby/ruby.i
+++ b/qpid/cpp/bindings/qmf/ruby/ruby.i
@@ -38,17 +38,33 @@
%typemap (out) uint16_t
{
- $result = UINT2NUM((unsigned short) $1);
+ $result = UINT2NUM((uint16_t) $1);
}
%typemap (in) uint32_t
{
- $1 = NUM2UINT ($input);
+ if (TYPE($input) == T_BIGNUM)
+ $1 = NUM2UINT($input);
+ else
+ $1 = FIX2UINT($input);
}
%typemap (out) uint32_t
{
- $result = UINT2NUM((unsigned int) $1);
+ $result = UINT2NUM((uint32_t) $1);
+}
+
+%typemap (in) int32_t
+{
+ if (TYPE($input) == T_BIGNUM)
+ $1 = NUM2INT($input);
+ else
+ $1 = FIX2INT($input);
+}
+
+%typemap (out) int32_t
+{
+ $result = INT2NUM((int32_t) $1);
}
%typemap (typecheck, precedence=SWIG_TYPECHECK_INTEGER) uint32_t {
@@ -57,12 +73,28 @@
%typemap (in) uint64_t
{
- $1 = NUM2ULONG ($input);
+ if (TYPE($input) == T_BIGNUM)
+ $1 = NUM2ULL($input);
+ else
+ $1 = (uint64_t) FIX2LONG($input);
}
%typemap (out) uint64_t
{
- $result = ULONG2NUM((unsigned long) $1);
+ $result = ULL2NUM((uint64_t) $1);
+}
+
+%typemap (in) int64_t
+{
+ if (TYPE($input) == T_BIGNUM)
+ $1 = NUM2LL($input);
+ else
+ $1 = (int64_t) FIX2LONG($input);
+}
+
+%typemap (out) int64_t
+{
+ $result = LL2NUM((int64_t) $1);
}
%typemap (typecheck, precedence=SWIG_TYPECHECK_INTEGER) uint64_t {
diff --git a/qpid/cpp/bindings/qmf/tests/Makefile.am b/qpid/cpp/bindings/qmf/tests/Makefile.am
index 1ff8a64bed..182771e16b 100644
--- a/qpid/cpp/bindings/qmf/tests/Makefile.am
+++ b/qpid/cpp/bindings/qmf/tests/Makefile.am
@@ -18,4 +18,10 @@
#
TESTS = run_interop_tests
-EXTRA_DIST = run_interop_tests
+
+EXTRA_DIST = \
+ agent_ruby.rb \
+ python_agent.py \
+ python_console.py \
+ ruby_console.rb \
+ run_interop_tests
diff --git a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb
index d395810cb6..75de2b5fa1 100755
--- a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb
+++ b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb
@@ -29,13 +29,34 @@ class Model
@parent_class = Qmf::SchemaObjectClass.new("org.apache.qpid.qmf", "parent")
@parent_class.add_property(Qmf::SchemaProperty.new("name", Qmf::TYPE_SSTR, :index => true))
@parent_class.add_property(Qmf::SchemaProperty.new("state", Qmf::TYPE_SSTR))
+
+ @parent_class.add_property(Qmf::SchemaProperty.new("uint64val", Qmf::TYPE_UINT64))
@parent_class.add_property(Qmf::SchemaProperty.new("uint32val", Qmf::TYPE_UINT32))
+ @parent_class.add_property(Qmf::SchemaProperty.new("uint16val", Qmf::TYPE_UINT16))
+ @parent_class.add_property(Qmf::SchemaProperty.new("uint8val", Qmf::TYPE_UINT8))
+
+ @parent_class.add_property(Qmf::SchemaProperty.new("int64val", Qmf::TYPE_INT64))
+ @parent_class.add_property(Qmf::SchemaProperty.new("int32val", Qmf::TYPE_INT32))
+ @parent_class.add_property(Qmf::SchemaProperty.new("int16val", Qmf::TYPE_INT16))
+ @parent_class.add_property(Qmf::SchemaProperty.new("int8val", Qmf::TYPE_INT8))
+
@parent_class.add_statistic(Qmf::SchemaStatistic.new("queryCount", Qmf::TYPE_UINT32, :unit => "query", :desc => "Query count"))
+ method = Qmf::SchemaMethod.new("echo", :desc => "Check responsiveness of the agent object")
+ method.add_argument(Qmf::SchemaArgument.new("sequence", Qmf::TYPE_UINT32, :dir => Qmf::DIR_IN_OUT))
+ @parent_class.add_method(method)
+
+ method = Qmf::SchemaMethod.new("set_numerics", :desc => "Set the numeric values in the object")
+ method.add_argument(Qmf::SchemaArgument.new("test", Qmf::TYPE_SSTR, :dir => Qmf::DIR_IN))
+ @parent_class.add_method(method)
+
method = Qmf::SchemaMethod.new("create_child", :desc => "Create a new child object")
method.add_argument(Qmf::SchemaArgument.new("child_name", Qmf::TYPE_LSTR, :dir => Qmf::DIR_IN))
method.add_argument(Qmf::SchemaArgument.new("child_ref", Qmf::TYPE_REF, :dir => Qmf::DIR_OUT))
+ @parent_class.add_method(method)
+ method = Qmf::SchemaMethod.new("probe_userid", :desc => "Return the user-id for this method call")
+ method.add_argument(Qmf::SchemaArgument.new("userid", Qmf::TYPE_SSTR, :dir => Qmf::DIR_OUT))
@parent_class.add_method(method)
@child_class = Qmf::SchemaObjectClass.new("org.apache.qpid.qmf", "child")
@@ -55,24 +76,83 @@ class App < Qmf::AgentHandler
#@parent.inc_attr("queryCount")
if query.class_name == 'parent'
@agent.query_response(context, @parent)
+ elsif query.object_id == @parent_oid
+ @agent.query_response(context, @parent)
end
@agent.query_complete(context)
end
def method_call(context, name, object_id, args, userId)
# puts "Method: user=#{userId} context=#{context} method=#{name} object_num=#{object_id.object_num_low if object_id} args=#{args}"
- oid = @agent.alloc_object_id(2)
- args['child_ref'] = oid
- @child = Qmf::QmfObject.new(@model.child_class)
- @child.set_attr("name", args.by_key("child_name"))
- @child.set_object_id(oid)
- @agent.method_response(context, 0, "OK", args)
+
+ if name == "echo"
+ @agent.method_response(context, 0, "OK", args)
+
+ elsif name == "set_numerics"
+ retCode = 0
+ retText = "OK"
+
+ if args['test'] == "big"
+ @parent.set_attr("uint64val", 0x9494949449494949)
+ @parent.set_attr("uint32val", 0xa5a55a5a)
+ @parent.set_attr("uint16val", 0xb66b)
+ @parent.set_attr("uint8val", 0xc7)
+
+ @parent.set_attr("int64val", 1000000000000000000)
+ @parent.set_attr("int32val", 1000000000)
+ @parent.set_attr("int16val", 10000)
+ @parent.set_attr("int8val", 100)
+
+ elsif args['test'] == "small"
+ @parent.set_attr("uint64val", 4)
+ @parent.set_attr("uint32val", 5)
+ @parent.set_attr("uint16val", 6)
+ @parent.set_attr("uint8val", 7)
+
+ @parent.set_attr("int64val", 8)
+ @parent.set_attr("int32val", 9)
+ @parent.set_attr("int16val", 10)
+ @parent.set_attr("int8val", 11)
+
+ elsif args['test'] == "negative"
+ @parent.set_attr("uint64val", 0)
+ @parent.set_attr("uint32val", 0)
+ @parent.set_attr("uint16val", 0)
+ @parent.set_attr("uint8val", 0)
+
+ @parent.set_attr("int64val", -10000000000)
+ @parent.set_attr("int32val", -100000)
+ @parent.set_attr("int16val", -1000)
+ @parent.set_attr("int8val", -100)
+
+ else
+ retCode = 1
+ retText = "Invalid argument value for test"
+ end
+
+ @agent.method_response(context, retCode, retText, args)
+
+ elsif name == "create_child"
+ oid = @agent.alloc_object_id(2)
+ args['child_ref'] = oid
+ @child = Qmf::QmfObject.new(@model.child_class)
+ @child.set_attr("name", args.by_key("child_name"))
+ @child.set_object_id(oid)
+ @agent.method_response(context, 0, "OK", args)
+
+ elsif name == "probe_userid"
+ args['userid'] = userId
+ @agent.method_response(context, 0, "OK", args)
+
+ else
+ @agent.method_response(context, 1, "Unimplemented Method: #{name}", args)
+ end
end
def main
@settings = Qmf::ConnectionSettings.new
- @settings.host = ARGV[0] if ARGV.size > 0
- @settings.port = ARGV[1].to_i if ARGV.size > 1
+ @settings.set_attr("host", ARGV[0]) if ARGV.size > 0
+ @settings.set_attr("port", ARGV[1].to_i) if ARGV.size > 1
@connection = Qmf::Connection.new(@settings)
@agent = Qmf::Agent.new(self)
@@ -84,10 +164,19 @@ class App < Qmf::AgentHandler
@parent = Qmf::QmfObject.new(@model.parent_class)
@parent.set_attr("name", "Parent One")
@parent.set_attr("state", "OPERATIONAL")
- @parent.set_attr("uint32val", 0xa5a5a5a5)
- oid = @agent.alloc_object_id(1)
- @parent.set_object_id(oid)
+ @parent.set_attr("uint64val", 0)
+ @parent.set_attr("uint32val", 0)
+ @parent.set_attr("uint16val", 0)
+ @parent.set_attr("uint8val", 0)
+
+ @parent.set_attr("int64val", 0)
+ @parent.set_attr("int32val", 0)
+ @parent.set_attr("int16val", 0)
+ @parent.set_attr("int8val", 0)
+
+ @parent_oid = @agent.alloc_object_id(1)
+ @parent.set_object_id(@parent_oid)
sleep
end
diff --git a/qpid/cpp/bindings/qmf/tests/python_agent.py b/qpid/cpp/bindings/qmf/tests/python_agent.py
new file mode 100644
index 0000000000..f6cb51cbf5
--- /dev/null
+++ b/qpid/cpp/bindings/qmf/tests/python_agent.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+
+import qmf
+import sys
+import time
+
+
+class Model:
+ # attr_reader :parent_class, :child_class
+ def __init__(self):
+ self.parent_class = qmf.SchemaObjectClass("org.apache.qpid.qmf", "parent")
+ self.parent_class.add_property(qmf.SchemaProperty("name", qmf.TYPE_SSTR, {"index":True}))
+ self.parent_class.add_property(qmf.SchemaProperty("state", qmf.TYPE_SSTR))
+
+ self.parent_class.add_property(qmf.SchemaProperty("uint64val", qmf.TYPE_UINT64))
+ self.parent_class.add_property(qmf.SchemaProperty("uint32val", qmf.TYPE_UINT32))
+ self.parent_class.add_property(qmf.SchemaProperty("uint16val", qmf.TYPE_UINT16))
+ self.parent_class.add_property(qmf.SchemaProperty("uint8val", qmf.TYPE_UINT8))
+
+ self.parent_class.add_property(qmf.SchemaProperty("int64val", qmf.TYPE_INT64))
+ self.parent_class.add_property(qmf.SchemaProperty("int32val", qmf.TYPE_INT32))
+ self.parent_class.add_property(qmf.SchemaProperty("int16val", qmf.TYPE_INT16))
+ self.parent_class.add_property(qmf.SchemaProperty("int8val", qmf.TYPE_INT8))
+
+ self.parent_class.add_statistic(qmf.SchemaStatistic("queryCount", qmf.TYPE_UINT32, {"unit":"query", "desc":"Query count"}))
+
+ _method = qmf.SchemaMethod("echo", {"desc":"Check responsiveness of the agent object"})
+ _method.add_argument(qmf.SchemaArgument("sequence", qmf.TYPE_UINT32, {"dir":qmf.DIR_IN_OUT}))
+ self.parent_class.add_method(_method)
+
+ _method = qmf.SchemaMethod("set_numerics", {"desc":"Set the numeric values in the object"})
+ _method.add_argument(qmf.SchemaArgument("test", qmf.TYPE_SSTR, {"dir":qmf.DIR_IN}))
+ self.parent_class.add_method(_method)
+
+ _method = qmf.SchemaMethod("create_child", {"desc":"Create a new child object"})
+ _method.add_argument(qmf.SchemaArgument("child_name", qmf.TYPE_LSTR, {"dir":qmf.DIR_IN}))
+ _method.add_argument(qmf.SchemaArgument("child_ref", qmf.TYPE_REF, {"dir":qmf.DIR_OUT}))
+ self.parent_class.add_method(_method)
+
+ _method = qmf.SchemaMethod("probe_userid", {"desc":"Return the user-id for this method call"})
+ _method.add_argument(qmf.SchemaArgument("userid", qmf.TYPE_SSTR, {"dir":qmf.DIR_OUT}))
+ self.parent_class.add_method(_method)
+
+ self.child_class = qmf.SchemaObjectClass("org.apache.qpid.qmf", "child")
+ self.child_class.add_property(qmf.SchemaProperty("name", qmf.TYPE_SSTR, {"index":True}))
+
+
+ def register(self, agent):
+ agent.register_class(self.parent_class)
+ agent.register_class(self.child_class)
+
+
+
+class App(qmf.AgentHandler):
+ def get_query(self, context, query, userId):
+ # puts "Query: user=#{userId} context=#{context} class=#{query.class_name} object_num=#{query.object_id.object_num_low if query.object_id}"
+ self._parent.inc_attr("queryCount")
+ if query.class_name() == 'parent':
+ self._agent.query_response(context, self._parent)
+ elif query.object_id() == self._parent_oid:
+ self._agent.query_response(context, self._parent)
+ self._agent.query_complete(context)
+
+
+ def method_call(self, context, name, object_id, args, userId):
+ # puts "Method: user=#{userId} context=#{context} method=#{name} object_num=#{object_id.object_num_low if object_id} args=#{args}"
+ # oid = self._agent.alloc_object_id(2)
+ # args['child_ref'] = oid
+ # self._child = qmf.QmfObject(self._model.child_class)
+ # self._child.set_attr("name", args.by_key("child_name"))
+ # self._child.set_object_id(oid)
+ # self._agent.method_response(context, 0, "OK", args)
+ if name == "echo":
+ self._agent.method_response(context, 0, "OK", args)
+
+ elif name == "set_numerics":
+ _retCode = 0
+ _retText = "OK"
+
+ if args['test'] == "big":
+ self._parent.set_attr("uint64val", 0x9494949449494949)
+ self._parent.set_attr("uint32val", 0xa5a55a5a)
+ self._parent.set_attr("uint16val", 0xb66b)
+ self._parent.set_attr("uint8val", 0xc7)
+
+ self._parent.set_attr("int64val", 1000000000000000000)
+ self._parent.set_attr("int32val", 1000000000)
+ self._parent.set_attr("int16val", 10000)
+ self._parent.set_attr("int8val", 100)
+
+ elif args['test'] == "small":
+ self._parent.set_attr("uint64val", 4)
+ self._parent.set_attr("uint32val", 5)
+ self._parent.set_attr("uint16val", 6)
+ self._parent.set_attr("uint8val", 7)
+
+ self._parent.set_attr("int64val", 8)
+ self._parent.set_attr("int32val", 9)
+ self._parent.set_attr("int16val", 10)
+ self._parent.set_attr("int8val", 11)
+
+ elif args['test'] == "negative":
+ self._parent.set_attr("uint64val", 0)
+ self._parent.set_attr("uint32val", 0)
+ self._parent.set_attr("uint16val", 0)
+ self._parent.set_attr("uint8val", 0)
+
+ self._parent.set_attr("int64val", -10000000000)
+ self._parent.set_attr("int32val", -100000)
+ self._parent.set_attr("int16val", -1000)
+ self._parent.set_attr("int8val", -100)
+
+ else:
+ _retCode = 1
+ _retText = "Invalid argument value for test"
+
+ self._agent.method_response(context, _retCode, _retText, args)
+
+ elif name == "create_child":
+ _oid = self._agent.alloc_object_id(2)
+ args['child_ref'] = _oid
+ self._child = qmf.QmfObject(self._model.child_class)
+ self._child.set_attr("name", args["child_name"])
+ self._child.set_object_id(_oid)
+ self._agent.method_response(context, 0, "OK", args)
+
+ elif name == "probe_userid":
+ args['userid'] = userId
+ self._agent.method_response(context, 0, "OK", args)
+
+ else:
+ self._agent.method_response(context, 1, "Unimplemented Method: %s" % name, args)
+
+
+ def main(self):
+ self._settings = qmf.ConnectionSettings()
+ if len(sys.argv) > 1:
+ self._settings.set_attr("host", sys.argv[1])
+ if len(sys.argv) > 2:
+ self._settings.set_attr("port", int(sys.argv[2]))
+ self._connection = qmf.Connection(self._settings)
+ self._agent = qmf.Agent(self)
+
+ self._model = Model()
+ self._model.register(self._agent)
+
+ self._agent.set_connection(self._connection)
+
+ self._parent = qmf.QmfObject(self._model.parent_class)
+ self._parent.set_attr("name", "Parent One")
+ self._parent.set_attr("state", "OPERATIONAL")
+
+ self._parent.set_attr("uint64val", 0)
+ self._parent.set_attr("uint32val", 0)
+ self._parent.set_attr("uint16val", 0)
+ self._parent.set_attr("uint8val", 0)
+
+ self._parent.set_attr("int64val", 0)
+ self._parent.set_attr("int32val", 0)
+ self._parent.set_attr("int16val", 0)
+ self._parent.set_attr("int8val", 0)
+
+ self._parent_oid = self._agent.alloc_object_id(1)
+ self._parent.set_object_id(self._parent_oid)
+
+ while True: # there may be a better way, but
+ time.sleep(1000) # I'm a python noob...
+
+
+
+app = App()
+app.main()
+
diff --git a/qpid/cpp/bindings/qmf/tests/python_console.py b/qpid/cpp/bindings/qmf/tests/python_console.py
index 7a8a2cb9fe..bcd3063fe3 100755
--- a/qpid/cpp/bindings/qmf/tests/python_console.py
+++ b/qpid/cpp/bindings/qmf/tests/python_console.py
@@ -36,16 +36,109 @@ class QmfInteropTests(TestBase010):
agents = qmf.getObjects(_class="agent")
sleep(1)
count += 1
- if count > 5:
+ if count > 10:
self.fail("Timed out waiting for remote agent")
- def test_B_basic_types(self):
+ def test_B_basic_method_invocation(self):
self.startQmf();
qmf = self.qmf
parents = qmf.getObjects(_class="parent")
self.assertEqual(len(parents), 1)
- self.assertEqual(parents[0].uint32val, 0xA5A5A5A5)
+ parent = parents[0]
+ for seq in range(10):
+ result = parent.echo(seq)
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.text, "OK")
+ self.assertEqual(result.sequence, seq)
+
+ result = parent.set_numerics("bogus")
+ self.assertEqual(result.status, 1)
+ self.assertEqual(result.text, "Invalid argument value for test")
+
+ def test_C_basic_types_numeric_big(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ result = parent.set_numerics("big")
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.text, "OK")
+
+ parent.update()
+
+ self.assertEqual(parent.uint64val, 0x9494949449494949)
+ self.assertEqual(parent.uint32val, 0xA5A55A5A)
+ self.assertEqual(parent.uint16val, 0xB66B)
+ self.assertEqual(parent.uint8val, 0xC7)
+
+ self.assertEqual(parent.int64val, 1000000000000000000)
+ self.assertEqual(parent.int32val, 1000000000)
+ self.assertEqual(parent.int16val, 10000)
+ self.assertEqual(parent.int8val, 100)
+
+ def test_C_basic_types_numeric_small(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ result = parent.set_numerics("small")
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.text, "OK")
+
+ parent.update()
+
+ self.assertEqual(parent.uint64val, 4)
+ self.assertEqual(parent.uint32val, 5)
+ self.assertEqual(parent.uint16val, 6)
+ self.assertEqual(parent.uint8val, 7)
+
+ self.assertEqual(parent.int64val, 8)
+ self.assertEqual(parent.int32val, 9)
+ self.assertEqual(parent.int16val, 10)
+ self.assertEqual(parent.int8val, 11)
+
+ def test_C_basic_types_numeric_negative(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ result = parent.set_numerics("negative")
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.text, "OK")
+
+ parent.update()
+
+ self.assertEqual(parent.uint64val, 0)
+ self.assertEqual(parent.uint32val, 0)
+ self.assertEqual(parent.uint16val, 0)
+ self.assertEqual(parent.uint8val, 0)
+
+ self.assertEqual(parent.int64val, -10000000000)
+ self.assertEqual(parent.int32val, -100000)
+ self.assertEqual(parent.int16val, -1000)
+ self.assertEqual(parent.int8val, -100)
+
+ def test_D_userid_for_method(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ parents = qmf.getObjects(_class="parent")
+ self.assertEqual(len(parents), 1)
+ parent = parents[0]
+
+ result = parent.probe_userid()
+ self.assertEqual(result.status, 0)
+ self.assertEqual(result.userid, "guest")
def getProperty(self, msg, name):
for h in msg.headers:
diff --git a/qpid/cpp/bindings/qmf/tests/ruby_console.rb b/qpid/cpp/bindings/qmf/tests/ruby_console.rb
new file mode 100755
index 0000000000..fb48c29566
--- /dev/null
+++ b/qpid/cpp/bindings/qmf/tests/ruby_console.rb
@@ -0,0 +1,61 @@
+#!/usr/bin/ruby
+
+#
+# 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.
+#
+
+require 'qmf'
+require 'socket'
+
+class App < Qmf::ConsoleHandler
+
+ def main
+ @settings = Qmf::ConnectionSettings.new
+ @settings.set_attr("host", ARGV[0]) if ARGV.size > 0
+ @settings.set_attr("port", ARGV[1].to_i) if ARGV.size > 1
+ @connection = Qmf::Connection.new(@settings)
+ @qmf = Qmf::Console.new
+
+ @broker = @qmf.add_connection(@connection)
+ @broker.waitForStable
+
+ packages = @qmf.get_packages
+ puts "----- Packages -----"
+ packages.each do |p|
+ puts p
+ puts " ----- Object Classes -----"
+ classes = @qmf.get_classes(p)
+ classes.each do |c|
+ puts " #{c.name}"
+ end
+ puts " ----- Event Classes -----"
+ classes = @qmf.get_classes(p, Qmf::CLASS_EVENT)
+ classes.each do |c|
+ puts " #{c.name}"
+ end
+ end
+ puts "-----"
+
+ sleep
+ end
+end
+
+app = App.new
+app.main
+
+
diff --git a/qpid/cpp/bindings/qmf/tests/run_interop_tests b/qpid/cpp/bindings/qmf/tests/run_interop_tests
index e6fc872dbb..01d7221ac6 100755
--- a/qpid/cpp/bindings/qmf/tests/run_interop_tests
+++ b/qpid/cpp/bindings/qmf/tests/run_interop_tests
@@ -28,6 +28,9 @@ BROKER_DIR=${BUILD_DIR}/src
API_DIR=${BUILD_DIR}/bindings/qmf
SPEC_DIR=${QPID_DIR}/specs
+RUBY_LIB_DIR=${API_DIR}/ruby/.libs
+PYTHON_LIB_DIR=${API_DIR}/python/.libs
+
trap stop_broker INT TERM QUIT
start_broker() {
@@ -41,7 +44,7 @@ stop_broker() {
}
start_ruby_agent() {
- ruby -I${MY_DIR}/../ruby -I${API_DIR}/ruby/.libs ${MY_DIR}/agent_ruby.rb localhost $BROKER_PORT &
+ ruby -I${MY_DIR}/../ruby -I${RUBY_LIB_DIR} ${MY_DIR}/agent_ruby.rb localhost $BROKER_PORT &
AGENT_PID=$!
}
@@ -49,19 +52,62 @@ stop_ruby_agent() {
kill $AGENT_PID
}
+start_python_agent() {
+ PYTHONPATH="${MY_DIR}/../python:${API_DIR}/python:${PYTHON_LIB_DIR}" python ${MY_DIR}/python_agent.py localhost $BROKER_PORT &
+ PY_AGENT_PID=$!
+}
+
+stop_python_agent() {
+ kill $PY_AGENT_PID
+}
+
+TESTS_FAILED=0
+
if test -d ${PYTHON_DIR} ; then
start_broker
echo "Running qmf interop tests using broker on port $BROKER_PORT"
PYTHONPATH=${PYTHON_DIR}:${MY_DIR}
export PYTHONPATH
- echo " Ruby Agent vs. Pure-Python Console"
- start_ruby_agent
- echo " Ruby agent started at pid $AGENT_PID"
- ${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@
- RETCODE=$?
- stop_ruby_agent
+
+ if test -d ${PYTHON_LIB_DIR} ; then
+ echo " Python Agent (external storage) vs. Pure-Python Console"
+ start_python_agent
+ echo " Python agent started at pid $PY_AGENT_PID"
+ ${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@
+ RETCODE=$?
+ stop_python_agent
+ if test x$RETCODE != x0; then
+ echo "FAIL qmf interop tests (Python Agent)";
+ TESTS_FAILED=1
+ fi
+ fi
+
+ if test -d ${RUBY_LIB_DIR} ; then
+ echo " Ruby Agent (external storage) vs. Pure-Python Console"
+ start_ruby_agent
+ echo " Ruby agent started at pid $AGENT_PID"
+ ${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@
+ RETCODE=$?
+ stop_ruby_agent
+ if test x$RETCODE != x0; then
+ echo "FAIL qmf interop tests (Ruby Agent)";
+ TESTS_FAILED=1
+ fi
+ fi
+
+ # Also against the Pure-Python console:
+ # Ruby agent (internal storage)
+ # Python agent (external and internal)
+ # C++ agent (external and internal)
+ #
+ # Other consoles against the same set of agents:
+ # Wrapped Python console
+ # Ruby console
+ # C++ console
+
stop_broker
- if test x$RETCODE != x0; then
- echo "FAIL qmf interop tests"; exit 1;
+ if test x$TESTS_FAILED != x0; then
+ echo "TEST FAILED!"
+ exit 1
fi
fi
diff --git a/qpid/cpp/configure.ac b/qpid/cpp/configure.ac
index adf3da06b8..7eb1e99159 100644
--- a/qpid/cpp/configure.ac
+++ b/qpid/cpp/configure.ac
@@ -512,8 +512,10 @@ AC_CONFIG_FILES([
examples/xml-exchange/Makefile
examples/qmf-console/Makefile
examples/tradedemo/Makefile
+ examples/messaging/Makefile
bindings/qmf/Makefile
bindings/qmf/ruby/Makefile
+ bindings/qmf/python/Makefile
bindings/qmf/tests/Makefile
managementgen/Makefile
etc/Makefile
diff --git a/qpid/cpp/docs/api/doxygen_mainpage.h b/qpid/cpp/docs/api/doxygen_mainpage.h
index cb59cfa260..83efaba31d 100644
--- a/qpid/cpp/docs/api/doxygen_mainpage.h
+++ b/qpid/cpp/docs/api/doxygen_mainpage.h
@@ -26,6 +26,7 @@
* <h2>Messaging Client API classes</h2>
* <ul>
* <li><p>\ref clientapi</p></li>
+ * <li><p>\ref qmfapi</p></li>
* </ul>
*
* <h2>Code for common tasks</h2>
@@ -127,5 +128,6 @@
/**
* \defgroup clientapi Qpid C++ Client API
+ * \defgroup qmfapi Qpid Management Framework C++ API
*
*/
diff --git a/qpid/cpp/docs/api/user.doxygen.in b/qpid/cpp/docs/api/user.doxygen.in
index 6ade9ab846..f6f8c161b7 100644
--- a/qpid/cpp/docs/api/user.doxygen.in
+++ b/qpid/cpp/docs/api/user.doxygen.in
@@ -456,7 +456,7 @@ WARN_LOGFILE = doxygen.log
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = @top_srcdir@/include @top_builddir@/include
+INPUT = @top_srcdir@/docs/api @top_srcdir@/include @top_builddir@/include
# If the value of the INPUT tag contains directories, you can use the
@@ -471,7 +471,7 @@ FILE_PATTERNS = *.h
# should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used.
-RECURSIVE = NO
+RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a
diff --git a/qpid/cpp/examples/CMakeLists.txt b/qpid/cpp/examples/CMakeLists.txt
index 7d0a4d0d21..126adab32e 100644
--- a/qpid/cpp/examples/CMakeLists.txt
+++ b/qpid/cpp/examples/CMakeLists.txt
@@ -62,3 +62,4 @@ add_subdirectory(qmf-console)
add_subdirectory(request-response)
add_subdirectory(tradedemo)
add_subdirectory(xml-exchange)
+add_subdirectory(messaging)
diff --git a/qpid/cpp/examples/Makefile.am b/qpid/cpp/examples/Makefile.am
index 9c355b84e4..b526424e2a 100644
--- a/qpid/cpp/examples/Makefile.am
+++ b/qpid/cpp/examples/Makefile.am
@@ -16,7 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
-SUBDIRS = direct fanout pub-sub request-response failover qmf-console tradedemo
+SUBDIRS = direct fanout pub-sub request-response failover qmf-console tradedemo messaging
if HAVE_XML
SUBDIRS += xml-exchange
broker_args = "--no-module-dir --data-dir \"\" --auth no --load-module $(top_builddir)/src/.libs/xml.so"
diff --git a/qpid/cpp/examples/messaging/CMakeLists.txt b/qpid/cpp/examples/messaging/CMakeLists.txt
new file mode 100644
index 0000000000..e7885d0b50
--- /dev/null
+++ b/qpid/cpp/examples/messaging/CMakeLists.txt
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+add_example(messaging queue_listener)
+add_example(messaging queue_receiver)
+add_example(messaging queue_sender)
+
+add_example(messaging topic_listener)
+add_example(messaging topic_receiver)
+add_example(messaging topic_sender)
+
+add_example(messaging map_receiver)
+add_example(messaging map_sender)
+
+add_example(messaging client)
+add_example(messaging server)
diff --git a/qpid/cpp/examples/messaging/Makefile.am b/qpid/cpp/examples/messaging/Makefile.am
new file mode 100644
index 0000000000..250e549e82
--- /dev/null
+++ b/qpid/cpp/examples/messaging/Makefile.am
@@ -0,0 +1,54 @@
+#
+# 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.
+#
+examplesdir=$(pkgdatadir)/examples/messaging
+
+MAKELDFLAGS=$(CLIENTFLAGS)
+include $(top_srcdir)/examples/makedist.mk
+
+noinst_PROGRAMS=queue_sender queue_listener queue_receiver topic_sender topic_listener topic_receiver client server map_sender map_receiver
+
+queue_sender_SOURCES=queue_sender.cpp
+queue_sender_LDADD=$(CLIENT_LIB)
+
+queue_listener_SOURCES=queue_listener.cpp
+queue_listener_LDADD=$(CLIENT_LIB)
+
+queue_receiver_SOURCES=queue_receiver.cpp
+queue_receiver_LDADD=$(CLIENT_LIB)
+
+topic_sender_SOURCES=topic_sender.cpp
+topic_sender_LDADD=$(CLIENT_LIB)
+
+topic_listener_SOURCES=topic_listener.cpp
+topic_listener_LDADD=$(CLIENT_LIB)
+
+topic_receiver_SOURCES=topic_receiver.cpp
+topic_receiver_LDADD=$(CLIENT_LIB)
+
+client_SOURCES=client.cpp
+client_LDADD=$(CLIENT_LIB)
+
+server_SOURCES=server.cpp
+server_LDADD=$(CLIENT_LIB)
+
+map_sender_SOURCES=map_sender.cpp
+map_sender_LDADD=$(CLIENT_LIB)
+
+map_receiver_SOURCES=map_receiver.cpp
+map_receiver_LDADD=$(CLIENT_LIB)
diff --git a/qpid/cpp/examples/messaging/client.cpp b/qpid/cpp/examples/messaging/client.cpp
new file mode 100644
index 0000000000..45c065880b
--- /dev/null
+++ b/qpid/cpp/examples/messaging/client.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 <qpid/messaging/Address.h>
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+
+ Sender sender = session.createSender("service_queue");
+
+ //create temp queue & receiver...
+ Address responseQueue = session.createTempQueue();
+ Receiver receiver = session.createReceiver(responseQueue);
+
+ // Now send some messages ...
+ string s[] = {
+ "Twas brillig, and the slithy toves",
+ "Did gire and gymble in the wabe.",
+ "All mimsy were the borogroves,",
+ "And the mome raths outgrabe."
+ };
+
+ Message request;
+ request.setReplyTo(responseQueue);
+ for (int i=0; i<4; i++) {
+ request.setContent(s[i]);
+ sender.send(request);
+ Message response = receiver.fetch();
+ std::cout << request.getContent().asString() << " -> " << response.getContent().asString() << std::endl;
+ }
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/messaging/map_receiver.cpp b/qpid/cpp/examples/messaging/map_receiver.cpp
new file mode 100644
index 0000000000..e6557b1560
--- /dev/null
+++ b/qpid/cpp/examples/messaging/map_receiver.cpp
@@ -0,0 +1,54 @@
+/*
+ *
+ * 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 <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Receiver receiver = session.createReceiver("message_queue");
+ Message message = receiver.fetch();
+ std::cout << message.getContent().asMap() << std::endl;
+ session.acknowledge();
+ receiver.cancel();
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/qpid/cpp/examples/messaging/map_sender.cpp b/qpid/cpp/examples/messaging/map_sender.cpp
new file mode 100644
index 0000000000..9301c1fe1f
--- /dev/null
+++ b/qpid/cpp/examples/messaging/map_sender.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Sender sender = session.createSender("message_queue");
+
+ Message message;
+ message.getContent()["id"] = 987654321;
+ message.getContent()["name"] = "Widget";
+ message.getContent()["price"] = 0.99;//bad use of floating point number, just an example!
+ Variant::List colours;
+ colours.push_back(Variant("red"));
+ colours.push_back(Variant("green"));
+ colours.push_back(Variant("white"));
+ message.getContent()["colours"] = colours;
+
+ sender.send(message);
+ session.sync();
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/messaging/queue_listener.cpp b/qpid/cpp/examples/messaging/queue_listener.cpp
new file mode 100644
index 0000000000..099e8e145a
--- /dev/null
+++ b/qpid/cpp/examples/messaging/queue_listener.cpp
@@ -0,0 +1,82 @@
+/*
+ *
+ * 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 <qpid/messaging/Connection.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/MessageListener.h>
+#include <qpid/messaging/Receiver.h>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::messaging;
+
+class Listener : public MessageListener
+{
+ public:
+ Listener(const Receiver& receiver);
+ void received(Message& message);
+ bool isFinished();
+ private:
+ Receiver receiver;
+ bool finished;
+};
+
+Listener::Listener(const Receiver& r) : receiver(r), finished(false) {}
+
+bool Listener::isFinished() { return finished; }
+
+void Listener::received(Message& message)
+{
+ std::cout << "Message: " << message.getContent().asString() << std::endl;
+ if (message.getContent().asString() == "That's all, folks!") {
+ std::cout << "Shutting down listener" << std::endl;
+ receiver.cancel();
+ finished = true;
+ }
+}
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+
+ Receiver receiver = session.createReceiver("message_queue");
+ Listener listener(receiver);
+ receiver.setListener(&listener);
+ receiver.setCapacity(1);
+ receiver.start();
+ while (session.dispatch()) {
+ session.acknowledge();
+ if (listener.isFinished()) break;
+ }
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/messaging/queue_receiver.cpp b/qpid/cpp/examples/messaging/queue_receiver.cpp
new file mode 100644
index 0000000000..83a44b2ca9
--- /dev/null
+++ b/qpid/cpp/examples/messaging/queue_receiver.cpp
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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 <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Variant::Map options;
+ if (argc>2) parseOptionString(argv[2], options);
+ Connection connection = Connection::open(url, options);
+ Session session = connection.newSession();
+ Receiver receiver = session.createReceiver("message_queue");
+ while (true) {
+ Message message = receiver.fetch();
+ std::cout << "Message: " << message.getContent() << std::endl;
+ session.acknowledge();
+ if (message.getContent().asString() == "That's all, folks!") {
+ std::cout << "Cancelling receiver" << std::endl;
+ receiver.cancel();
+ break;
+ }
+ }
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/messaging/queue_sender.cpp b/qpid/cpp/examples/messaging/queue_sender.cpp
new file mode 100644
index 0000000000..637e7eb8e4
--- /dev/null
+++ b/qpid/cpp/examples/messaging/queue_sender.cpp
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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 <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ int count = argc>2 ? atoi(argv[2]) : 10;
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Sender sender = session.createSender("message_queue");
+
+ // Now send some messages ...
+ for (int i=0; i<count; i++) {
+ Message message;
+ message.getContent() << "Message " << i;
+ sender.send(message);
+ }
+
+ // And send a final message to indicate termination.
+ Message message("That's all, folks!");
+ sender.send(message);
+ session.sync();
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/messaging/server.cpp b/qpid/cpp/examples/messaging/server.cpp
new file mode 100644
index 0000000000..38f4601ff6
--- /dev/null
+++ b/qpid/cpp/examples/messaging/server.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 <qpid/messaging/Address.h>
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/messaging/Variant.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Receiver receiver = session.createReceiver("service_queue");
+
+ while (true) {
+ Message request = receiver.fetch();
+ const Address& address = request.getReplyTo();
+ if (address) {
+ Sender sender = session.createSender(address);
+ std::string s = request.getContent().asString();
+ std::transform(s.begin(), s.end(), s.begin(), toupper);
+ Message response(s);
+ sender.send(response);
+ std::cout << "Processed request: "
+ << request.getContent().asString()
+ << " -> "
+ << response.getContent().asString() << std::endl;
+ session.acknowledge();
+ } else {
+ std::cerr << "Error: no reply address specified for request: " << request.getContent().asString() << std::endl;
+ session.reject(request);
+ }
+ }
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/messaging/topic_listener.cpp b/qpid/cpp/examples/messaging/topic_listener.cpp
new file mode 100644
index 0000000000..700e03cdf9
--- /dev/null
+++ b/qpid/cpp/examples/messaging/topic_listener.cpp
@@ -0,0 +1,82 @@
+/*
+ *
+ * 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 <qpid/messaging/Connection.h>
+#include <qpid/messaging/Filter.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/MessageListener.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/messaging/Receiver.h>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::messaging;
+
+class Listener : public MessageListener
+{
+ public:
+ Listener(const Receiver& receiver);
+ void received(Message& message);
+ bool isFinished();
+ private:
+ Receiver receiver;
+ bool finished;
+};
+
+Listener::Listener(const Receiver& r) : receiver(r), finished(false) {}
+
+bool Listener::isFinished() { return finished; }
+
+void Listener::received(Message& message)
+{
+ std::cout << "Message: " << message.getContent().asString() << std::endl;
+ if (message.getContent().asString() == "That's all, folks!") {
+ std::cout << "Shutting down listener" << std::endl;
+ receiver.cancel();
+ finished = true;
+ }
+}
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ const char* pattern = argc>2 ? argv[2] : "#.#";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+
+ Filter filter(Filter::WILDCARD, pattern, "control");
+ Receiver receiver = session.createReceiver("news_service", filter);
+ Listener listener(receiver);
+ receiver.setListener(&listener);
+ receiver.setCapacity(1);
+ receiver.start();
+ while (session.dispatch() && !listener.isFinished()) ;
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/messaging/topic_receiver.cpp b/qpid/cpp/examples/messaging/topic_receiver.cpp
new file mode 100644
index 0000000000..063f0d9cb0
--- /dev/null
+++ b/qpid/cpp/examples/messaging/topic_receiver.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <qpid/messaging/Address.h>
+#include <qpid/messaging/Connection.h>
+#include <qpid/messaging/Filter.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ const char* pattern = argc>2 ? argv[2] : "#.#";
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Filter filter(Filter::WILDCARD, pattern, "control");
+ Receiver receiver = session.createReceiver(Address("news_service", "topic"), filter);
+ while (true) {
+ Message message = receiver.fetch();
+ std::cout << "Message: " << message.getContent().asString() << std::endl;
+ if (message.getContent().asString() == "That's all, folks!") {
+ std::cout << "Cancelling receiver" << std::endl;
+ receiver.cancel();
+ break;
+ }
+ }
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/examples/messaging/topic_sender.cpp b/qpid/cpp/examples/messaging/topic_sender.cpp
new file mode 100644
index 0000000000..5665fc45f9
--- /dev/null
+++ b/qpid/cpp/examples/messaging/topic_sender.cpp
@@ -0,0 +1,78 @@
+/*
+ *
+ * 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 <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <sstream>
+
+using namespace qpid::messaging;
+
+using std::stringstream;
+using std::string;
+
+void sendMessages(Sender& sender, int count, const std::string& subject, const std::string& text)
+{
+ Message message;
+ message.setSubject(subject);
+ for (int i=0; i<count; i++) {
+ stringstream message_data;
+ message_data << text << i;
+
+ message.setContent(message_data.str());
+ sender.send(message);
+ }
+}
+
+int main(int argc, char** argv) {
+ const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672";
+ int count = argc>2 ? atoi(argv[2]) : 10;
+
+ try {
+ Connection connection = Connection::open(url);
+ Session session = connection.newSession();
+ Sender sender = session.createSender("news_service");
+
+ // Now send some messages to each topic...
+ sendMessages(sender, count, "usa.news", "news about the usa");
+ sendMessages(sender, count, "usa.weather", "weather report for the usa");
+ sendMessages(sender, count, "europe.news", "news about europe");
+ sendMessages(sender, count, "europe.weather", "weather report for europe");
+
+ // And send a final message to indicate termination.
+ Message message("That's all, folks!");
+ message.setSubject("control");
+ sender.send(message);
+ session.sync();
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/include/qmf/Agent.h b/qpid/cpp/include/qmf/Agent.h
new file mode 100644
index 0000000000..e61cd737d0
--- /dev/null
+++ b/qpid/cpp/include/qmf/Agent.h
@@ -0,0 +1,287 @@
+#ifndef _QmfAgent_
+#define _QmfAgent_
+
+/*
+ * 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 "qmf/QmfImportExport.h"
+
+namespace qmf {
+
+ class AgentImpl;
+ class Connection;
+ class ObjectId;
+ class AgentObject;
+ class Value;
+ class Event;
+ class SchemaObjectClass;
+
+ /**
+ * AgentListener is used by agents that select the internalStore=false option (see Agent
+ * constructor) or by agents that wish to provide access control for queries and methods.
+ *
+ * \ingroup qmfapi
+ */
+ class AgentListener {
+ QMF_EXTERN virtual ~AgentListener();
+
+ /**
+ * allowQuery is called before a query operation is executed. If true is returned
+ * by this function, the query will proceed. If false is returned, the query will
+ * be forbidden.
+ *
+ * @param q The query being requested.
+ * @param userId The authenticated identity of the user requesting the query.
+ */
+ virtual bool allowQuery(const Query& q, const char* userId);
+
+ /**
+ * allowMethod is called before a method call is executed. If true is returned
+ * by this function, the method call will proceed. If false is returned, the method
+ * call will be forbidden.
+ *
+ * @param name The name of the method being called.
+ * @param args A value object (of type "map") that contains both input and output arguments.
+ * @param oid The objectId that identifies the instance of the object being called.
+ * @param cls The Schema describing the object being called.
+ * @param userId The authenticated identity of the requesting user.
+ */
+ virtual bool allowMethod(const char* name, const Value& args, const ObjectId& oid,
+ const SchemaObjectClass& cls, const char* userId);
+
+ /**
+ * query is called when the agent receives a query request. The handler must invoke
+ * Agent::queryResponse zero or more times (using the supplied context) followed by
+ * a single invocation of Agent::queryComplete. These calls do not need to be made
+ * synchronously in the context of this function. They may occur before or after this
+ * function returns.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context A context value to use in resulting calls to queryResponse and quertComplete.
+ * @param q The query requested by the console.
+ * @param userId the authenticated identity of the user requesting the query.
+ */
+ virtual void query(uint32_t context, const Query& q, const char* userId);
+
+ /**
+ * syncStart is called when a console requests a standing query. This function must
+ * behave exactly like AgentListener::query (i.e. send zero or more responses followed
+ * by a queryComplete) except it then remembers the context and the query and makes
+ * subsequent queryResponse calls whenever appropriate according the the query.
+ *
+ * The standing query shall stay in effect until syncStop is called with the same context
+ * value or until a specified period of time elapses without receiving a syncTouch for the
+ * context.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context A context value to use in resulting calls to queryResponse and queryComplete.
+ * @param q The query requested by the console.
+ * @param userId the authenticated identity of the user requesting the query.
+ */
+ virtual void syncStart(uint32_t context, const Query& q, const char* userId);
+
+ /**
+ * syncTouch is called when the console that requested a standing query refreshes its
+ * interest in the query. The console must periodically "touch" a standing query to keep
+ * it alive. This prevents standing queries from accumulating when the console disconnects
+ * before it can stop the query.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context The context supplied in a previous call to syncStart.
+ * @param userId The authenticated identity of the requesting user.
+ */
+ virtual void syncTouch(uint32_t context, const char* userId);
+
+ /**
+ * syncStop is called when the console that requested a standing query no longer wishes to
+ * receive data associated with that query. The application shall stop processing this
+ * query and shall remove its record of the context value.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context The context supplied in a previous call to syncStart.
+ * @param userId The authenticated identity of the requesting user.
+ */
+ virtual void syncStop(uint32_t context, const char* userId);
+
+ /**
+ * methodCall is called when a console invokes a method on a QMF object. The application
+ * must call Agent::methodResponse once in response to this function. The response does
+ * not need to be called synchronously in the context of this function. It may be called
+ * before or after this function returns.
+ *
+ * This function will only be invoked if internalStore=false in the Agent's constructor.
+ *
+ * @param context A context value to use in resulting call to methodResponse.
+ * @param name The name of the method being called.
+ * @param args A value object (of type "map") that contains both input and output arguments.
+ * @param oid The objectId that identifies the instance of the object being called.
+ * @param cls The Schema describing the object being called.
+ * @param userId The authenticated identity of the requesting user.
+ */
+ virtual void methodCall(uint32_t context, const char* name, Value& args,
+ const ObjectId& oid, const SchemaObjectClass& cls, const char* userId);
+ };
+
+ /**
+ * The Agent class is the QMF Agent portal. It should be instantiated once and associated with a
+ * Connection (setConnection) to connect an agent to the QMF infrastructure.
+ *
+ * \ingroup qmfapi
+ */
+ class Agent {
+ public:
+ /**
+ * Create an instance of the Agent class.
+ *
+ * @param label An optional string label that can be used to identify the agent.
+ *
+ * @param internalStore If true, objects shall be tracked internally by the agent.
+ * If false, the user of the agent must track the objects.
+ * If the agent is tracking the objects, queries and syncs are handled by
+ * the agent. The only involvement the user has is to optionally authorize
+ * individual operations. If the user is tracking the objects, the user code
+ * must implement queries and syncs (standing queries).
+ *
+ * @param listener A pointer to a class that implements the AgentListener interface.
+ * This must be supplied if any of the following conditions are true:
+ * - The agent model contains methods
+ * - The user wishes to individually authorize query and sync operations.
+ * - internalStore = false
+ */
+ QMF_EXTERN Agent(char* label="qmfa", bool internalStore=true, AgentListener* listener=0);
+
+ /**
+ * Destroy an instance of the Agent class.
+ */
+ QMF_EXTERN ~Agent();
+
+ /**
+ * Set the persistent store file. This file, if specified, is used to store state information
+ * about the Agent. For example, if object-ids must be persistent across restarts of the Agent
+ * program, this file path must be supplied.
+ *
+ * @param path Full path to a file that is both writable and readable by the Agent program.
+ */
+ QMF_EXTERN void setStoreDir(const char* path);
+
+ /**
+ * Provide a connection (to a Qpid broker) over which the agent can communicate.
+ *
+ * @param conn Pointer to a Connection object.
+ */
+ QMF_EXTERN void setConnection(Connection* conn);
+
+ /**
+ * Register a class schema (object or event) with the agent. The agent must have a registered
+ * schema for an object class or an event class before it can handle objects or events of that
+ * class.
+ *
+ * @param cls Pointer to the schema structure describing the class.
+ */
+ QMF_EXTERN void registerClass(SchemaObjectClass* cls);
+ QMF_EXTERN void registerClass(SchemaEventClass* cls);
+
+ /**
+ * Add an object to the agent (for internal storage mode only).
+ *
+ * @param obj Reference to the object to be managed by the agent.
+ *
+ * @param persistent Iff true, the object ID assigned to the object shall indicate persistence
+ * (i.e. the object ID shall be the same across restarts of the agent program).
+ *
+ * @param oid 64-bit value for the oid (if zero, the agent will assign the value).
+ *
+ * @param oidLo 32-bit value for the lower 32-bits of the oid.
+ *
+ * @param oidHi 32-bit value for the upper 32-bits of the oid.
+ */
+ QMF_EXTERN const ObjectId* addObject(AgentObject& obj, bool persistent=false, uint64_t oid=0);
+ QMF_EXTERN const ObjectId* addObject(AgentObject& obj, bool persistent, uint32_t oidLo, uint32_t oidHi);
+
+ /**
+ * Allocate an object ID for an object (for external storage mode only).
+ *
+ * @param persistent Iff true, the object ID allocated shall indicate persistence
+ * (i.e. the object ID shall be the same across restarts of the agent program).
+ *
+ * @param oid 64-bit value for the oid (if zero, the agent will assign the value).
+ *
+ * @param oidLo 32-bit value for the lower 32-bits of the oid.
+ *
+ * @param oidHi 32-bit value for the upper 32-bits of the oid.
+ */
+ QMF_EXTERN const ObjectId* allocObjectId(bool persistent=false, uint64_t oid=0);
+ QMF_EXTERN const ObjectId* allocObjectId(bool persistent, uint32_t oidLo, uint32_t oidHi);
+
+ /**
+ * Raise a QMF event.
+ *
+ * @param event Reference to an event object to be raised to the QMF infrastructure.
+ */
+ QMF_EXTERN void raiseEvent(Event& event);
+
+ /**
+ * Provide a response to a query (for external storage mode only).
+ *
+ * @param context The context value supplied in the query (via the AgentListener interface).
+ *
+ * @param object A reference to the agent that matched the query criteria.
+ *
+ * @param prop If true, transmit the property attributes of this object.
+ *
+ * @param stat If true, transmit the statistic attributes of this object.
+ */
+ QMF_EXTERN void queryResponse(uint32_t context, AgentObject& object, bool prop = true, bool stat = true);
+
+ /**
+ * Indicate that a query (or the initial dump of a sync) is complete (for external storage mode only).
+ *
+ * @param context The context value supplied in the query/sync (via the AgentListener interface).
+ */
+ QMF_EXTERN void queryComplete(uint32_t context);
+
+ /**
+ * Provide the response to a method call.
+ *
+ * @param context The context value supplied in the method request (via the AgentListener interface).
+ *
+ * @param args The argument list from the method call. Must include the output arguments (may include
+ * the input arguments).
+ *
+ * @param status Numerical return status: zero indicates no error, non-zero indicates error.
+ *
+ * @param exception Pointer to an exception value. If status is non-zero, the exception value is
+ * sent to the caller. It is optional (i.e. leave the pointer as 0), or may be
+ * set to any legal value. A string may be supplied, but an unmanaged object of
+ * any schema may also be passed.
+ */
+ QMF_EXTERN void methodResponse(uint32_t context, const Value& args, uint32_t status=0,
+ const Value* exception=0);
+
+ private:
+ AgentImpl* impl;
+ };
+
+}
+
+#endif
diff --git a/qpid/cpp/include/qmf/AgentObject.h b/qpid/cpp/include/qmf/AgentObject.h
new file mode 100644
index 0000000000..a1878605eb
--- /dev/null
+++ b/qpid/cpp/include/qmf/AgentObject.h
@@ -0,0 +1,95 @@
+#ifndef _QmfAgentObject_
+#define _QmfAgentObject_
+
+/*
+ * 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 "qmf/QmfImportExport.h"
+
+namespace qmf {
+
+ class AgentObjectImpl;
+ class SchemaObjectClass;
+ class ObjectId;
+ class Value;
+ class Agent;
+
+ /**
+ * AgentObject is an extension of Object with agent-specific methods added.
+ *
+ * \ingroup qmfapi
+ */
+ class AgentObject : public Object {
+ public:
+ /**
+ * Create a new Object of a specific type.
+ *
+ * @param type Pointer to the schema class to use as a type for this object.
+ */
+ QMF_EXTERN AgentObject(const SchemaObjectClass* type);
+
+ /**
+ * Schedule this object for deletion. Agent objects should never be directly
+ * destroyed, rather this method should be called and all pointers to this
+ * object dropped. The agent will clean up and properly delete the object at
+ * the appropraite time.
+ */
+ QMF_EXTERN void destroy();
+
+ /**
+ * Set the object ID for this object if it is to be managed by the agent.
+ *
+ * @param oid The new object ID for the managed object.
+ */
+ QMF_EXTERN void setObjectId(ObjectId& oid);
+
+ /**
+ * Handler for invoked method calls. This will only be called for objects that
+ * are being managed and stored by an agent (see internalStore argument in Agent::Agent).
+ * If this function is not overridden in a child class, the default implementation will
+ * cause AgentListener::methodCall to be invoked in the application program.
+ *
+ * If this function is overridden in a sub-class, the implementation must perform
+ * the actions associated with the method call (i.e. implement the method). Once the
+ * method execution is complete, it must call Agent::methodResponse with the result
+ * of the method execution. Agent::methodResponse does not need to be called
+ * synchronously in the context of this function call. It may be called at a later
+ * time from a different thread.
+ *
+ * @param context Context supplied by the agent and required to be passed in the
+ * call to Agent::methodResponse
+ *
+ * @param name The name of the method.
+ *
+ * @param args A Value (of type map) that contains the input and output arguments.
+ *
+ * @param userId The authenticated identity of the user who invoked the method.
+ */
+ QMF_EXTERN virtual void methodInvoked(uint32_t context, const char* name, Value& args,
+ const char* userId);
+ private:
+ friend class Agent;
+ virtual ~AgentObject();
+ void setAgent(Agent* agent);
+ AgentObjectImpl* impl;
+ };
+
+}
+
+#endif
diff --git a/qpid/cpp/include/qmf/Connection.h b/qpid/cpp/include/qmf/Connection.h
new file mode 100644
index 0000000000..f648b1427f
--- /dev/null
+++ b/qpid/cpp/include/qmf/Connection.h
@@ -0,0 +1,125 @@
+#ifndef _QmfConnection_
+#define _QmfConnection_
+
+/*
+ * 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 "qmf/QmfImportExport.h"
+#include "qmf/ConnectionSettings.h"
+
+namespace qmf {
+
+ /**
+ * Operational states for Connections.
+ *
+ * \ingroup qmfapi
+ */
+ enum ConnectionState {
+ CONNECTION_UP = 1,
+ CONNECTION_DOWN = 2
+ };
+
+ /**
+ * Implement a subclass of ConnectionListener and provide it with the
+ * Connection constructor to receive notification of changes in the
+ * connection state.
+ *
+ * \ingroup qmfapi
+ */
+ class ConnectionListener {
+ QMF_EXTERN virtual ~ConnectionListener();
+
+ /**
+ * Called each time the state of the connection changes.
+ *
+ * @param state the new state
+ */
+ virtual void newState(ConnectionState state);
+
+ /**
+ * Called if the connection requires input from an interactive client.
+ *
+ * @param prompt Text of the prompt - describes what information is required.
+ * @param answer The interactive user input.
+ * @param answerLen on Input - the maximum number of bytes that can be copied to answer.
+ * on Output - the number of bytes copied to answer.
+ */
+ virtual void interactivePrompt(const char* prompt, char* answer, uint32_t answerLen);
+ };
+
+ class ConnectionImpl;
+
+ /**
+ * The Connection class represents a connection to a QPID broker that can
+ * be used by agents and consoles, possibly multiple at the same time.
+ *
+ * \ingroup qmfapi
+ */
+ class Connection {
+ public:
+
+ /**
+ * Creates a connection object and begins the process of attempting to
+ * connect to the QPID broker.
+ *
+ * @param settings The settings that control how the connection is set
+ * up.
+ *
+ * @param listener An optional pointer to a subclass of
+ * ConnectionListener to receive notifications of events related to
+ * this connection.
+ */
+ QMF_EXTERN Connection(const ConnectionSettings& settings,
+ const ConnectionListener* listener = 0);
+
+ /**
+ * Destroys a connection, causing the connection to be closed.
+ */
+ QMF_EXTERN ~Connection();
+
+ /**
+ * Set the administrative state of the connection (enabled or disabled).
+ *
+ * @param enabled True => enable connection, False => disable connection
+ */
+ QMF_EXTERN void setAdminState(bool enabled);
+
+ /**
+ * Return the current operational state of the connection (up or down).
+ *
+ * @return the current connection state.
+ */
+ QMF_EXTERN ConnectionState getOperState() const;
+
+ /**
+ * Get the error message from the last failure to connect.
+ *
+ * @return Null-terminated string containing the error message.
+ */
+ QMF_EXTERN const char* getLastError() const;
+
+ private:
+ friend class AgentImpl;
+ friend class ConsoleImpl;
+ ConnectionImpl* impl;
+ };
+
+}
+
+#endif
diff --git a/qpid/cpp/include/qmf/ConnectionSettings.h b/qpid/cpp/include/qmf/ConnectionSettings.h
new file mode 100644
index 0000000000..9bd6922a56
--- /dev/null
+++ b/qpid/cpp/include/qmf/ConnectionSettings.h
@@ -0,0 +1,143 @@
+#ifndef _QmfConnectionSettings_
+#define _QmfConnectionSettings_
+
+/*
+ * 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 "qmf/QmfImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qmf {
+
+ class ConnectionSettingsImpl;
+ class Value;
+
+ /**
+ * Settings for AMQP connections to the broker.
+ *
+ * \ingroup qmfapi
+ */
+ class ConnectionSettings {
+ public:
+
+ ConnectionSettings(const ConnectionSettings& copy);
+
+ /**
+ * Create a set of default connection settings.
+ *
+ * If no further attributes are set, the settings will cause a connection to be made to
+ * the default broker (on localhost or at a host/port supplied by service discovery) and
+ * authentication will be the best-available (GSSAPI/Kerberos, Anonymous, Plain with prompts
+ * for username and password).
+ */
+ QMF_EXTERN ConnectionSettings();
+
+ /**
+ * Create a set of connection settings by URL.
+ *
+ * @param url Universal resource locator describing the broker address and additional attributes.
+ *
+ * The URL is of the form:
+ * amqp[s]://host[:port][?key=value[&key=value]*]
+ *
+ * For example:
+ * amqp://localhost
+ * amqp://broker?transport=rdma&authmech=GSSAPI&authservice=qpidd
+ * amqps://broker?authmech=PLAIN&authuser=guest&authpass=guest
+ */
+ QMF_EXTERN ConnectionSettings(const char* url);
+
+ /**
+ * Destroy the connection settings object.
+ */
+ QMF_EXTERN ~ConnectionSettings();
+
+ /**
+ * Set an attribute to control connection setup.
+ *
+ * @param key A null-terminated string that is an attribute name.
+ *
+ * @param value Reference to a value to be stored as the attribute. The type of the value
+ * is specific to the key.
+ */
+ QMF_EXTERN void setAttr(const char* key, const Value& value);
+
+ /**
+ * Get the value of an attribute.
+ *
+ * @param key A null-terminated attribute name.
+ *
+ * @return The value associated with the attribute name.
+ */
+ QMF_EXTERN Value getAttr(const char* key) const;
+
+ /**
+ * Get the attribute string (the portion of the URL following the '?') for the settings.
+ *
+ * @return A pointer to the attribute string. If the content of this string needs to be
+ * available beyond the scope of the calling function, it should be copied. The
+ * returned pointer may become invalid if the set of attributes is changed.
+ */
+ QMF_EXTERN const char* getAttrString() const;
+
+ /**
+ * Shortcuts for setting the transport for the connection.
+ *
+ * @param port The port value for the connection address.
+ */
+ QMF_EXTERN void transportTcp(uint16_t port = 5672);
+ QMF_EXTERN void transportSsl(uint16_t port = 5671);
+ QMF_EXTERN void transportRdma(uint16_t port = 5672);
+
+ /**
+ * Shortcuts for setting authentication mechanisms.
+ *
+ * @param username Null-terminated authentication user name.
+ *
+ * @param password Null-terminated authentication password.
+ *
+ * @param serviceName Null-terminated GSSAPI service name (Kerberos service principal)
+ *
+ * @param minSsf Minimum security factor for connections. 0 = encryption not required.
+ *
+ * @param maxSsf Maximum security factor for connections. 0 = encryption not permitted.
+ */
+ QMF_EXTERN void authAnonymous(const char* username = 0);
+ QMF_EXTERN void authPlain(const char* username = 0, const char* password = 0);
+ QMF_EXTERN void authGssapi(const char* serviceName, uint32_t minSsf = 0, uint32_t maxSsf = 256);
+
+ /**
+ * Shortcut for setting connection retry attributes.
+ *
+ * @param delayMin Minimum delay (in seconds) between connection attempts.
+ *
+ * @param delaxMax Maximum delay (in seconds) between connection attempts.
+ *
+ * @param delayFactor Factor to multiply the delay by between failed connection attempts.
+ */
+ QMF_EXTERN void setRetry(int delayMin = 1, int delayMax = 128, int delayFactor = 2);
+
+ private:
+ friend class ResilientConnectionImpl;
+ ConnectionSettingsImpl* impl;
+ };
+
+}
+
+#endif
diff --git a/qpid/cpp/include/qmf/QmfImportExport.h b/qpid/cpp/include/qmf/QmfImportExport.h
new file mode 100644
index 0000000000..f5e1d9127c
--- /dev/null
+++ b/qpid/cpp/include/qmf/QmfImportExport.h
@@ -0,0 +1,33 @@
+#ifndef QMF_IMPORT_EXPORT_H
+#define QMF_IMPORT_EXPORT_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#if defined(WIN32) && !defined(QPID_DECLARE_STATIC)
+# if defined(QMF_EXPORT) || defined (qmfcommon_EXPORTS)
+# define QMF_EXTERN __declspec(dllexport)
+# else
+# define QMF_EXTERN __declspec(dllimport)
+# endif
+#else
+# define QMF_EXTERN
+#endif
+
+#endif
diff --git a/qpid/cpp/include/qpid/client/Connection.h b/qpid/cpp/include/qpid/client/Connection.h
index b7b967d232..0f5999cdcc 100644
--- a/qpid/cpp/include/qpid/client/Connection.h
+++ b/qpid/cpp/include/qpid/client/Connection.h
@@ -43,7 +43,21 @@ class ConnectionImpl;
*
* \ingroup clientapi
*
+ * Some methods use an AMQP 0-10 URL to specify connection parameters.
+ * This is defined in the AMQP 0-10 specification (http://jira.amqp.org/confluence/display/AMQP/AMQP+Specification).
+ *
+ * amqp_url = "amqp:" prot_addr_list
+ * prot_addr_list = [prot_addr ","]* prot_addr
+ * prot_addr = tcp_prot_addr | tls_prot_addr
+ *
+ * tcp_prot_addr = tcp_id tcp_addr
+ * tcp_id = "tcp:" | ""
+ * tcp_addr = [host [":" port] ]
+ * host = <as per http://www.ietf.org/rfc/rfc3986.txt>
+ * port = number]]>
+ *
*/
+
class Connection
{
framing::ProtocolVersion version;
diff --git a/qpid/cpp/include/qpid/client/amqp0_10/Codecs.h b/qpid/cpp/include/qpid/client/amqp0_10/Codecs.h
new file mode 100644
index 0000000000..5ef0b9fffe
--- /dev/null
+++ b/qpid/cpp/include/qpid/client/amqp0_10/Codecs.h
@@ -0,0 +1,61 @@
+#ifndef QPID_CLIENT_AMQP0_10_CODECS_H
+#define QPID_CLIENT_AMQP0_10_CODECS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Codec.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+
+/**
+ * Codec for encoding/decoding a map of Variants using the AMQP 0-10
+ * map encoding.
+ */
+class MapCodec : public qpid::messaging::Codec
+{
+ public:
+ void encode(const qpid::messaging::Variant&, std::string&);
+ void decode(const std::string&, qpid::messaging::Variant&);
+
+ static const std::string contentType;
+ private:
+};
+
+/**
+ * Codec for encoding/decoding a list of Variants using the AMQP 0-10
+ * list encoding.
+ */
+class ListCodec : public qpid::messaging::Codec
+{
+ public:
+ void encode(const qpid::messaging::Variant&, std::string&);
+ void decode(const std::string&, qpid::messaging::Variant&);
+
+ static const std::string contentType;
+ private:
+};
+
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_CODECS_H*/
diff --git a/qpid/cpp/include/qpid/framing/FieldTable.h b/qpid/cpp/include/qpid/framing/FieldTable.h
index a3a5c8a4ee..fd09cfc6f6 100644
--- a/qpid/cpp/include/qpid/framing/FieldTable.h
+++ b/qpid/cpp/include/qpid/framing/FieldTable.h
@@ -51,6 +51,9 @@ class FieldTable
typedef boost::shared_ptr<FieldValue> ValuePtr;
typedef std::map<std::string, ValuePtr> ValueMap;
typedef ValueMap::iterator iterator;
+ typedef ValueMap::const_reference const_reference;
+ typedef ValueMap::reference reference;
+ typedef ValueMap::value_type value_type;
QPID_COMMON_EXTERN FieldTable() {};
QPID_COMMON_EXTERN FieldTable(const FieldTable& ft);
@@ -97,12 +100,16 @@ class FieldTable
QPID_COMMON_EXTERN bool operator==(const FieldTable& other) const;
// Map-like interface.
- // TODO: may need to duplicate into versions that return mutable iterator
ValueMap::const_iterator begin() const { return values.begin(); }
ValueMap::const_iterator end() const { return values.end(); }
ValueMap::const_iterator find(const std::string& s) const { return values.find(s); }
+ ValueMap::iterator begin() { return values.begin(); }
+ ValueMap::iterator end() { return values.end(); }
+ ValueMap::iterator find(const std::string& s) { return values.find(s); }
+
std::pair <ValueMap::iterator, bool> insert(const ValueMap::value_type&);
+ QPID_COMMON_EXTERN ValueMap::iterator insert(ValueMap::iterator, const ValueMap::value_type&);
void clear() { values.clear(); }
// ### Hack Alert
diff --git a/qpid/cpp/include/qpid/framing/FieldValue.h b/qpid/cpp/include/qpid/framing/FieldValue.h
index 97fc56d606..ce4d06d2c8 100644
--- a/qpid/cpp/include/qpid/framing/FieldValue.h
+++ b/qpid/cpp/include/qpid/framing/FieldValue.h
@@ -36,7 +36,6 @@
namespace qpid {
namespace framing {
-//class Array;
/**
* Exception that is the base exception for all field table errors.
*
@@ -53,6 +52,8 @@ struct InvalidConversionException : public FieldValueException {
InvalidConversionException() {}
};
+class List;
+
/**
* Value that can appear in an AMQP field table
*
@@ -82,7 +83,7 @@ class FieldValue {
FieldValue(): data(0) {};
// Default assignment operator is fine
void setType(uint8_t type);
- uint8_t getType();
+ QPID_COMMON_EXTERN uint8_t getType();
Data& getData() { return *data; }
uint32_t encodedSize() const { return 1 + data->encodedSize(); };
bool empty() const { return data.get() == 0; }
@@ -96,12 +97,19 @@ class FieldValue {
template <typename T> bool convertsTo() const { return false; }
template <typename T> T get() const { throw InvalidConversionException(); }
+ template <class T, int W> T getIntegerValue() const;
+ template <class T, int W> T getFloatingPointValue() const;
+ template <class T> bool get(T&) const;
+
protected:
FieldValue(uint8_t t, Data* d): typeOctet(t), data(d) {}
+ QPID_COMMON_EXTERN static uint8_t* convertIfRequired(uint8_t* const octets, int width);
+
private:
uint8_t typeOctet;
std::auto_ptr<Data> data;
+
};
template <>
@@ -165,10 +173,52 @@ class FixedWidthValue : public FieldValue::Data {
return v;
}
uint8_t* rawOctets() { return octets; }
+ uint8_t* rawOctets() const { return octets; }
void print(std::ostream& o) const { o << "F" << width << ":"; };
};
+template <class T, int W>
+inline T FieldValue::getIntegerValue() const
+{
+ FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get());
+ if (fwv) {
+ uint8_t* octets = fwv->rawOctets();
+ T v = 0;
+ for (int i = 0; i < W-1; ++i) {
+ v |= octets[i]; v <<= 8;
+ }
+ v |= octets[W-1];
+ return v;
+ } else {
+ throw InvalidConversionException();
+ }
+}
+
+template <class T, int W>
+inline T FieldValue::getFloatingPointValue() const {
+ FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get());
+ if (fwv) {
+ T value;
+ uint8_t* const octets = convertIfRequired(fwv->rawOctets(), W);
+ uint8_t* const target = reinterpret_cast<uint8_t*>(&value);
+ for (uint i = 0; i < W; ++i) target[i] = octets[i];
+ return value;
+ } else {
+ throw InvalidConversionException();
+ }
+}
+
+template <>
+inline float FieldValue::get<float>() const {
+ return getFloatingPointValue<float, 4>();
+}
+
+template <>
+inline double FieldValue::get<double>() const {
+ return getFloatingPointValue<double, 8>();
+}
+
template <>
class FixedWidthValue<0> : public FieldValue::Data {
public:
@@ -243,6 +293,27 @@ class EncodedValue : public FieldValue::Data {
void print(std::ostream& o) const { o << "[" << value << "]"; };
};
+/**
+ * Accessor that can be used to get values of type FieldTable, Array
+ * and List.
+ */
+template <class T>
+inline bool FieldValue::get(T& t) const
+{
+ const EncodedValue<T>* v = dynamic_cast< EncodedValue<T>* >(data.get());
+ if (v != 0) {
+ t = v->getValue();
+ return true;
+ } else {
+ try {
+ t = get<T>();
+ return true;
+ } catch (const InvalidConversionException&) {
+ return false;
+ }
+ }
+}
+
class Str8Value : public FieldValue {
public:
QPID_COMMON_EXTERN Str8Value(const std::string& v);
@@ -294,6 +365,7 @@ class Unsigned64Value : public FieldValue {
class FieldTableValue : public FieldValue {
public:
+ typedef FieldTable ValueType;
QPID_COMMON_EXTERN FieldTableValue(const FieldTable&);
};
@@ -302,6 +374,49 @@ class ArrayValue : public FieldValue {
QPID_COMMON_EXTERN ArrayValue(const Array&);
};
+class VoidValue : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN VoidValue();
+};
+
+class BoolValue : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN BoolValue(bool);
+};
+
+class Unsigned8Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Unsigned8Value(uint8_t);
+};
+
+class Unsigned16Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Unsigned16Value(uint16_t);
+};
+
+class Unsigned32Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Unsigned32Value(uint32_t);
+};
+
+class Integer8Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Integer8Value(int8_t);
+};
+
+class Integer16Value : public FieldValue {
+ public:
+ QPID_COMMON_EXTERN Integer16Value(int16_t);
+};
+
+typedef IntegerValue Integer32Value;
+
+class ListValue : public FieldValue {
+ public:
+ typedef List ValueType;
+ QPID_COMMON_EXTERN ListValue(const List&);
+};
+
template <class T>
bool getEncodedValue(FieldTable::ValuePtr vptr, T& value)
{
@@ -315,7 +430,6 @@ bool getEncodedValue(FieldTable::ValuePtr vptr, T& value)
return false;
}
-
}} // qpid::framing
#endif
diff --git a/qpid/cpp/include/qpid/framing/List.h b/qpid/cpp/include/qpid/framing/List.h
new file mode 100644
index 0000000000..0f17c7884c
--- /dev/null
+++ b/qpid/cpp/include/qpid/framing/List.h
@@ -0,0 +1,77 @@
+#ifndef QPID_FRAMING_LIST_H
+#define QPID_FRAMING_LIST_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/CommonImportExport.h"
+#include "qpid/framing/amqp_types.h"
+#include <iostream>
+#include <list>
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace framing {
+
+class Buffer;
+class FieldValue;
+
+/**
+ * Representation of an AMQP 0-10 list
+ */
+class List
+{
+ public:
+ typedef boost::shared_ptr<FieldValue> ValuePtr;
+ typedef std::list<ValuePtr> Values;
+ typedef Values::const_iterator const_iterator;
+ typedef Values::iterator iterator;
+ typedef Values::const_reference const_reference;
+ typedef Values::reference reference;
+
+ QPID_COMMON_EXTERN uint32_t encodedSize() const;
+ QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
+ QPID_COMMON_EXTERN void decode(Buffer& buffer);
+
+ QPID_COMMON_EXTERN bool operator==(const List& other) const;
+
+ // std collection interface.
+ QPID_COMMON_EXTERN const_iterator begin() const { return values.begin(); }
+ QPID_COMMON_EXTERN const_iterator end() const { return values.end(); }
+ QPID_COMMON_EXTERN iterator begin() { return values.begin(); }
+ QPID_COMMON_EXTERN iterator end(){ return values.end(); }
+
+ QPID_COMMON_EXTERN ValuePtr front() const { return values.front(); }
+ QPID_COMMON_EXTERN ValuePtr back() const { return values.back(); }
+ QPID_COMMON_EXTERN size_t size() const { return values.size(); }
+
+ QPID_COMMON_EXTERN iterator insert(iterator i, ValuePtr value) { return values.insert(i, value); }
+ QPID_COMMON_EXTERN void erase(iterator i) { values.erase(i); }
+ QPID_COMMON_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); }
+ QPID_COMMON_EXTERN void pop_back() { values.pop_back(); }
+
+ private:
+ Values values;
+
+ friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& out, const List& list);
+};
+}} // namespace qpid::framing
+
+#endif /*!QPID_FRAMING_LIST_H*/
diff --git a/qpid/cpp/include/qpid/framing/Uuid.h b/qpid/cpp/include/qpid/framing/Uuid.h
index 0dfa7a58e7..618515622d 100644
--- a/qpid/cpp/include/qpid/framing/Uuid.h
+++ b/qpid/cpp/include/qpid/framing/Uuid.h
@@ -20,7 +20,6 @@
*/
#include "qpid/CommonImportExport.h"
-#include "qpid/sys/uuid.h"
#include "qpid/sys/IntegerTypes.h"
#include <boost/array.hpp>
@@ -38,33 +37,31 @@ class Buffer;
*
* Full value semantics, operators ==, < etc. are provided by
* boost::array so Uuid can be the key type in a map etc.
+ *
+ * TODO: change this implementation as it leaks boost into the
+ * client API
*/
struct Uuid : public boost::array<uint8_t, 16> {
/** If unique is true, generate a unique ID else a null ID. */
- Uuid(bool unique=false) { if (unique) generate(); else clear(); }
+ QPID_COMMON_EXTERN Uuid(bool unique=false);
/** Copy from 16 bytes of data. */
- Uuid(const uint8_t* data) { assign(data); }
+ QPID_COMMON_EXTERN Uuid(const uint8_t* data);
+
+ // Default op= and copy ctor are fine.
+ // boost::array gives us ==, < etc.
/** Copy from 16 bytes of data. */
- void assign(const uint8_t* data) {
- uuid_copy(c_array(), data);
- }
+ void assign(const uint8_t* data);
/** Set to a new unique identifier. */
- void generate() { uuid_generate(c_array()); }
+ QPID_COMMON_EXTERN void generate();
/** Set to all zeros. */
- void clear() { uuid_clear(c_array()); }
+ void clear();
/** Test for null (all zeros). */
- // Force int 0/!0 to false/true; avoids compile warnings.
- bool isNull() {
- return !!uuid_is_null(data());
- }
-
- // Default op= and copy ctor are fine.
- // boost::array gives us ==, < etc.
+ bool isNull();
QPID_COMMON_EXTERN void encode(framing::Buffer& buf) const;
QPID_COMMON_EXTERN void decode(framing::Buffer& buf);
diff --git a/qpid/cpp/include/qpid/management/Manageable.h b/qpid/cpp/include/qpid/management/Manageable.h
index 8062479ac6..7a72cc1592 100644
--- a/qpid/cpp/include/qpid/management/Manageable.h
+++ b/qpid/cpp/include/qpid/management/Manageable.h
@@ -43,7 +43,7 @@ class QPID_COMMON_EXTERN Manageable
static const status_t STATUS_UNKNOWN_OBJECT = 1;
static const status_t STATUS_UNKNOWN_METHOD = 2;
static const status_t STATUS_NOT_IMPLEMENTED = 3;
- static const status_t STATUS_INVALID_PARAMETER = 4;
+ static const status_t STATUS_PARAMETER_INVALID = 4;
static const status_t STATUS_FEATURE_NOT_IMPLEMENTED = 5;
static const status_t STATUS_FORBIDDEN = 6;
static const status_t STATUS_EXCEPTION = 7;
diff --git a/qpid/cpp/include/qpid/messaging/Address.h b/qpid/cpp/include/qpid/messaging/Address.h
new file mode 100644
index 0000000000..e66c52f4c2
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Address.h
@@ -0,0 +1,58 @@
+#ifndef QPID_MESSAGING_ADDRESS_H
+#define QPID_MESSAGING_ADDRESS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/ClientImportExport.h"
+#include <ostream>
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+/**
+ * Represents an address to which messages can be sent and from which
+ * messages can be received. Often a simple name is sufficient for
+ * this. However this struct allows the type of address to be
+ * specified allowing more sophisticated treatment if necessary.
+ */
+struct Address
+{
+ std::string value;
+ std::string type;
+
+ QPID_CLIENT_EXTERN Address();
+ QPID_CLIENT_EXTERN Address(const std::string& address);
+ QPID_CLIENT_EXTERN Address(const std::string& address, const std::string& type);
+ QPID_CLIENT_EXTERN operator const std::string&() const;
+ QPID_CLIENT_EXTERN const std::string& toStr() const;
+ QPID_CLIENT_EXTERN operator bool() const;
+ QPID_CLIENT_EXTERN bool operator !() const;
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const Address& address);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_ADDRESS_H*/
diff --git a/qpid/cpp/include/qpid/messaging/Codec.h b/qpid/cpp/include/qpid/messaging/Codec.h
new file mode 100644
index 0000000000..bacec5c786
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Codec.h
@@ -0,0 +1,44 @@
+#ifndef QPID_MESSAGING_CODEC_H
+#define QPID_MESSAGING_CODEC_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace messaging {
+
+class Variant;
+/**
+ *
+ */
+class Codec
+{
+ public:
+ QPID_CLIENT_EXTERN virtual ~Codec() {}
+ virtual void encode(const Variant&, std::string&) = 0;
+ virtual void decode(const std::string&, Variant&) = 0;
+ private:
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_CODEC_H*/
diff --git a/qpid/cpp/include/qpid/messaging/Connection.h b/qpid/cpp/include/qpid/messaging/Connection.h
new file mode 100644
index 0000000000..19dae586a4
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Connection.h
@@ -0,0 +1,67 @@
+#ifndef QPID_MESSAGING_CONNECTION_H
+#define QPID_MESSAGING_CONNECTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+#include "qpid/messaging/Variant.h"
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+
+}
+
+namespace messaging {
+
+class ConnectionImpl;
+class Session;
+
+class Connection : public qpid::client::Handle<ConnectionImpl>
+{
+ public:
+ static QPID_CLIENT_EXTERN Connection open(const std::string& url, const Variant::Map& options = Variant::Map());
+
+ QPID_CLIENT_EXTERN Connection(ConnectionImpl* impl = 0);
+ QPID_CLIENT_EXTERN Connection(const Connection&);
+ QPID_CLIENT_EXTERN ~Connection();
+ QPID_CLIENT_EXTERN Connection& operator=(const Connection&);
+ QPID_CLIENT_EXTERN void close();
+ QPID_CLIENT_EXTERN Session newSession();
+ private:
+ friend class qpid::client::PrivateImplRef<Connection>;
+
+};
+
+struct InvalidOptionString : public qpid::Exception
+{
+ InvalidOptionString(const std::string& msg);
+};
+
+QPID_CLIENT_EXTERN void parseOptionString(const std::string&, Variant::Map&);
+QPID_CLIENT_EXTERN Variant::Map parseOptionString(const std::string&);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_CONNECTION_H*/
diff --git a/qpid/cpp/include/qpid/messaging/Filter.h b/qpid/cpp/include/qpid/messaging/Filter.h
new file mode 100644
index 0000000000..5cd844cf73
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Filter.h
@@ -0,0 +1,48 @@
+#ifndef QPID_MESSAGING_FILTER_H
+#define QPID_MESSAGING_FILTER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include <vector>
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+struct Filter
+{
+ std::string type;
+ std::vector<std::string> patterns;
+
+ QPID_CLIENT_EXTERN Filter(std::string type, std::string pattern);
+ QPID_CLIENT_EXTERN Filter(std::string type, std::string pattern1, std::string pattern2);
+
+ static QPID_CLIENT_EXTERN const std::string WILDCARD;
+ static QPID_CLIENT_EXTERN const std::string EXACT_MATCH;
+};
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_FILTER_H*/
diff --git a/qpid/cpp/include/qpid/messaging/Message.h b/qpid/cpp/include/qpid/messaging/Message.h
new file mode 100644
index 0000000000..e68d8a1141
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Message.h
@@ -0,0 +1,88 @@
+#ifndef QPID_MESSAGING_MESSAGE_H
+#define QPID_MESSAGING_MESSAGE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include "qpid/messaging/Variant.h"
+#include "qpid/messaging/MessageContent.h"
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+struct Address;
+class Codec;
+struct MessageImpl;
+
+/**
+ * Representation of a message.
+ */
+class Message
+{
+ public:
+ QPID_CLIENT_EXTERN Message(const std::string& bytes = std::string());
+ QPID_CLIENT_EXTERN Message(const char*, size_t);
+ QPID_CLIENT_EXTERN Message(const Message&);
+ QPID_CLIENT_EXTERN ~Message();
+
+ QPID_CLIENT_EXTERN Message& operator=(const Message&);
+
+ QPID_CLIENT_EXTERN void setReplyTo(const Address&);
+ QPID_CLIENT_EXTERN const Address& getReplyTo() const;
+
+ QPID_CLIENT_EXTERN void setSubject(const std::string&);
+ QPID_CLIENT_EXTERN const std::string& getSubject() const;
+
+ QPID_CLIENT_EXTERN void setContentType(const std::string&);
+ QPID_CLIENT_EXTERN const std::string& getContentType() const;
+
+ QPID_CLIENT_EXTERN const VariantMap& getHeaders() const;
+ QPID_CLIENT_EXTERN VariantMap& getHeaders();
+
+ QPID_CLIENT_EXTERN const std::string& getBytes() const;
+ QPID_CLIENT_EXTERN std::string& getBytes();
+ QPID_CLIENT_EXTERN void setBytes(const std::string&);
+ QPID_CLIENT_EXTERN void setBytes(const char* chars, size_t count);
+ QPID_CLIENT_EXTERN const char* getRawContent() const;
+ QPID_CLIENT_EXTERN size_t getContentSize() const;
+
+
+ QPID_CLIENT_EXTERN MessageContent& getContent();
+ QPID_CLIENT_EXTERN const MessageContent& getContent() const;
+ QPID_CLIENT_EXTERN void setContent(const std::string& s);
+ QPID_CLIENT_EXTERN void setContent(const Variant::Map&);
+ QPID_CLIENT_EXTERN void setContent(const Variant::List&);
+
+ QPID_CLIENT_EXTERN void encode(Codec&);
+ QPID_CLIENT_EXTERN void decode(Codec&);
+
+ private:
+ MessageImpl* impl;
+ friend struct MessageImplAccess;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MESSAGE_H*/
diff --git a/qpid/cpp/include/qpid/messaging/MessageContent.h b/qpid/cpp/include/qpid/messaging/MessageContent.h
new file mode 100644
index 0000000000..7c3a636c07
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/MessageContent.h
@@ -0,0 +1,90 @@
+#ifndef QPID_MESSAGING_MESSAGECONTENT_H
+#define QPID_MESSAGING_MESSAGECONTENT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/messaging/Variant.h"
+#include <string>
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace messaging {
+
+/**
+ *
+ */
+class MessageContent
+{
+ public:
+ QPID_CLIENT_EXTERN virtual ~MessageContent() {}
+
+ virtual const std::string& asString() const = 0;
+ virtual std::string& asString() = 0;
+
+ virtual const char* asChars() const = 0;
+ virtual size_t size() const = 0;
+
+ virtual const Variant::Map& asMap() const = 0;
+ virtual Variant::Map& asMap() = 0;
+ virtual bool isMap() const = 0;
+
+ virtual const Variant::List& asList() const = 0;
+ virtual Variant::List& asList() = 0;
+ virtual bool isList() const = 0;
+
+ virtual void clear() = 0;
+
+ virtual Variant& operator[](const std::string&) = 0;
+
+
+ virtual std::ostream& print(std::ostream& out) const = 0;
+
+
+ //operator<< for variety of types... (is this a good idea?)
+ virtual MessageContent& operator<<(const std::string&) = 0;
+ virtual MessageContent& operator<<(const char*) = 0;
+ virtual MessageContent& operator<<(bool) = 0;
+ virtual MessageContent& operator<<(int8_t) = 0;
+ virtual MessageContent& operator<<(int16_t) = 0;
+ virtual MessageContent& operator<<(int32_t) = 0;
+ virtual MessageContent& operator<<(int64_t) = 0;
+ virtual MessageContent& operator<<(uint8_t) = 0;
+ virtual MessageContent& operator<<(uint16_t) = 0;
+ virtual MessageContent& operator<<(uint32_t) = 0;
+ virtual MessageContent& operator<<(uint64_t) = 0;
+ virtual MessageContent& operator<<(double) = 0;
+ virtual MessageContent& operator<<(float) = 0;
+
+ //assignment from string, map and list
+ virtual MessageContent& operator=(const std::string&) = 0;
+ virtual MessageContent& operator=(const char*) = 0;
+ virtual MessageContent& operator=(const Variant::Map&) = 0;
+ virtual MessageContent& operator=(const Variant::List&) = 0;
+
+ private:
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const MessageContent& content);
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MESSAGECONTENT_H*/
diff --git a/qpid/cpp/include/qpid/messaging/MessageListener.h b/qpid/cpp/include/qpid/messaging/MessageListener.h
new file mode 100644
index 0000000000..72811e7b9c
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/MessageListener.h
@@ -0,0 +1,49 @@
+#ifndef QPID_MESSAGING_MESSAGELISTENER_H
+#define QPID_MESSAGING_MESSAGELISTENER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace messaging {
+
+class Message;
+
+/**
+ * To use a push style interface for receiving messages, applications
+ * provide implementations of this interface and pass an implementing
+ * instance to MessageSource::subscribe().
+ *
+ * Messages arriving for that subscription will then be passed to the
+ * implementation via the received() method.
+ */
+class MessageListener
+{
+ public:
+ QPID_CLIENT_EXTERN virtual ~MessageListener() {}
+ virtual void received(Message&) = 0;
+ private:
+};
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MESSAGELISTENER_H*/
diff --git a/qpid/cpp/include/qpid/messaging/Receiver.h b/qpid/cpp/include/qpid/messaging/Receiver.h
new file mode 100644
index 0000000000..e51e1093d1
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Receiver.h
@@ -0,0 +1,115 @@
+#ifndef QPID_MESSAGING_RECEIVER_H
+#define QPID_MESSAGING_RECEIVER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/Exception.h"
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+
+}
+
+namespace messaging {
+
+class Message;
+class MessageListener;
+class ReceiverImpl;
+
+/**
+ * A pull style interface for message retrieval.
+ */
+class Receiver : public qpid::client::Handle<ReceiverImpl>
+{
+ public:
+ struct NoMessageAvailable : qpid::Exception {};
+
+ QPID_CLIENT_EXTERN Receiver(ReceiverImpl* impl = 0);
+ QPID_CLIENT_EXTERN Receiver(const Receiver&);
+ QPID_CLIENT_EXTERN ~Receiver();
+ QPID_CLIENT_EXTERN Receiver& operator=(const Receiver&);
+ /**
+ * Retrieves a message from this receivers local queue, or waits
+ * for upto the specified timeout for a message to become
+ * available. Returns false if there is no message to give after
+ * waiting for the specified timeout.
+ */
+ QPID_CLIENT_EXTERN bool get(Message& message, qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ /**
+ * Retrieves a message from this receivers local queue, or waits
+ * for upto the specified timeout for a message to become
+ * available. Throws NoMessageAvailable if there is no
+ * message to give after waiting for the specified timeout.
+ */
+ QPID_CLIENT_EXTERN Message get(qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ /**
+ * Retrieves a message for this receivers subscription or waits
+ * for upto the specified timeout for one to become
+ * available. Unlike get() this method will check with the server
+ * that there is no message for the subscription this receiver is
+ * serving before returning false.
+ */
+ QPID_CLIENT_EXTERN bool fetch(Message& message, qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ /**
+ * Retrieves a message for this receivers subscription or waits
+ * for upto the specified timeout for one to become
+ * available. Unlike get() this method will check with the server
+ * that there is no message for the subscription this receiver is
+ * serving before throwing an exception.
+ */
+ QPID_CLIENT_EXTERN Message fetch(qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+
+ /**
+ * Enables the message flow for this receiver
+ */
+ QPID_CLIENT_EXTERN void start();
+ /**
+ * Stops the message flow for this receiver (without actually
+ * cancelling the subscription).
+ */
+ QPID_CLIENT_EXTERN void stop();
+ /**
+ * Sets the capacity for the receiver. The capacity determines how
+ * many incoming messages can be held in the receiver before being
+ * requested by a client via fetch() (or pushed to a listener).
+ */
+ QPID_CLIENT_EXTERN void setCapacity(uint32_t);
+
+ /**
+ * Cancels this receiver
+ */
+ QPID_CLIENT_EXTERN void cancel();
+
+ /**
+ * Set a message listener for receiving messages asynchronously.
+ */
+ QPID_CLIENT_EXTERN void setListener(MessageListener* listener);
+ private:
+ friend class qpid::client::PrivateImplRef<Receiver>;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_RECEIVER_H*/
diff --git a/qpid/cpp/include/qpid/messaging/Sender.h b/qpid/cpp/include/qpid/messaging/Sender.h
new file mode 100644
index 0000000000..45ec659ecf
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Sender.h
@@ -0,0 +1,57 @@
+#ifndef QPID_MESSAGING_SENDER_H
+#define QPID_MESSAGING_SENDER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+
+}
+
+namespace messaging {
+
+class Message;
+class SenderImpl;
+
+/**
+ * Interface through which messages are sent.
+ */
+class Sender : public qpid::client::Handle<SenderImpl>
+{
+ public:
+ QPID_CLIENT_EXTERN Sender(SenderImpl* impl = 0);
+ QPID_CLIENT_EXTERN Sender(const Sender&);
+ QPID_CLIENT_EXTERN ~Sender();
+ QPID_CLIENT_EXTERN Sender& operator=(const Sender&);
+
+ QPID_CLIENT_EXTERN void send(const Message& message);
+ QPID_CLIENT_EXTERN void cancel();
+ private:
+ friend class qpid::client::PrivateImplRef<Sender>;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_SENDER_H*/
diff --git a/qpid/cpp/include/qpid/messaging/Session.h b/qpid/cpp/include/qpid/messaging/Session.h
new file mode 100644
index 0000000000..1d88882db6
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Session.h
@@ -0,0 +1,99 @@
+#ifndef QPID_MESSAGING_SESSION_H
+#define QPID_MESSAGING_SESSION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/ClientImportExport.h"
+#include "qpid/client/Handle.h"
+#include "qpid/sys/Time.h"
+#include "Variant.h"
+
+namespace qpid {
+namespace client {
+
+template <class> class PrivateImplRef;
+
+}
+
+namespace messaging {
+
+struct Address;
+struct Filter;
+class Message;
+class MessageListener;
+class Sender;
+class Receiver;
+class SessionImpl;
+class Subscription;
+
+/**
+ * A session represents a distinct 'conversation' which can involve
+ * sending and receiving messages from different sources and sinks.
+ */
+class Session : public qpid::client::Handle<SessionImpl>
+{
+ public:
+ QPID_CLIENT_EXTERN Session(SessionImpl* impl = 0);
+ QPID_CLIENT_EXTERN Session(const Session&);
+ QPID_CLIENT_EXTERN ~Session();
+ QPID_CLIENT_EXTERN Session& operator=(const Session&);
+
+ QPID_CLIENT_EXTERN void close();
+
+ QPID_CLIENT_EXTERN void commit();
+ QPID_CLIENT_EXTERN void rollback();
+
+ /**
+ * Acknowledges all outstanding messages that have been received
+ * by the application on this session.
+ */
+ QPID_CLIENT_EXTERN void acknowledge();
+ /**
+ * Rejects the specified message. This will prevent the message
+ * being redelivered.
+ */
+ QPID_CLIENT_EXTERN void reject(Message&);
+
+ QPID_CLIENT_EXTERN void sync();
+ QPID_CLIENT_EXTERN void flush();
+
+ QPID_CLIENT_EXTERN bool fetch(Message& message, qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ QPID_CLIENT_EXTERN Message fetch(qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+ QPID_CLIENT_EXTERN bool dispatch(qpid::sys::Duration timeout=qpid::sys::TIME_INFINITE);
+
+ QPID_CLIENT_EXTERN Sender createSender(const Address& address, const VariantMap& options = VariantMap());
+ QPID_CLIENT_EXTERN Sender createSender(const std::string& address, const VariantMap& options = VariantMap());
+
+ QPID_CLIENT_EXTERN Receiver createReceiver(const Address& address, const VariantMap& options = VariantMap());
+ QPID_CLIENT_EXTERN Receiver createReceiver(const Address& address, const Filter& filter, const VariantMap& options = VariantMap());
+ QPID_CLIENT_EXTERN Receiver createReceiver(const std::string& address, const VariantMap& options = VariantMap());
+ QPID_CLIENT_EXTERN Receiver createReceiver(const std::string& address, const Filter& filter, const VariantMap& options = VariantMap());
+
+ QPID_CLIENT_EXTERN Address createTempQueue(const std::string& baseName = std::string());
+
+ QPID_CLIENT_EXTERN void* getLastConfirmedSent();
+ QPID_CLIENT_EXTERN void* getLastConfirmedAcknowledged();
+ private:
+ friend class qpid::client::PrivateImplRef<Session>;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_SESSION_H*/
diff --git a/qpid/cpp/include/qpid/messaging/Variant.h b/qpid/cpp/include/qpid/messaging/Variant.h
new file mode 100644
index 0000000000..1e51914794
--- /dev/null
+++ b/qpid/cpp/include/qpid/messaging/Variant.h
@@ -0,0 +1,167 @@
+#ifndef QPID_MESSAGING_VARIANT_H
+#define QPID_MESSAGING_VARIANT_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <list>
+#include <map>
+#include <ostream>
+#include <string>
+#include "qpid/Exception.h"
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/client/ClientImportExport.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+/**
+ * Thrown when an illegal conversion of a variant is attempted.
+ */
+struct InvalidConversion : public qpid::Exception
+{
+ InvalidConversion(const std::string& msg);
+};
+
+enum VariantType {
+ VAR_VOID = 0,
+ VAR_BOOL,
+ VAR_UINT8,
+ VAR_UINT16,
+ VAR_UINT32,
+ VAR_UINT64,
+ VAR_INT8,
+ VAR_INT16,
+ VAR_INT32,
+ VAR_INT64,
+ VAR_FLOAT,
+ VAR_DOUBLE,
+ VAR_STRING,
+ VAR_MAP,
+ VAR_LIST
+};
+
+class VariantImpl;
+
+/**
+ * Represents a value of variable type.
+ */
+class Variant
+{
+ public:
+ typedef std::map<std::string, Variant> Map;
+ typedef std::list<Variant> List;
+
+ QPID_CLIENT_EXTERN Variant();
+ QPID_CLIENT_EXTERN Variant(bool);
+ QPID_CLIENT_EXTERN Variant(uint8_t);
+ QPID_CLIENT_EXTERN Variant(uint16_t);
+ QPID_CLIENT_EXTERN Variant(uint32_t);
+ QPID_CLIENT_EXTERN Variant(uint64_t);
+ QPID_CLIENT_EXTERN Variant(int8_t);
+ QPID_CLIENT_EXTERN Variant(int16_t);
+ QPID_CLIENT_EXTERN Variant(int32_t);
+ QPID_CLIENT_EXTERN Variant(int64_t);
+ QPID_CLIENT_EXTERN Variant(float);
+ QPID_CLIENT_EXTERN Variant(double);
+ QPID_CLIENT_EXTERN Variant(const std::string&);
+ QPID_CLIENT_EXTERN Variant(const char*);
+ QPID_CLIENT_EXTERN Variant(const Map&);
+ QPID_CLIENT_EXTERN Variant(const List&);
+ QPID_CLIENT_EXTERN Variant(const Variant&);
+
+ QPID_CLIENT_EXTERN ~Variant();
+
+ QPID_CLIENT_EXTERN VariantType getType() const;
+
+ QPID_CLIENT_EXTERN Variant& operator=(bool);
+ QPID_CLIENT_EXTERN Variant& operator=(uint8_t);
+ QPID_CLIENT_EXTERN Variant& operator=(uint16_t);
+ QPID_CLIENT_EXTERN Variant& operator=(uint32_t);
+ QPID_CLIENT_EXTERN Variant& operator=(uint64_t);
+ QPID_CLIENT_EXTERN Variant& operator=(int8_t);
+ QPID_CLIENT_EXTERN Variant& operator=(int16_t);
+ QPID_CLIENT_EXTERN Variant& operator=(int32_t);
+ QPID_CLIENT_EXTERN Variant& operator=(int64_t);
+ QPID_CLIENT_EXTERN Variant& operator=(float);
+ QPID_CLIENT_EXTERN Variant& operator=(double);
+ QPID_CLIENT_EXTERN Variant& operator=(const std::string&);
+ QPID_CLIENT_EXTERN Variant& operator=(const char*);
+ QPID_CLIENT_EXTERN Variant& operator=(const Map&);
+ QPID_CLIENT_EXTERN Variant& operator=(const List&);
+ QPID_CLIENT_EXTERN Variant& operator=(const Variant&);
+
+ QPID_CLIENT_EXTERN bool asBool() const;
+ QPID_CLIENT_EXTERN uint8_t asUint8() const;
+ QPID_CLIENT_EXTERN uint16_t asUint16() const;
+ QPID_CLIENT_EXTERN uint32_t asUint32() const;
+ QPID_CLIENT_EXTERN uint64_t asUint64() const;
+ QPID_CLIENT_EXTERN int8_t asInt8() const;
+ QPID_CLIENT_EXTERN int16_t asInt16() const;
+ QPID_CLIENT_EXTERN int32_t asInt32() const;
+ QPID_CLIENT_EXTERN int64_t asInt64() const;
+ QPID_CLIENT_EXTERN float asFloat() const;
+ QPID_CLIENT_EXTERN double asDouble() const;
+ QPID_CLIENT_EXTERN std::string asString() const;
+
+ QPID_CLIENT_EXTERN operator bool() const;
+ QPID_CLIENT_EXTERN operator uint8_t() const;
+ QPID_CLIENT_EXTERN operator uint16_t() const;
+ QPID_CLIENT_EXTERN operator uint32_t() const;
+ QPID_CLIENT_EXTERN operator uint64_t() const;
+ QPID_CLIENT_EXTERN operator int8_t() const;
+ QPID_CLIENT_EXTERN operator int16_t() const;
+ QPID_CLIENT_EXTERN operator int32_t() const;
+ QPID_CLIENT_EXTERN operator int64_t() const;
+ QPID_CLIENT_EXTERN operator float() const;
+ QPID_CLIENT_EXTERN operator double() const;
+ QPID_CLIENT_EXTERN operator const char*() const;
+
+ QPID_CLIENT_EXTERN const Map& asMap() const;
+ QPID_CLIENT_EXTERN Map& asMap();
+ QPID_CLIENT_EXTERN const List& asList() const;
+ QPID_CLIENT_EXTERN List& asList();
+ /**
+ * Unlike asString(), getString() will not do any conversions and
+ * will throw InvalidConversion if the type is not STRING.
+ */
+ QPID_CLIENT_EXTERN const std::string& getString() const;
+ QPID_CLIENT_EXTERN std::string& getString();
+
+ QPID_CLIENT_EXTERN void setEncoding(const std::string&);
+ QPID_CLIENT_EXTERN const std::string& getEncoding() const;
+
+ QPID_CLIENT_EXTERN void reset();
+ private:
+ VariantImpl* impl;
+};
+
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const Variant& value);
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const Variant::Map& map);
+QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const Variant::List& list);
+
+typedef Variant::Map VariantMap;
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_VARIANT_H*/
diff --git a/qpid/cpp/include/qpid/sys/windows/Condition.h b/qpid/cpp/include/qpid/sys/windows/Condition.h
index c31f7b4823..979fae9b0a 100755
--- a/qpid/cpp/include/qpid/sys/windows/Condition.h
+++ b/qpid/cpp/include/qpid/sys/windows/Condition.h
@@ -30,7 +30,6 @@
#include <boost/thread/condition.hpp>
#include <boost/thread/thread_time.hpp>
#include <windows.h>
-#undef STATUS_INVALID_PARAMETER // Hack for windows.h namespace pollution
namespace qpid {
namespace sys {
diff --git a/qpid/cpp/include/qpid/sys/windows/Mutex.h b/qpid/cpp/include/qpid/sys/windows/Mutex.h
index 12768640d5..5dcc69e836 100755
--- a/qpid/cpp/include/qpid/sys/windows/Mutex.h
+++ b/qpid/cpp/include/qpid/sys/windows/Mutex.h
@@ -31,7 +31,6 @@
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/tss.hpp>
-#undef STATUS_INVALID_PARAMETER // Hack for windows.h namespace pollution
namespace qpid {
namespace sys {
diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt
index a1d01ceca4..ff0188890b 100644
--- a/qpid/cpp/src/CMakeLists.txt
+++ b/qpid/cpp/src/CMakeLists.txt
@@ -451,6 +451,7 @@ set (libqpidcommon_SOURCES
qpid/framing/FieldValue.cpp
qpid/framing/FrameSet.cpp
qpid/framing/FrameDecoder.cpp
+ qpid/framing/List.cpp
qpid/framing/ProtocolInitiation.cpp
qpid/framing/ProtocolVersion.cpp
qpid/framing/SendContent.cpp
@@ -522,6 +523,40 @@ set (libqpidclient_SOURCES
qpid/client/SubscriptionImpl.cpp
qpid/client/SubscriptionManager.cpp
qpid/client/SubscriptionManagerImpl.cpp
+ qpid/messaging/Address.cpp
+ qpid/messaging/Connection.cpp
+ qpid/messaging/ConnectionImpl.h
+ qpid/messaging/Filter.cpp
+ qpid/messaging/Message.cpp
+ qpid/messaging/MessageImpl.h
+ qpid/messaging/MessageImpl.cpp
+ qpid/messaging/Receiver.cpp
+ qpid/messaging/ReceiverImpl.h
+ qpid/messaging/Session.cpp
+ qpid/messaging/SessionImpl.h
+ qpid/messaging/Sender.cpp
+ qpid/messaging/SenderImpl.h
+ qpid/messaging/Variant.cpp
+ qpid/client/amqp0_10/AddressResolution.h
+ qpid/client/amqp0_10/AddressResolution.cpp
+ qpid/client/amqp0_10/Codecs.cpp
+ qpid/client/amqp0_10/CodecsInternal.h
+ qpid/client/amqp0_10/CompletionTracker.h
+ qpid/client/amqp0_10/CompletionTracker.cpp
+ qpid/client/amqp0_10/ConnectionImpl.h
+ qpid/client/amqp0_10/ConnectionImpl.cpp
+ qpid/client/amqp0_10/IncomingMessages.h
+ qpid/client/amqp0_10/IncomingMessages.cpp
+ qpid/client/amqp0_10/MessageSink.h
+ qpid/client/amqp0_10/MessageSource.h
+ qpid/client/amqp0_10/OutgoingMessage.h
+ qpid/client/amqp0_10/OutgoingMessage.cpp
+ qpid/client/amqp0_10/ReceiverImpl.h
+ qpid/client/amqp0_10/ReceiverImpl.cpp
+ qpid/client/amqp0_10/SessionImpl.h
+ qpid/client/amqp0_10/SessionImpl.cpp
+ qpid/client/amqp0_10/SenderImpl.h
+ qpid/client/amqp0_10/SenderImpl.cpp
)
add_library (qpidclient SHARED ${libqpidclient_SOURCES})
target_link_libraries (qpidclient qpidcommon)
@@ -615,10 +650,10 @@ target_link_libraries (qpidd qpidbroker qpidcommon ${Boost_PROGRAM_OPTIONS_LIBRA
# qpid/agent/ManagementAgent.h \
# qpid/agent/ManagementAgentImpl.h
set (qmfagent_SOURCES
- ../include/qpid/agent/ManagementAgent.h
- qpid/agent/ManagementAgentImpl.cpp
- qpid/agent/ManagementAgentImpl.h
- qmf/Agent.cpp
+ qmf/AgentEngine.cpp
+ qmf/AgentEngine.h
+ qpid/agent/ManagementAgentImpl.cpp
+ qpid/agent/ManagementAgentImpl.h
)
add_library (qmfagent SHARED ${qmfagent_SOURCES})
target_link_libraries (qmfagent qmfcommon)
@@ -626,14 +661,31 @@ set_target_properties (qmfagent PROPERTIES
VERSION ${qpidc_version})
set (qmfcommon_SOURCES
- qmf/Agent.cpp
- qmf/ResilientConnection.cpp
+ qmf/ConnectionSettingsImpl.cpp
+ qmf/ConnectionSettingsImpl.h
+ qmf/ConsoleEngine.h
+ qmf/Event.h
+ qmf/Message.h
qmf/MessageImpl.cpp
- qmf/SchemaImpl.cpp
- qmf/ValueImpl.cpp
+ qmf/MessageImpl.h
+ qmf/Object.h
+ qmf/ObjectId.h
qmf/ObjectIdImpl.cpp
+ qmf/ObjectIdImpl.h
qmf/ObjectImpl.cpp
+ qmf/ObjectImpl.h
+ qmf/Query.h
qmf/QueryImpl.cpp
+ qmf/QueryImpl.h
+ qmf/ResilientConnection.cpp
+ qmf/ResilientConnection.h
+ qmf/Schema.h
+ qmf/SchemaImpl.cpp
+ qmf/SchemaImpl.h
+ qmf/Typecode.h
+ qmf/Value.h
+ qmf/ValueImpl.cpp
+ qmf/ValueImpl.h
)
add_library (qmfcommon SHARED ${qmfcommon_SOURCES})
target_link_libraries (qmfcommon qpidclient)
diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am
index 0eff526203..75cda31dbb 100644
--- a/qpid/cpp/src/Makefile.am
+++ b/qpid/cpp/src/Makefile.am
@@ -54,7 +54,7 @@ windows_dist = \
qpid/sys/windows/Time.cpp \
../include/qpid/sys/windows/Time.h \
qpid/sys/windows/uuid.cpp \
- ../include/qpid/sys/windows/uuid.h \
+ qpid/sys/windows/uuid.h \
windows/QpiddBroker.cpp \
qpid/broker/windows/BrokerDefaults.cpp \
qpid/broker/windows/SaslAuthenticator.cpp
@@ -378,6 +378,7 @@ libqpidcommon_la_SOURCES += \
qpid/framing/InputHandler.h \
qpid/framing/Invoker.h \
qpid/framing/IsInSequenceSet.h \
+ qpid/framing/List.cpp \
qpid/framing/MethodBodyFactory.h \
qpid/framing/MethodContent.h \
qpid/framing/ModelMethod.h \
@@ -460,7 +461,8 @@ libqpidcommon_la_SOURCES += \
qpid/sys/Timer.cpp \
qpid/sys/Timer.h \
qpid/sys/Waitable.h \
- qpid/sys/alloca.h
+ qpid/sys/alloca.h \
+ qpid/sys/uuid.h
if HAVE_SASL
libqpidcommon_la_SOURCES += qpid/sys/cyrus/CyrusSecurityLayer.h
@@ -680,7 +682,41 @@ libqpidclient_la_SOURCES = \
qpid/client/SubscriptionImpl.h \
qpid/client/SubscriptionManager.cpp \
qpid/client/SubscriptionManagerImpl.cpp \
- qpid/client/SubscriptionManagerImpl.h
+ qpid/client/SubscriptionManagerImpl.h \
+ qpid/messaging/Address.cpp \
+ qpid/messaging/Connection.cpp \
+ qpid/messaging/Filter.cpp \
+ qpid/messaging/Message.cpp \
+ qpid/messaging/MessageImpl.h \
+ qpid/messaging/MessageImpl.cpp \
+ qpid/messaging/Sender.cpp \
+ qpid/messaging/Receiver.cpp \
+ qpid/messaging/Session.cpp \
+ qpid/messaging/Variant.cpp \
+ qpid/messaging/ConnectionImpl.h \
+ qpid/messaging/SenderImpl.h \
+ qpid/messaging/ReceiverImpl.h \
+ qpid/messaging/SessionImpl.h \
+ qpid/client/amqp0_10/AddressResolution.h \
+ qpid/client/amqp0_10/AddressResolution.cpp \
+ qpid/client/amqp0_10/Codecs.cpp \
+ qpid/client/amqp0_10/CodecsInternal.h \
+ qpid/client/amqp0_10/ConnectionImpl.h \
+ qpid/client/amqp0_10/ConnectionImpl.cpp \
+ qpid/client/amqp0_10/CompletionTracker.h \
+ qpid/client/amqp0_10/CompletionTracker.cpp \
+ qpid/client/amqp0_10/IncomingMessages.h \
+ qpid/client/amqp0_10/IncomingMessages.cpp \
+ qpid/client/amqp0_10/MessageSink.h \
+ qpid/client/amqp0_10/MessageSource.h \
+ qpid/client/amqp0_10/OutgoingMessage.h \
+ qpid/client/amqp0_10/OutgoingMessage.cpp \
+ qpid/client/amqp0_10/ReceiverImpl.h \
+ qpid/client/amqp0_10/ReceiverImpl.cpp \
+ qpid/client/amqp0_10/SessionImpl.h \
+ qpid/client/amqp0_10/SessionImpl.cpp \
+ qpid/client/amqp0_10/SenderImpl.h \
+ qpid/client/amqp0_10/SenderImpl.cpp
# NOTE: only public header files (which should be in ../include)
# should go in this list. Private headers should go in the SOURCES
@@ -723,6 +759,7 @@ nobase_include_HEADERS += \
../include/qpid/framing/Buffer.h \
../include/qpid/framing/FieldTable.h \
../include/qpid/framing/FieldValue.h \
+ ../include/qpid/framing/List.h \
../include/qpid/framing/ProtocolVersion.h \
../include/qpid/framing/SequenceNumber.h \
../include/qpid/framing/SequenceSet.h \
@@ -749,7 +786,18 @@ nobase_include_HEADERS += \
../include/qpid/sys/SystemInfo.h \
../include/qpid/sys/Thread.h \
../include/qpid/sys/Time.h \
- ../include/qpid/sys/uuid.h
+ ../include/qpid/messaging/Address.h \
+ ../include/qpid/messaging/Connection.h \
+ ../include/qpid/messaging/Codec.h \
+ ../include/qpid/messaging/Filter.h \
+ ../include/qpid/messaging/Message.h \
+ ../include/qpid/messaging/MessageContent.h \
+ ../include/qpid/messaging/MessageListener.h \
+ ../include/qpid/messaging/Sender.h \
+ ../include/qpid/messaging/Receiver.h \
+ ../include/qpid/messaging/Session.h \
+ ../include/qpid/messaging/Variant.h \
+ ../include/qpid/client/amqp0_10/Codecs.h
# Force build of qpidd during dist phase so help2man will work.
dist-hook: $(BUILT_SOURCES)
diff --git a/qpid/cpp/src/qmf.mk b/qpid/cpp/src/qmf.mk
index 62393cdcfb..54110ebaf7 100644
--- a/qpid/cpp/src/qmf.mk
+++ b/qpid/cpp/src/qmf.mk
@@ -18,7 +18,7 @@
#
#
-# qmf agent library makefile fragment, to be included in Makefile.am
+# qmf library makefile fragment, to be included in Makefile.am
#
lib_LTLIBRARIES += \
libqmfcommon.la \
@@ -27,13 +27,18 @@ lib_LTLIBRARIES += \
# Public header files
nobase_include_HEADERS += \
../include/qpid/agent/ManagementAgent.h \
- ../include/qpid/agent/QmfAgentImportExport.h
-
+ ../include/qpid/agent/QmfAgentImportExport.h \
+ ../include/qmf/Agent.h \
+ ../include/qmf/Connection.h \
+ ../include/qmf/QmfImportExport.h \
+ ../include/qmf/ConnectionSettings.h \
+ ../include/qmf/AgentObject.h
libqmfcommon_la_SOURCES = \
- qmf/Agent.cpp \
- qmf/Agent.h \
- qmf/Console.h \
+ qmf/ConnectionSettingsImpl.cpp \
+ qmf/ConnectionSettingsImpl.h \
+ qmf/ConsoleEngine.cpp \
+ qmf/ConsoleEngine.h \
qmf/Event.h \
qmf/Message.h \
qmf/MessageImpl.cpp \
@@ -44,11 +49,15 @@ libqmfcommon_la_SOURCES = \
qmf/ObjectIdImpl.h \
qmf/ObjectImpl.cpp \
qmf/ObjectImpl.h \
+ qmf/Protocol.cpp \
+ qmf/Protocol.h \
qmf/Query.h \
qmf/QueryImpl.cpp \
qmf/QueryImpl.h \
qmf/ResilientConnection.cpp \
qmf/ResilientConnection.h \
+ qmf/SequenceManager.cpp \
+ qmf/SequenceManager.h \
qmf/Schema.h \
qmf/SchemaImpl.cpp \
qmf/SchemaImpl.h \
@@ -58,9 +67,9 @@ libqmfcommon_la_SOURCES = \
qmf/ValueImpl.h
libqmfagent_la_SOURCES = \
- ../include/qpid/agent/ManagementAgent.h \
+ qmf/AgentEngine.cpp \
+ qmf/AgentEngine.h \
qpid/agent/ManagementAgentImpl.cpp \
- qpid/agent/ManagementAgentImpl.h \
- qmf/Agent.cpp
+ qpid/agent/ManagementAgentImpl.h
-libqmfagent_la_LIBADD = libqpidclient.la
+libqmfagent_la_LIBADD = libqpidclient.la libqmfcommon.la
diff --git a/qpid/cpp/src/qmf/Agent.cpp b/qpid/cpp/src/qmf/AgentEngine.cpp
index 6d59ae2750..d3204042d5 100644
--- a/qpid/cpp/src/qmf/Agent.cpp
+++ b/qpid/cpp/src/qmf/AgentEngine.cpp
@@ -17,7 +17,7 @@
* under the License.
*/
-#include "qmf/Agent.h"
+#include "qmf/AgentEngine.h"
#include "qmf/MessageImpl.h"
#include "qmf/SchemaImpl.h"
#include "qmf/Typecode.h"
@@ -25,6 +25,7 @@
#include "qmf/ObjectIdImpl.h"
#include "qmf/QueryImpl.h"
#include "qmf/ValueImpl.h"
+#include "qmf/Protocol.h"
#include <qpid/framing/Buffer.h>
#include <qpid/framing/Uuid.h>
#include <qpid/framing/FieldTable.h>
@@ -77,17 +78,17 @@ namespace qmf {
AgentQueryContext() : schemaMethod(0) {}
};
- class AgentImpl {
+ class AgentEngineImpl {
public:
- AgentImpl(char* label, bool internalStore);
- ~AgentImpl();
+ AgentEngineImpl(char* label, bool internalStore);
+ ~AgentEngineImpl();
- void setStoreDir(char* path);
- void setTransferDir(char* path);
+ void setStoreDir(const char* path);
+ void setTransferDir(const char* path);
void handleRcvMessage(Message& message);
- bool getXmtMessage(Message& item);
+ bool getXmtMessage(Message& item) const;
void popXmt();
- bool getEvent(AgentEvent& event);
+ bool getEvent(AgentEvent& event) const;
void popEvent();
void newSession();
void startProtocol();
@@ -103,7 +104,7 @@ namespace qmf {
void raiseEvent(Event& event);
private:
- Mutex lock;
+ mutable Mutex lock;
Mutex addLock;
string label;
string queueName;
@@ -134,13 +135,13 @@ namespace qmf {
# define MA_BUFFER_SIZE 65536
char outputBuffer[MA_BUFFER_SIZE];
- struct SchemaClassKey {
+ struct AgentClassKey {
string name;
uint8_t hash[16];
- SchemaClassKey(const string& n, const uint8_t* h) : name(n) {
+ AgentClassKey(const string& n, const uint8_t* h) : name(n) {
memcpy(hash, h, 16);
}
- SchemaClassKey(Buffer& buffer) {
+ AgentClassKey(Buffer& buffer) {
buffer.getShortString(name);
buffer.getBin128(hash);
}
@@ -149,8 +150,8 @@ namespace qmf {
}
};
- struct SchemaClassKeyComp {
- bool operator() (const SchemaClassKey& lhs, const SchemaClassKey& rhs) const
+ struct AgentClassKeyComp {
+ bool operator() (const AgentClassKey& lhs, const AgentClassKey& rhs) const
{
if (lhs.name != rhs.name)
return lhs.name < rhs.name;
@@ -162,8 +163,8 @@ namespace qmf {
}
};
- typedef map<SchemaClassKey, SchemaObjectClassImpl*, SchemaClassKeyComp> ObjectClassMap;
- typedef map<SchemaClassKey, SchemaEventClassImpl*, SchemaClassKeyComp> EventClassMap;
+ typedef map<AgentClassKey, SchemaObjectClassImpl*, AgentClassKeyComp> ObjectClassMap;
+ typedef map<AgentClassKey, SchemaEventClassImpl*, AgentClassKeyComp> EventClassMap;
struct ClassMaps {
ObjectClassMap objectClasses;
@@ -172,8 +173,6 @@ namespace qmf {
map<string, ClassMaps> packages;
- bool checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq);
- void encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq = 0);
AgentEventImpl::Ptr eventDeclareQueue(const string& queueName);
AgentEventImpl::Ptr eventBind(const string& exchange, const string& queue, const string& key);
AgentEventImpl::Ptr eventSetupComplete();
@@ -185,7 +184,7 @@ namespace qmf {
void sendBufferLH(Buffer& buf, const string& destination, const string& routingKey);
void sendPackageIndicationLH(const string& packageName);
- void sendClassIndicationLH(ClassKind kind, const string& packageName, const SchemaClassKey& key);
+ void sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key);
void sendCommandCompleteLH(const string& exchange, const string& key, uint32_t seq,
uint32_t code = 0, const string& text = "OK");
void sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text="");
@@ -200,9 +199,9 @@ namespace qmf {
};
}
-const char* AgentImpl::QMF_EXCHANGE = "qpid.management";
-const char* AgentImpl::DIR_EXCHANGE = "amq.direct";
-const char* AgentImpl::BROKER_KEY = "broker";
+const char* AgentEngineImpl::QMF_EXCHANGE = "qpid.management";
+const char* AgentEngineImpl::DIR_EXCHANGE = "amq.direct";
+const char* AgentEngineImpl::BROKER_KEY = "broker";
#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
@@ -228,7 +227,7 @@ AgentEvent AgentEventImpl::copy()
return item;
}
-AgentImpl::AgentImpl(char* _label, bool i) :
+AgentEngineImpl::AgentEngineImpl(char* _label, bool i) :
label(_label), queueName("qmfa-"), internalStore(i), nextTransientId(1),
requestedBrokerBank(0), requestedAgentBank(0),
assignedBrokerBank(0), assignedAgentBank(0),
@@ -237,11 +236,11 @@ AgentImpl::AgentImpl(char* _label, bool i) :
queueName += label;
}
-AgentImpl::~AgentImpl()
+AgentEngineImpl::~AgentEngineImpl()
{
}
-void AgentImpl::setStoreDir(char* path)
+void AgentEngineImpl::setStoreDir(const char* path)
{
Mutex::ScopedLock _lock(lock);
if (path)
@@ -250,7 +249,7 @@ void AgentImpl::setStoreDir(char* path)
storeDir.clear();
}
-void AgentImpl::setTransferDir(char* path)
+void AgentEngineImpl::setTransferDir(const char* path)
{
Mutex::ScopedLock _lock(lock);
if (path)
@@ -259,7 +258,7 @@ void AgentImpl::setTransferDir(char* path)
transferDir.clear();
}
-void AgentImpl::handleRcvMessage(Message& message)
+void AgentEngineImpl::handleRcvMessage(Message& message)
{
Buffer inBuffer(message.body, message.length);
uint8_t opcode;
@@ -268,16 +267,20 @@ void AgentImpl::handleRcvMessage(Message& message)
string replyToKey(message.replyKey ? message.replyKey : "");
string userId(message.userId ? message.userId : "");
- if (checkHeader(inBuffer, &opcode, &sequence)) {
- if (opcode == 'a') handleAttachResponse(inBuffer);
- else if (opcode == 'S') handleSchemaRequest(inBuffer, sequence, replyToExchange, replyToKey);
- else if (opcode == 'x') handleConsoleAddedIndication();
- else if (opcode == 'G') handleGetQuery(inBuffer, sequence, replyToKey, userId);
- else if (opcode == 'M') handleMethodRequest(inBuffer, sequence, replyToKey, userId);
+ while (Protocol::checkHeader(inBuffer, &opcode, &sequence)) {
+ if (opcode == Protocol::OP_ATTACH_RESPONSE) handleAttachResponse(inBuffer);
+ else if (opcode == Protocol::OP_SCHEMA_REQUEST) handleSchemaRequest(inBuffer, sequence, replyToExchange, replyToKey);
+ else if (opcode == Protocol::OP_CONSOLE_ADDED_INDICATION) handleConsoleAddedIndication();
+ else if (opcode == Protocol::OP_GET_QUERY) handleGetQuery(inBuffer, sequence, replyToKey, userId);
+ else if (opcode == Protocol::OP_METHOD_REQUEST) handleMethodRequest(inBuffer, sequence, replyToKey, userId);
+ else {
+ QPID_LOG(error, "AgentEngineImpl::handleRcvMessage invalid opcode=" << opcode);
+ break;
+ }
}
}
-bool AgentImpl::getXmtMessage(Message& item)
+bool AgentEngineImpl::getXmtMessage(Message& item) const
{
Mutex::ScopedLock _lock(lock);
if (xmtQueue.empty())
@@ -286,14 +289,14 @@ bool AgentImpl::getXmtMessage(Message& item)
return true;
}
-void AgentImpl::popXmt()
+void AgentEngineImpl::popXmt()
{
Mutex::ScopedLock _lock(lock);
if (!xmtQueue.empty())
xmtQueue.pop_front();
}
-bool AgentImpl::getEvent(AgentEvent& event)
+bool AgentEngineImpl::getEvent(AgentEvent& event) const
{
Mutex::ScopedLock _lock(lock);
if (eventQueue.empty())
@@ -302,14 +305,14 @@ bool AgentImpl::getEvent(AgentEvent& event)
return true;
}
-void AgentImpl::popEvent()
+void AgentEngineImpl::popEvent()
{
Mutex::ScopedLock _lock(lock);
if (!eventQueue.empty())
eventQueue.pop_front();
}
-void AgentImpl::newSession()
+void AgentEngineImpl::newSession()
{
Mutex::ScopedLock _lock(lock);
eventQueue.clear();
@@ -319,13 +322,13 @@ void AgentImpl::newSession()
eventQueue.push_back(eventSetupComplete());
}
-void AgentImpl::startProtocol()
+void AgentEngineImpl::startProtocol()
{
Mutex::ScopedLock _lock(lock);
char rawbuffer[512];
Buffer buffer(rawbuffer, 512);
- encodeHeader(buffer, 'A');
+ Protocol::encodeHeader(buffer, Protocol::OP_ATTACH_REQUEST);
buffer.putShortString("qmfa");
systemId.encode(buffer);
buffer.putLong(requestedBrokerBank);
@@ -335,12 +338,12 @@ void AgentImpl::startProtocol()
" reqAgent=" << requestedAgentBank);
}
-void AgentImpl::heartbeat()
+void AgentEngineImpl::heartbeat()
{
Mutex::ScopedLock _lock(lock);
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'h');
+ Protocol::encodeHeader(buffer, Protocol::OP_HEARTBEAT_INDICATION);
buffer.putLongLong(uint64_t(Duration(now())));
stringstream key;
key << "console.heartbeat." << assignedBrokerBank << "." << assignedAgentBank;
@@ -348,8 +351,8 @@ void AgentImpl::heartbeat()
QPID_LOG(trace, "SENT HeartbeatIndication");
}
-void AgentImpl::methodResponse(uint32_t sequence, uint32_t status, char* text,
- const Value& argMap)
+void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* text,
+ const Value& argMap)
{
Mutex::ScopedLock _lock(lock);
map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence);
@@ -359,7 +362,7 @@ void AgentImpl::methodResponse(uint32_t sequence, uint32_t status, char* text,
contextMap.erase(iter);
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'm', context->sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, context->sequence);
buffer.putLong(status);
buffer.putMediumString(text);
if (status == 0) {
@@ -381,7 +384,7 @@ void AgentImpl::methodResponse(uint32_t sequence, uint32_t status, char* text,
QPID_LOG(trace, "SENT MethodResponse");
}
-void AgentImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat)
+void AgentEngineImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat)
{
Mutex::ScopedLock _lock(lock);
map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence);
@@ -390,7 +393,7 @@ void AgentImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool
AgentQueryContext::Ptr context = iter->second;
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'g', context->sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_OBJECT_INDICATION, context->sequence);
object.impl->encodeSchemaKey(buffer);
object.impl->encodeManagedObjectData(buffer);
@@ -403,7 +406,7 @@ void AgentImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool
QPID_LOG(trace, "SENT ContentIndication");
}
-void AgentImpl::queryComplete(uint32_t sequence)
+void AgentEngineImpl::queryComplete(uint32_t sequence)
{
Mutex::ScopedLock _lock(lock);
map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence);
@@ -415,7 +418,7 @@ void AgentImpl::queryComplete(uint32_t sequence)
sendCommandCompleteLH(context->exchange, context->key, context->sequence, 0, "OK");
}
-void AgentImpl::registerClass(SchemaObjectClass* cls)
+void AgentEngineImpl::registerClass(SchemaObjectClass* cls)
{
Mutex::ScopedLock _lock(lock);
SchemaObjectClassImpl* impl = cls->impl;
@@ -423,17 +426,17 @@ void AgentImpl::registerClass(SchemaObjectClass* cls)
map<string, ClassMaps>::iterator iter = packages.find(impl->package);
if (iter == packages.end()) {
packages[impl->package] = ClassMaps();
- iter = packages.find(impl->package);
+ iter = packages.find(impl->getClassKey()->getPackageName());
// TODO: Indicate this package if connected
}
- SchemaClassKey key(impl->name, impl->getHash());
+ AgentClassKey key(impl->getClassKey()->getClassName(), impl->getClassKey()->getHash());
iter->second.objectClasses[key] = impl;
// TODO: Indicate this schema if connected.
}
-void AgentImpl::registerClass(SchemaEventClass* cls)
+void AgentEngineImpl::registerClass(SchemaEventClass* cls)
{
Mutex::ScopedLock _lock(lock);
SchemaEventClassImpl* impl = cls->impl;
@@ -441,23 +444,23 @@ void AgentImpl::registerClass(SchemaEventClass* cls)
map<string, ClassMaps>::iterator iter = packages.find(impl->package);
if (iter == packages.end()) {
packages[impl->package] = ClassMaps();
- iter = packages.find(impl->package);
+ iter = packages.find(impl->getClassKey()->getPackageName());
// TODO: Indicate this package if connected
}
- SchemaClassKey key(impl->name, impl->getHash());
+ AgentClassKey key(impl->getClassKey()->getClassName(), impl->getClassKey()->getHash());
iter->second.eventClasses[key] = impl;
// TODO: Indicate this schema if connected.
}
-const ObjectId* AgentImpl::addObject(Object&, uint64_t)
+const ObjectId* AgentEngineImpl::addObject(Object&, uint64_t)
{
Mutex::ScopedLock _lock(lock);
return 0;
}
-const ObjectId* AgentImpl::allocObjectId(uint64_t persistId)
+const ObjectId* AgentEngineImpl::allocObjectId(uint64_t persistId)
{
Mutex::ScopedLock _lock(lock);
uint16_t sequence = persistId ? 0 : bootSequence;
@@ -467,41 +470,17 @@ const ObjectId* AgentImpl::allocObjectId(uint64_t persistId)
return oid->envelope;
}
-const ObjectId* AgentImpl::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi)
+const ObjectId* AgentEngineImpl::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi)
{
return allocObjectId(((uint64_t) persistIdHi) << 32 | (uint64_t) persistIdLo);
}
-void AgentImpl::raiseEvent(Event&)
+void AgentEngineImpl::raiseEvent(Event&)
{
Mutex::ScopedLock _lock(lock);
}
-void AgentImpl::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq)
-{
- buf.putOctet('A');
- buf.putOctet('M');
- buf.putOctet('3');
- buf.putOctet(opcode);
- buf.putLong (seq);
-}
-
-bool AgentImpl::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq)
-{
- if (buf.getSize() < 8)
- return false;
-
- uint8_t h1 = buf.getOctet();
- uint8_t h2 = buf.getOctet();
- uint8_t h3 = buf.getOctet();
-
- *opcode = buf.getOctet();
- *seq = buf.getLong();
-
- return h1 == 'A' && h2 == 'M' && h3 == '3';
-}
-
-AgentEventImpl::Ptr AgentImpl::eventDeclareQueue(const string& name)
+AgentEventImpl::Ptr AgentEngineImpl::eventDeclareQueue(const string& name)
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::DECLARE_QUEUE));
event->name = name;
@@ -509,8 +488,8 @@ AgentEventImpl::Ptr AgentImpl::eventDeclareQueue(const string& name)
return event;
}
-AgentEventImpl::Ptr AgentImpl::eventBind(const string& exchange, const string& queue,
- const string& key)
+AgentEventImpl::Ptr AgentEngineImpl::eventBind(const string& exchange, const string& queue,
+ const string& key)
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::BIND));
event->name = queue;
@@ -520,14 +499,14 @@ AgentEventImpl::Ptr AgentImpl::eventBind(const string& exchange, const string& q
return event;
}
-AgentEventImpl::Ptr AgentImpl::eventSetupComplete()
+AgentEventImpl::Ptr AgentEngineImpl::eventSetupComplete()
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::SETUP_COMPLETE));
return event;
}
-AgentEventImpl::Ptr AgentImpl::eventQuery(uint32_t num, const string& userId, const string& package,
- const string& cls, boost::shared_ptr<ObjectId> oid)
+AgentEventImpl::Ptr AgentEngineImpl::eventQuery(uint32_t num, const string& userId, const string& package,
+ const string& cls, boost::shared_ptr<ObjectId> oid)
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::GET_QUERY));
event->sequence = num;
@@ -538,9 +517,9 @@ AgentEventImpl::Ptr AgentImpl::eventQuery(uint32_t num, const string& userId, co
return event;
}
-AgentEventImpl::Ptr AgentImpl::eventMethod(uint32_t num, const string& userId, const string& method,
- boost::shared_ptr<ObjectId> oid, boost::shared_ptr<Value> argMap,
- SchemaObjectClass* objectClass)
+AgentEventImpl::Ptr AgentEngineImpl::eventMethod(uint32_t num, const string& userId, const string& method,
+ boost::shared_ptr<ObjectId> oid, boost::shared_ptr<Value> argMap,
+ SchemaObjectClass* objectClass)
{
AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::METHOD_CALL));
event->sequence = num;
@@ -552,7 +531,7 @@ AgentEventImpl::Ptr AgentImpl::eventMethod(uint32_t num, const string& userId, c
return event;
}
-void AgentImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
+void AgentEngineImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
{
uint32_t length = buf.getPosition();
MessageImpl::Ptr message(new MessageImpl);
@@ -567,19 +546,19 @@ void AgentImpl::sendBufferLH(Buffer& buf, const string& destination, const strin
xmtQueue.push_back(message);
}
-void AgentImpl::sendPackageIndicationLH(const string& packageName)
+void AgentEngineImpl::sendPackageIndicationLH(const string& packageName)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'p');
+ Protocol::encodeHeader(buffer, Protocol::OP_PACKAGE_INDICATION);
buffer.putShortString(packageName);
sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
QPID_LOG(trace, "SENT PackageIndication: package_name=" << packageName);
}
-void AgentImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const SchemaClassKey& key)
+void AgentEngineImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'q');
+ Protocol::encodeHeader(buffer, Protocol::OP_CLASS_INDICATION);
buffer.putOctet((int) kind);
buffer.putShortString(packageName);
buffer.putShortString(key.name);
@@ -588,21 +567,21 @@ void AgentImpl::sendClassIndicationLH(ClassKind kind, const string& packageName,
QPID_LOG(trace, "SENT ClassIndication: package_name=" << packageName << " class_name=" << key.name);
}
-void AgentImpl::sendCommandCompleteLH(const string& exchange, const string& replyToKey,
- uint32_t sequence, uint32_t code, const string& text)
+void AgentEngineImpl::sendCommandCompleteLH(const string& exchange, const string& replyToKey,
+ uint32_t sequence, uint32_t code, const string& text)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'z', sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_COMMAND_COMPLETE, sequence);
buffer.putLong(code);
buffer.putShortString(text);
sendBufferLH(buffer, exchange, replyToKey);
QPID_LOG(trace, "SENT CommandComplete: seq=" << sequence << " code=" << code << " text=" << text);
}
-void AgentImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text)
+void AgentEngineImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text)
{
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 'm', sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, sequence);
buffer.putLong(code);
string fulltext;
@@ -625,7 +604,7 @@ void AgentImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t
QPID_LOG(trace, "SENT MethodResponse: errorCode=" << code << " text=" << fulltext);
}
-void AgentImpl::handleAttachResponse(Buffer& inBuffer)
+void AgentEngineImpl::handleAttachResponse(Buffer& inBuffer)
{
Mutex::ScopedLock _lock(lock);
@@ -672,25 +651,25 @@ void AgentImpl::handleAttachResponse(Buffer& inBuffer)
}
}
-void AgentImpl::handlePackageRequest(Buffer&)
+void AgentEngineImpl::handlePackageRequest(Buffer&)
{
Mutex::ScopedLock _lock(lock);
}
-void AgentImpl::handleClassQuery(Buffer&)
+void AgentEngineImpl::handleClassQuery(Buffer&)
{
Mutex::ScopedLock _lock(lock);
}
-void AgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
- const string& replyExchange, const string& replyKey)
+void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
+ const string& replyExchange, const string& replyKey)
{
Mutex::ScopedLock _lock(lock);
string rExchange(replyExchange);
string rKey(replyKey);
string packageName;
inBuffer.getShortString(packageName);
- SchemaClassKey key(inBuffer);
+ AgentClassKey key(inBuffer);
if (rExchange.empty())
rExchange = QMF_EXCHANGE;
@@ -710,7 +689,7 @@ void AgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
if (ocIter != cMap.objectClasses.end()) {
SchemaObjectClassImpl* oImpl = ocIter->second;
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 's', sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence);
oImpl->encode(buffer);
sendBufferLH(buffer, rExchange, rKey);
QPID_LOG(trace, "SENT SchemaResponse: (object) package=" << packageName << " class=" << key.name);
@@ -721,7 +700,7 @@ void AgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
if (ecIter != cMap.eventClasses.end()) {
SchemaEventClassImpl* eImpl = ecIter->second;
Buffer buffer(outputBuffer, MA_BUFFER_SIZE);
- encodeHeader(buffer, 's', sequence);
+ Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence);
eImpl->encode(buffer);
sendBufferLH(buffer, rExchange, rKey);
QPID_LOG(trace, "SENT SchemaResponse: (event) package=" << packageName << " class=" << key.name);
@@ -731,7 +710,7 @@ void AgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence,
sendCommandCompleteLH(rExchange, rKey, sequence, 1, "class not found");
}
-void AgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId)
+void AgentEngineImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId)
{
Mutex::ScopedLock _lock(lock);
FieldTable ft;
@@ -783,7 +762,7 @@ void AgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string
eventQueue.push_back(eventQuery(contextNum, userId, pname, cname, oid));
}
-void AgentImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const string& replyTo, const string& userId)
+void AgentEngineImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const string& replyTo, const string& userId)
{
Mutex::ScopedLock _lock(lock);
string pname;
@@ -791,7 +770,7 @@ void AgentImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const str
ObjectIdImpl* oidImpl = new ObjectIdImpl(buffer);
boost::shared_ptr<ObjectId> oid(oidImpl->envelope);
buffer.getShortString(pname);
- SchemaClassKey classKey(buffer);
+ AgentClassKey classKey(buffer);
buffer.getShortString(method);
map<string, ClassMaps>::const_iterator pIter = packages.find(pname);
@@ -842,7 +821,7 @@ void AgentImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const str
eventQueue.push_back(eventMethod(contextNum, userId, method, oid, argMap, schema->envelope));
}
-void AgentImpl::handleConsoleAddedIndication()
+void AgentEngineImpl::handleConsoleAddedIndication()
{
Mutex::ScopedLock _lock(lock);
}
@@ -851,108 +830,25 @@ void AgentImpl::handleConsoleAddedIndication()
// Wrappers
//==================================================================
-Agent::Agent(char* label, bool internalStore)
-{
- impl = new AgentImpl(label, internalStore);
-}
-
-Agent::~Agent()
-{
- delete impl;
-}
-
-void Agent::setStoreDir(char* path)
-{
- impl->setStoreDir(path);
-}
-
-void Agent::setTransferDir(char* path)
-{
- impl->setTransferDir(path);
-}
-
-void Agent::handleRcvMessage(Message& message)
-{
- impl->handleRcvMessage(message);
-}
-
-bool Agent::getXmtMessage(Message& item)
-{
- return impl->getXmtMessage(item);
-}
-
-void Agent::popXmt()
-{
- impl->popXmt();
-}
-
-bool Agent::getEvent(AgentEvent& event)
-{
- return impl->getEvent(event);
-}
-
-void Agent::popEvent()
-{
- impl->popEvent();
-}
-
-void Agent::newSession()
-{
- impl->newSession();
-}
-
-void Agent::startProtocol()
-{
- impl->startProtocol();
-}
-
-void Agent::heartbeat()
-{
- impl->heartbeat();
-}
-
-void Agent::methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments)
-{
- impl->methodResponse(sequence, status, text, arguments);
-}
-
-void Agent::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat)
-{
- impl->queryResponse(sequence, object, prop, stat);
-}
-
-void Agent::queryComplete(uint32_t sequence)
-{
- impl->queryComplete(sequence);
-}
-
-void Agent::registerClass(SchemaObjectClass* cls)
-{
- impl->registerClass(cls);
-}
-
-void Agent::registerClass(SchemaEventClass* cls)
-{
- impl->registerClass(cls);
-}
-
-const ObjectId* Agent::addObject(Object& obj, uint64_t persistId)
-{
- return impl->addObject(obj, persistId);
-}
-
-const ObjectId* Agent::allocObjectId(uint64_t persistId)
-{
- return impl->allocObjectId(persistId);
-}
-
-const ObjectId* Agent::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi)
-{
- return impl->allocObjectId(persistIdLo, persistIdHi);
-}
-
-void Agent::raiseEvent(Event& event)
-{
- impl->raiseEvent(event);
-}
+AgentEngine::AgentEngine(char* label, bool internalStore) { impl = new AgentEngineImpl(label, internalStore); }
+AgentEngine::~AgentEngine() { delete impl; }
+void AgentEngine::setStoreDir(const char* path) { impl->setStoreDir(path); }
+void AgentEngine::setTransferDir(const char* path) { impl->setTransferDir(path); }
+void AgentEngine::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
+bool AgentEngine::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
+void AgentEngine::popXmt() { impl->popXmt(); }
+bool AgentEngine::getEvent(AgentEvent& event) const { return impl->getEvent(event); }
+void AgentEngine::popEvent() { impl->popEvent(); }
+void AgentEngine::newSession() { impl->newSession(); }
+void AgentEngine::startProtocol() { impl->startProtocol(); }
+void AgentEngine::heartbeat() { impl->heartbeat(); }
+void AgentEngine::methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments) { impl->methodResponse(sequence, status, text, arguments); }
+void AgentEngine::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat) { impl->queryResponse(sequence, object, prop, stat); }
+void AgentEngine::queryComplete(uint32_t sequence) { impl->queryComplete(sequence); }
+void AgentEngine::registerClass(SchemaObjectClass* cls) { impl->registerClass(cls); }
+void AgentEngine::registerClass(SchemaEventClass* cls) { impl->registerClass(cls); }
+const ObjectId* AgentEngine::addObject(Object& obj, uint64_t persistId) { return impl->addObject(obj, persistId); }
+const ObjectId* AgentEngine::allocObjectId(uint64_t persistId) { return impl->allocObjectId(persistId); }
+const ObjectId* AgentEngine::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi) { return impl->allocObjectId(persistIdLo, persistIdHi); }
+void AgentEngine::raiseEvent(Event& event) { impl->raiseEvent(event); }
diff --git a/qpid/cpp/src/qmf/Agent.h b/qpid/cpp/src/qmf/AgentEngine.h
index d8f784e9d8..c88ef33657 100644
--- a/qpid/cpp/src/qmf/Agent.h
+++ b/qpid/cpp/src/qmf/AgentEngine.h
@@ -1,5 +1,5 @@
-#ifndef _QmfAgent_
-#define _QmfAgent_
+#ifndef _QmfAgentEngine_
+#define _QmfAgentEngine_
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -64,15 +64,15 @@ namespace qmf {
SchemaObjectClass* objectClass; // (METHOD_CALL)
};
- class AgentImpl;
+ class AgentEngineImpl;
/**
- * Agent - Protocol engine for the QMF agent
+ * AgentEngine - Protocol engine for the QMF agent
*/
- class Agent {
+ class AgentEngine {
public:
- Agent(char* label, bool internalStore=true);
- ~Agent();
+ AgentEngine(char* label, bool internalStore=true);
+ ~AgentEngine();
/**
* Configure the directory path for storing persistent data.
@@ -80,7 +80,7 @@ namespace qmf {
* created, written, and read. If NULL, no persistent storage will be
* attempted.
*/
- void setStoreDir(char* path);
+ void setStoreDir(const char* path);
/**
* Configure the directory path for files transferred over QMF.
@@ -88,7 +88,7 @@ namespace qmf {
* created, deleted, written, and read. If NULL, file transfers shall not
* be permitted.
*/
- void setTransferDir(char* path);
+ void setTransferDir(const char* path);
/**
* Pass messages received from the AMQP session to the Agent engine.
@@ -101,7 +101,7 @@ namespace qmf {
*@param item The Message structure describing the message to be produced.
*@return true if the Message is valid, false if there are no messages to send.
*/
- bool getXmtMessage(Message& item);
+ bool getXmtMessage(Message& item) const;
/**
* Remove and discard one message from the head of the transmit queue.
@@ -113,7 +113,7 @@ namespace qmf {
*@param event The event iff the return value is true
*@return true if event is valid, false if there are no events to process
*/
- bool getEvent(AgentEvent& event);
+ bool getEvent(AgentEvent& event) const;
/**
* Remove and discard one event from the head of the event queue.
@@ -182,11 +182,12 @@ namespace qmf {
*@return The objectId of the managed object.
*/
const ObjectId* addObject(Object& obj, uint64_t persistId);
+ // const ObjectId* addObject(Object& obj, uint32_t persistIdLo, uint32_t persistIdHi);
/**
- * Allocate an objecc-id for an object that will be managed by the application.
+ * Allocate an object-id for an object that will be managed by the application.
*@param persistId A unique non-zero value if the object-id is to be persistent.
- @return The objectId structure for the allocated ID.
+ *@return The objectId structure for the allocated ID.
*/
const ObjectId* allocObjectId(uint64_t persistId);
const ObjectId* allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi);
@@ -198,7 +199,7 @@ namespace qmf {
void raiseEvent(Event& event);
private:
- AgentImpl* impl;
+ AgentEngineImpl* impl;
};
}
diff --git a/qpid/cpp/src/qmf/ConnectionSettingsImpl.cpp b/qpid/cpp/src/qmf/ConnectionSettingsImpl.cpp
new file mode 100644
index 0000000000..034ab18395
--- /dev/null
+++ b/qpid/cpp/src/qmf/ConnectionSettingsImpl.cpp
@@ -0,0 +1,323 @@
+/*
+ * 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 "qmf/ConnectionSettingsImpl.h"
+#include "qmf/Typecode.h"
+
+using namespace std;
+using namespace qmf;
+using namespace qpid;
+
+const string attrProtocol("protocol");
+const string attrHost("host");
+const string attrPort("port");
+const string attrVirtualhost("virtualhost");
+const string attrUsername("username");
+const string attrPassword("password");
+const string attrMechanism("mechanism");
+const string attrLocale("locale");
+const string attrHeartbeat("heartbeat");
+const string attrMaxChannels("maxChannels");
+const string attrMaxFrameSize("maxFrameSize");
+const string attrBounds("bounds");
+const string attrTcpNoDelay("tcpNoDelay");
+const string attrService("service");
+const string attrMinSsf("minSsf");
+const string attrMaxSsf("maxSsf");
+const string attrRetryDelayMin("retryDelayMin");
+const string attrRetryDelayMax("retryDelayMax");
+const string attrRetryDelayFactor("retryDelayFactor");
+
+ConnectionSettingsImpl::ConnectionSettingsImpl(ConnectionSettings* e) :
+ envelope(e), retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2)
+{
+}
+
+ConnectionSettingsImpl::ConnectionSettingsImpl(ConnectionSettings* e, const string& /*url*/) :
+ envelope(e), retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2)
+{
+ // TODO: Parse the URL
+}
+
+void ConnectionSettingsImpl::setAttr(const string& key, const Value& value)
+{
+ if (key == attrProtocol) clientSettings.protocol = value.asString();
+ else if (key == attrHost) clientSettings.host = value.asString();
+ else if (key == attrPort) clientSettings.port = value.asUint();
+ else if (key == attrVirtualhost) clientSettings.virtualhost = value.asString();
+ else if (key == attrUsername) clientSettings.username = value.asString();
+ else if (key == attrPassword) clientSettings.password = value.asString();
+ else if (key == attrMechanism) clientSettings.mechanism = value.asString();
+ else if (key == attrLocale) clientSettings.locale = value.asString();
+ else if (key == attrHeartbeat) clientSettings.heartbeat = value.asUint();
+ else if (key == attrMaxChannels) clientSettings.maxChannels = value.asUint();
+ else if (key == attrMaxFrameSize) clientSettings.maxFrameSize = value.asUint();
+ else if (key == attrBounds) clientSettings.bounds = value.asUint();
+ else if (key == attrTcpNoDelay) clientSettings.tcpNoDelay = value.asBool();
+ else if (key == attrService) clientSettings.service = value.asString();
+ else if (key == attrMinSsf) clientSettings.minSsf = value.asUint();
+ else if (key == attrMaxSsf) clientSettings.maxSsf = value.asUint();
+
+ else if (key == attrRetryDelayMin) retryDelayMin = value.asUint();
+ else if (key == attrRetryDelayMax) retryDelayMax = value.asUint();
+ else if (key == attrRetryDelayFactor) retryDelayFactor = value.asUint();
+}
+
+Value ConnectionSettingsImpl::getAttr(const string& key) const
+{
+ Value strval(TYPE_LSTR);
+ Value intval(TYPE_UINT32);
+ Value boolval(TYPE_BOOL);
+
+ if (key == attrProtocol) {
+ strval.setString(clientSettings.protocol.c_str());
+ return strval;
+ }
+
+ if (key == attrHost) {
+ strval.setString(clientSettings.host.c_str());
+ return strval;
+ }
+
+ if (key == attrPort) {
+ intval.setUint(clientSettings.port);
+ return intval;
+ }
+
+ if (key == attrVirtualhost) {
+ strval.setString(clientSettings.virtualhost.c_str());
+ return strval;
+ }
+
+ if (key == attrUsername) {
+ strval.setString(clientSettings.username.c_str());
+ return strval;
+ }
+
+ if (key == attrPassword) {
+ strval.setString(clientSettings.password.c_str());
+ return strval;
+ }
+
+ if (key == attrMechanism) {
+ strval.setString(clientSettings.mechanism.c_str());
+ return strval;
+ }
+
+ if (key == attrLocale) {
+ strval.setString(clientSettings.locale.c_str());
+ return strval;
+ }
+
+ if (key == attrHeartbeat) {
+ intval.setUint(clientSettings.heartbeat);
+ return intval;
+ }
+
+ if (key == attrMaxChannels) {
+ intval.setUint(clientSettings.maxChannels);
+ return intval;
+ }
+
+ if (key == attrMaxFrameSize) {
+ intval.setUint(clientSettings.maxFrameSize);
+ return intval;
+ }
+
+ if (key == attrBounds) {
+ intval.setUint(clientSettings.bounds);
+ return intval;
+ }
+
+ if (key == attrTcpNoDelay) {
+ boolval.setBool(clientSettings.tcpNoDelay);
+ return boolval;
+ }
+
+ if (key == attrService) {
+ strval.setString(clientSettings.service.c_str());
+ return strval;
+ }
+
+ if (key == attrMinSsf) {
+ intval.setUint(clientSettings.minSsf);
+ return intval;
+ }
+
+ if (key == attrMaxSsf) {
+ intval.setUint(clientSettings.maxSsf);
+ return intval;
+ }
+
+ if (key == attrRetryDelayMin) {
+ intval.setUint(retryDelayMin);
+ return intval;
+ }
+
+ if (key == attrRetryDelayMax) {
+ intval.setUint(retryDelayMax);
+ return intval;
+ }
+
+ if (key == attrRetryDelayFactor) {
+ intval.setUint(retryDelayFactor);
+ return intval;
+ }
+
+ return strval;
+}
+
+const string& ConnectionSettingsImpl::getAttrString() const
+{
+ // TODO: build and return attribute string
+ return attrString;
+}
+
+void ConnectionSettingsImpl::transportTcp(uint16_t port)
+{
+ clientSettings.protocol = "tcp";
+ clientSettings.port = port;
+}
+
+void ConnectionSettingsImpl::transportSsl(uint16_t port)
+{
+ clientSettings.protocol = "ssl";
+ clientSettings.port = port;
+}
+
+void ConnectionSettingsImpl::transportRdma(uint16_t port)
+{
+ clientSettings.protocol = "rdma";
+ clientSettings.port = port;
+}
+
+void ConnectionSettingsImpl::authAnonymous(const string& username)
+{
+ clientSettings.mechanism = "ANONYMOUS";
+ clientSettings.username = username;
+}
+
+void ConnectionSettingsImpl::authPlain(const string& username, const string& password)
+{
+ clientSettings.mechanism = "PLAIN";
+ clientSettings.username = username;
+ clientSettings.password = password;
+}
+
+void ConnectionSettingsImpl::authGssapi(const string& serviceName, uint32_t minSsf, uint32_t maxSsf)
+{
+ clientSettings.mechanism = "GSSAPI";
+ clientSettings.service = serviceName;
+ clientSettings.minSsf = minSsf;
+ clientSettings.maxSsf = maxSsf;
+}
+
+void ConnectionSettingsImpl::setRetry(int delayMin, int delayMax, int delayFactor)
+{
+ retryDelayMin = delayMin;
+ retryDelayMax = delayMax;
+ retryDelayFactor = delayFactor;
+}
+
+const client::ConnectionSettings& ConnectionSettingsImpl::getClientSettings() const
+{
+ return clientSettings;
+}
+
+void ConnectionSettingsImpl::getRetrySettings(int* min, int* max, int* factor) const
+{
+ *min = retryDelayMin;
+ *max = retryDelayMax;
+ *factor = retryDelayFactor;
+}
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+ConnectionSettings::ConnectionSettings(const ConnectionSettings& from)
+{
+ impl = new ConnectionSettingsImpl(*from.impl);
+}
+
+ConnectionSettings::ConnectionSettings()
+{
+ impl = new ConnectionSettingsImpl(this);
+}
+
+ConnectionSettings::ConnectionSettings(const char* url)
+{
+ impl = new ConnectionSettingsImpl(this, url);
+}
+
+ConnectionSettings::~ConnectionSettings()
+{
+ delete impl;
+}
+
+void ConnectionSettings::setAttr(const char* key, const Value& value)
+{
+ impl->setAttr(key, value);
+}
+
+Value ConnectionSettings::getAttr(const char* key) const
+{
+ return impl->getAttr(key);
+}
+
+const char* ConnectionSettings::getAttrString() const
+{
+ return impl->getAttrString().c_str();
+}
+
+void ConnectionSettings::transportTcp(uint16_t port)
+{
+ impl->transportTcp(port);
+}
+
+void ConnectionSettings::transportSsl(uint16_t port)
+{
+ impl->transportSsl(port);
+}
+
+void ConnectionSettings::transportRdma(uint16_t port)
+{
+ impl->transportRdma(port);
+}
+
+void ConnectionSettings::authAnonymous(const char* username)
+{
+ impl->authAnonymous(username);
+}
+
+void ConnectionSettings::authPlain(const char* username, const char* password)
+{
+ impl->authPlain(username, password);
+}
+
+void ConnectionSettings::authGssapi(const char* serviceName, uint32_t minSsf, uint32_t maxSsf)
+{
+ impl->authGssapi(serviceName, minSsf, maxSsf);
+}
+
+void ConnectionSettings::setRetry(int delayMin, int delayMax, int delayFactor)
+{
+ impl->setRetry(delayMin, delayMax, delayFactor);
+}
+
diff --git a/qpid/cpp/src/qmf/ConnectionSettingsImpl.h b/qpid/cpp/src/qmf/ConnectionSettingsImpl.h
new file mode 100644
index 0000000000..a177233cf3
--- /dev/null
+++ b/qpid/cpp/src/qmf/ConnectionSettingsImpl.h
@@ -0,0 +1,60 @@
+#ifndef _QmfConnectionSettingsImpl_
+#define _QmfConnectionSettingsImpl_
+
+/*
+ * 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 "qmf/ConnectionSettings.h"
+#include "qmf/Value.h"
+#include "qpid/client/ConnectionSettings.h"
+#include <string>
+#include <map>
+
+namespace qmf {
+
+ class ConnectionSettingsImpl {
+ ConnectionSettings* envelope;
+ qpid::client::ConnectionSettings clientSettings;
+ mutable std::string attrString;
+ int retryDelayMin;
+ int retryDelayMax;
+ int retryDelayFactor;
+
+ public:
+ ConnectionSettingsImpl(ConnectionSettings* e);
+ ConnectionSettingsImpl(ConnectionSettings* e, const std::string& url);
+ ~ConnectionSettingsImpl() {}
+ void setAttr(const std::string& key, const Value& value);
+ Value getAttr(const std::string& key) const;
+ const std::string& getAttrString() const;
+ void transportTcp(uint16_t port);
+ void transportSsl(uint16_t port);
+ void transportRdma(uint16_t port);
+ void authAnonymous(const std::string& username);
+ void authPlain(const std::string& username, const std::string& password);
+ void authGssapi(const std::string& serviceName, uint32_t minSsf, uint32_t maxSsf);
+ void setRetry(int delayMin, int delayMax, int delayFactor);
+
+ const qpid::client::ConnectionSettings& getClientSettings() const;
+ void getRetrySettings(int* delayMin, int* delayMax, int* delayFactor) const;
+ };
+
+}
+
+#endif
diff --git a/qpid/cpp/src/qmf/Console.h b/qpid/cpp/src/qmf/Console.h
deleted file mode 100644
index de7949e1de..0000000000
--- a/qpid/cpp/src/qmf/Console.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef _QmfConsole_
-#define _QmfConsole_
-
-/*
- * 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 <qmf/ManagedConnection.h>
-#include <qmf/Agent.h>
-#include <qmf/Broker.h>
-#include <qmf/Package.h>
-#include <qmf/SchemaClassTable.h>
-#include <qmf/Object.h>
-#include <qmf/ConsoleHandler.h>
-#include <set>
-#include <vector>
-#include <string>
-
-namespace qmf {
-
- struct ConsoleSettings {
- bool rcvObjects;
- bool rcvEvents;
- bool rcvHeartbeats;
- bool userBindings;
- uint32_t methodTimeout;
- uint32_t getTimeout;
-
- ConsoleSettings() :
- rcvObjects(true),
- rcvEvents(true),
- rcvHeartbeats(true),
- userBindings(false),
- methodTimeout(20),
- getTimeout(20) {}
- };
-
- class Console {
- public:
- Console(ConsoleHandler* handler = 0, ConsoleSettings settings = ConsoleSettings());
- ~Console();
-
- Broker* addConnection(ManagedConnection& connection);
- void delConnection(Broker* broker);
- void delConnection(ManagedConnection& connection);
-
- const PackageMap& getPackages() const;
-
- void bindPackage(const Package& package);
- void bindPackage(const std::string& packageName);
- void bindClass(const SchemaClass& otype);
- void bindClass(const std::string& packageName, const std::string& className);
-
- void getAgents(std::set<Agent>& agents, Broker* = 0);
- void getObjects(std::vector<Object>& objects, const std::string& typeName,
- const std::string& packageName = "",
- Broker* broker = 0,
- Agent* agent = 0);
- void getObjects(std::vector<Object>& objects,
- const std::map<std::string, std::string>& query,
- Broker* broker = 0,
- Agent* agent = 0);
- };
-}
-
-#endif
-
diff --git a/qpid/cpp/src/qmf/ConsoleEngine.cpp b/qpid/cpp/src/qmf/ConsoleEngine.cpp
new file mode 100644
index 0000000000..3d1b378b68
--- /dev/null
+++ b/qpid/cpp/src/qmf/ConsoleEngine.cpp
@@ -0,0 +1,886 @@
+/*
+ * 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 "qmf/ConsoleEngine.h"
+#include "qmf/MessageImpl.h"
+#include "qmf/SchemaImpl.h"
+#include "qmf/Typecode.h"
+#include "qmf/ObjectImpl.h"
+#include "qmf/ObjectIdImpl.h"
+#include "qmf/QueryImpl.h"
+#include "qmf/ValueImpl.h"
+#include "qmf/Protocol.h"
+#include "qmf/SequenceManager.h"
+#include <qpid/framing/Buffer.h>
+#include <qpid/framing/Uuid.h>
+#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/FieldValue.h>
+#include <qpid/sys/Mutex.h>
+#include <qpid/log/Statement.h>
+#include <qpid/sys/Time.h>
+#include <string.h>
+#include <string>
+#include <deque>
+#include <map>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <boost/shared_ptr.hpp>
+
+using namespace std;
+using namespace qmf;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+namespace qmf {
+
+ struct MethodResponseImpl {
+ typedef boost::shared_ptr<MethodResponseImpl> Ptr;
+ MethodResponse* envelope;
+ uint32_t status;
+ auto_ptr<Value> exception;
+ auto_ptr<Value> arguments;
+
+ MethodResponseImpl(Buffer& buf);
+ ~MethodResponseImpl() {}
+ uint32_t getStatus() const { return status; }
+ const Value* getException() const { return exception.get(); }
+ const Value* getArgs() const { return arguments.get(); }
+ };
+
+ struct ConsoleEventImpl {
+ typedef boost::shared_ptr<ConsoleEventImpl> Ptr;
+ ConsoleEvent::EventKind kind;
+ boost::shared_ptr<AgentProxyImpl> agent;
+ string name;
+ boost::shared_ptr<SchemaClassKey> classKey;
+ Object* object;
+ void* context;
+ Event* event;
+ uint64_t timestamp;
+ uint32_t methodHandle;
+ MethodResponseImpl::Ptr methodResponse;
+
+ ConsoleEventImpl(ConsoleEvent::EventKind k) :
+ kind(k), object(0), context(0), event(0), timestamp(0), methodHandle(0) {}
+ ~ConsoleEventImpl() {}
+ ConsoleEvent copy();
+ };
+
+ struct BrokerEventImpl {
+ typedef boost::shared_ptr<BrokerEventImpl> Ptr;
+ BrokerEvent::EventKind kind;
+ string name;
+ string exchange;
+ string bindingKey;
+
+ BrokerEventImpl(BrokerEvent::EventKind k) : kind(k) {}
+ ~BrokerEventImpl() {}
+ BrokerEvent copy();
+ };
+
+ class BrokerProxyImpl : public SequenceContext {
+ public:
+ typedef boost::shared_ptr<BrokerProxyImpl> Ptr;
+
+ BrokerProxyImpl(BrokerProxy* e, ConsoleEngine& _console);
+ ~BrokerProxyImpl() {}
+
+ void sessionOpened(SessionHandle& sh);
+ void sessionClosed();
+ void startProtocol();
+
+ void sendBufferLH(Buffer& buf, const string& destination, const string& routingKey);
+ void handleRcvMessage(Message& message);
+ bool getXmtMessage(Message& item) const;
+ void popXmt();
+
+ bool getEvent(BrokerEvent& event) const;
+ void popEvent();
+
+ // From SequenceContext
+ void complete();
+
+ void addBinding(const string& exchange, const string& key);
+
+ private:
+ mutable Mutex lock;
+ BrokerProxy* envelope;
+ ConsoleEngineImpl* console;
+ string queueName;
+ Uuid brokerId;
+ SequenceManager seqMgr;
+ uint32_t requestsOutstanding;
+ bool topicBound;
+ deque<MessageImpl::Ptr> xmtQueue;
+ deque<BrokerEventImpl::Ptr> eventQueue;
+
+# define MA_BUFFER_SIZE 65536
+ char outputBuffer[MA_BUFFER_SIZE];
+
+ BrokerEventImpl::Ptr eventDeclareQueue(const string& queueName);
+ BrokerEventImpl::Ptr eventBind(const string& exchange, const string& queue, const string& key);
+ BrokerEventImpl::Ptr eventSetupComplete();
+ BrokerEventImpl::Ptr eventStable();
+
+ void handleBrokerResponse(Buffer& inBuffer, uint32_t seq);
+ void handlePackageIndication(Buffer& inBuffer, uint32_t seq);
+ void handleCommandComplete(Buffer& inBuffer, uint32_t seq);
+ void handleClassIndication(Buffer& inBuffer, uint32_t seq);
+ void handleMethodResponse(Buffer& inBuffer, uint32_t seq);
+ void handleHeartbeatIndication(Buffer& inBuffer, uint32_t seq);
+ void handleEventIndication(Buffer& inBuffer, uint32_t seq);
+ void handleSchemaResponse(Buffer& inBuffer, uint32_t seq);
+ void handleObjectIndication(Buffer& inBuffer, uint32_t seq, bool prop, bool stat);
+ void incOutstandingLH();
+ void decOutstanding();
+ };
+
+ struct AgentProxyImpl {
+ typedef boost::shared_ptr<AgentProxyImpl> Ptr;
+ AgentProxy* envelope;
+ ConsoleEngineImpl* console;
+
+ AgentProxyImpl(AgentProxy* e, ConsoleEngine& _console) :
+ envelope(e), console(_console.impl) {}
+ ~AgentProxyImpl() {}
+ };
+
+ class ConsoleEngineImpl {
+ public:
+ ConsoleEngineImpl(ConsoleEngine* e, const ConsoleSettings& settings = ConsoleSettings());
+ ~ConsoleEngineImpl();
+
+ bool getEvent(ConsoleEvent& event) const;
+ void popEvent();
+
+ void addConnection(BrokerProxy& broker, void* context);
+ void delConnection(BrokerProxy& broker);
+
+ uint32_t packageCount() const;
+ const string& getPackageName(uint32_t idx) const;
+
+ uint32_t classCount(const char* packageName) const;
+ const SchemaClassKey* getClass(const char* packageName, uint32_t idx) const;
+
+ ClassKind getClassKind(const SchemaClassKey* key) const;
+ const SchemaObjectClass* getObjectClass(const SchemaClassKey* key) const;
+ const SchemaEventClass* getEventClass(const SchemaClassKey* key) const;
+
+ void bindPackage(const char* packageName);
+ void bindClass(const SchemaClassKey* key);
+ void bindClass(const char* packageName, const char* className);
+
+ uint32_t agentCount() const;
+ const AgentProxy* getAgent(uint32_t idx) const;
+
+ void sendQuery(const Query& query, void* context);
+
+ /*
+ void startSync(const Query& query, void* context, SyncQuery& sync);
+ void touchSync(SyncQuery& sync);
+ void endSync(SyncQuery& sync);
+ */
+
+ private:
+ friend class BrokerProxyImpl;
+ ConsoleEngine* envelope;
+ const ConsoleSettings& settings;
+ mutable Mutex lock;
+ deque<ConsoleEventImpl::Ptr> eventQueue;
+ vector<BrokerProxyImpl*> brokerList;
+ vector<pair<string, string> > bindingList; // exchange/key (empty exchange => QMF_EXCHANGE)
+
+ // Declare a compare class for the class maps that compares the dereferenced
+ // class key pointers. The default behavior would be to compare the pointer
+ // addresses themselves.
+ struct KeyCompare {
+ bool operator()(const SchemaClassKeyImpl* left, const SchemaClassKeyImpl* right) const {
+ return *left < *right;
+ }
+ };
+
+ typedef map<const SchemaClassKeyImpl*, SchemaObjectClassImpl::Ptr, KeyCompare> ObjectClassList;
+ typedef map<const SchemaClassKeyImpl*, SchemaEventClassImpl::Ptr, KeyCompare> EventClassList;
+ typedef map<string, pair<ObjectClassList, EventClassList> > PackageList;
+
+ PackageList packages;
+
+ void learnPackage(const string& packageName);
+ void learnClass(SchemaObjectClassImpl::Ptr cls);
+ void learnClass(SchemaEventClassImpl::Ptr cls);
+ bool haveClass(const SchemaClassKeyImpl& key) const;
+ };
+}
+
+namespace {
+const char* QMF_EXCHANGE = "qpid.management";
+const char* DIR_EXCHANGE = "amq.direct";
+const char* BROKER_KEY = "broker";
+}
+
+#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());}
+
+ConsoleEvent ConsoleEventImpl::copy()
+{
+ ConsoleEvent item;
+
+ ::memset(&item, 0, sizeof(ConsoleEvent));
+ item.kind = kind;
+ item.agent = agent.get() ? agent->envelope : 0;
+ item.classKey = classKey.get();
+ item.object = object;
+ item.context = context;
+ item.event = event;
+ item.timestamp = timestamp;
+ item.methodHandle = methodHandle;
+ item.methodResponse = methodResponse.get() ? methodResponse->envelope : 0;
+
+ STRING_REF(name);
+
+ return item;
+}
+
+BrokerEvent BrokerEventImpl::copy()
+{
+ BrokerEvent item;
+
+ ::memset(&item, 0, sizeof(BrokerEvent));
+ item.kind = kind;
+
+ STRING_REF(name);
+ STRING_REF(exchange);
+ STRING_REF(bindingKey);
+
+ return item;
+}
+
+BrokerProxyImpl::BrokerProxyImpl(BrokerProxy* e, ConsoleEngine& _console) :
+ envelope(e), console(_console.impl), queueName("qmfc-")
+{
+ // TODO: Give the queue name a unique suffix
+}
+
+void BrokerProxyImpl::sessionOpened(SessionHandle& /*sh*/)
+{
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.clear();
+ xmtQueue.clear();
+ eventQueue.push_back(eventDeclareQueue(queueName));
+ eventQueue.push_back(eventBind(DIR_EXCHANGE, queueName, queueName));
+ eventQueue.push_back(eventSetupComplete());
+
+ // TODO: Store session handle
+}
+
+void BrokerProxyImpl::sessionClosed()
+{
+ Mutex::ScopedLock _lock(lock);
+ eventQueue.clear();
+ xmtQueue.clear();
+}
+
+void BrokerProxyImpl::startProtocol()
+{
+ Mutex::ScopedLock _lock(lock);
+ char rawbuffer[512];
+ Buffer buffer(rawbuffer, 512);
+
+ requestsOutstanding = 1;
+ topicBound = false;
+ Protocol::encodeHeader(buffer, Protocol::OP_BROKER_REQUEST);
+ sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT BrokerRequest");
+}
+
+void BrokerProxyImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey)
+{
+ uint32_t length = buf.getPosition();
+ MessageImpl::Ptr message(new MessageImpl);
+
+ buf.reset();
+ buf.getRawData(message->body, length);
+ message->destination = destination;
+ message->routingKey = routingKey;
+ message->replyExchange = DIR_EXCHANGE;
+ message->replyKey = queueName;
+
+ xmtQueue.push_back(message);
+}
+
+void BrokerProxyImpl::handleRcvMessage(Message& message)
+{
+ Buffer inBuffer(message.body, message.length);
+ uint8_t opcode;
+ uint32_t sequence;
+
+ while (Protocol::checkHeader(inBuffer, &opcode, &sequence)) {
+ if (opcode == Protocol::OP_BROKER_RESPONSE) handleBrokerResponse(inBuffer, sequence);
+ else if (opcode == Protocol::OP_PACKAGE_INDICATION) handlePackageIndication(inBuffer, sequence);
+ else if (opcode == Protocol::OP_COMMAND_COMPLETE) handleCommandComplete(inBuffer, sequence);
+ else if (opcode == Protocol::OP_CLASS_INDICATION) handleClassIndication(inBuffer, sequence);
+ else if (opcode == Protocol::OP_METHOD_RESPONSE) handleMethodResponse(inBuffer, sequence);
+ else if (opcode == Protocol::OP_HEARTBEAT_INDICATION) handleHeartbeatIndication(inBuffer, sequence);
+ else if (opcode == Protocol::OP_EVENT_INDICATION) handleEventIndication(inBuffer, sequence);
+ else if (opcode == Protocol::OP_SCHEMA_RESPONSE) handleSchemaResponse(inBuffer, sequence);
+ else if (opcode == Protocol::OP_PROPERTY_INDICATION) handleObjectIndication(inBuffer, sequence, true, false);
+ else if (opcode == Protocol::OP_STATISTIC_INDICATION) handleObjectIndication(inBuffer, sequence, false, true);
+ else if (opcode == Protocol::OP_OBJECT_INDICATION) handleObjectIndication(inBuffer, sequence, true, true);
+ else {
+ QPID_LOG(trace, "BrokerProxyImpl::handleRcvMessage invalid opcode: " << opcode);
+ break;
+ }
+ }
+}
+
+bool BrokerProxyImpl::getXmtMessage(Message& item) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (xmtQueue.empty())
+ return false;
+ item = xmtQueue.front()->copy();
+ return true;
+}
+
+void BrokerProxyImpl::popXmt()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!xmtQueue.empty())
+ xmtQueue.pop_front();
+}
+
+bool BrokerProxyImpl::getEvent(BrokerEvent& event) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front()->copy();
+ return true;
+}
+
+void BrokerProxyImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+void BrokerProxyImpl::complete()
+{
+ decOutstanding();
+}
+
+void BrokerProxyImpl::addBinding(const string& exchange, const string& key)
+{
+ eventQueue.push_back(eventBind(exchange, queueName, key));
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventDeclareQueue(const string& queueName)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::DECLARE_QUEUE));
+ event->name = queueName;
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventBind(const string& exchange, const string& queue, const string& key)
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::BIND));
+ event->name = queue;
+ event->exchange = exchange;
+ event->bindingKey = key;
+
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventSetupComplete()
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::SETUP_COMPLETE));
+ return event;
+}
+
+BrokerEventImpl::Ptr BrokerProxyImpl::eventStable()
+{
+ BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::STABLE));
+ return event;
+}
+
+void BrokerProxyImpl::handleBrokerResponse(Buffer& inBuffer, uint32_t seq)
+{
+ // Note that this function doesn't touch requestsOutstanding. This is because
+ // it accounts for one request completed (the BrokerRequest) and one request
+ // started (the PackageRequest) which cancel each other out.
+
+ brokerId.decode(inBuffer);
+ QPID_LOG(trace, "RCVD BrokerResponse seq=" << seq << " brokerId=" << brokerId);
+ Mutex::ScopedLock _lock(lock);
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve(this));
+ Protocol::encodeHeader(outBuffer, Protocol::OP_PACKAGE_REQUEST, sequence);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT PackageRequest seq=" << sequence);
+}
+
+void BrokerProxyImpl::handlePackageIndication(Buffer& inBuffer, uint32_t seq)
+{
+ string package;
+
+ inBuffer.getShortString(package);
+ QPID_LOG(trace, "RCVD PackageIndication seq=" << seq << " package=" << package);
+ console->learnPackage(package);
+
+ Mutex::ScopedLock _lock(lock);
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve(this));
+ incOutstandingLH();
+ Protocol::encodeHeader(outBuffer, Protocol::OP_CLASS_QUERY, sequence);
+ outBuffer.putShortString(package);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT ClassQuery seq=" << sequence << " package=" << package);
+}
+
+void BrokerProxyImpl::handleCommandComplete(Buffer& inBuffer, uint32_t seq)
+{
+ string text;
+ uint32_t code = inBuffer.getLong();
+ inBuffer.getShortString(text);
+ QPID_LOG(trace, "RCVD CommandComplete seq=" << seq << " code=" << code << " text=" << text);
+ seqMgr.release(seq);
+}
+
+void BrokerProxyImpl::handleClassIndication(Buffer& inBuffer, uint32_t seq)
+{
+ string package;
+ string clsName;
+ SchemaHash hash;
+ uint8_t kind = inBuffer.getOctet();
+ inBuffer.getShortString(package);
+ inBuffer.getShortString(clsName);
+ hash.decode(inBuffer);
+ Uuid printableHash(hash.get());
+ SchemaClassKeyImpl classKey(package, clsName, hash);
+
+ QPID_LOG(trace, "RCVD ClassIndication seq=" << seq << " kind=" << (int) kind << " key=" << classKey.str());
+
+ if (!console->haveClass(classKey)) {
+ Mutex::ScopedLock _lock(lock);
+ incOutstandingLH();
+ Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE);
+ uint32_t sequence(seqMgr.reserve(this));
+ Protocol::encodeHeader(outBuffer, Protocol::OP_SCHEMA_REQUEST, sequence);
+ classKey.encode(outBuffer);
+ sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY);
+ QPID_LOG(trace, "SENT SchemaRequest seq=" << sequence <<" key=" << classKey.str());
+ }
+}
+
+void BrokerProxyImpl::handleMethodResponse(Buffer& /*inBuffer*/, uint32_t /*seq*/)
+{
+ // TODO
+}
+
+void BrokerProxyImpl::handleHeartbeatIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/)
+{
+ // TODO
+}
+
+void BrokerProxyImpl::handleEventIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/)
+{
+ // TODO
+}
+
+void BrokerProxyImpl::handleSchemaResponse(Buffer& inBuffer, uint32_t seq)
+{
+ SchemaObjectClassImpl::Ptr oClassPtr;
+ SchemaEventClassImpl::Ptr eClassPtr;
+ uint8_t kind = inBuffer.getOctet();
+ const SchemaClassKeyImpl* key;
+ if (kind == CLASS_OBJECT) {
+ oClassPtr.reset(new SchemaObjectClassImpl(inBuffer));
+ console->learnClass(oClassPtr);
+ key = oClassPtr->getClassKey()->impl;
+ QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=object key=" << key->str());
+ } else if (kind == CLASS_EVENT) {
+ eClassPtr.reset(new SchemaEventClassImpl(inBuffer));
+ console->learnClass(eClassPtr);
+ key = eClassPtr->getClassKey()->impl;
+ QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=event key=" << key->str());
+ }
+ else {
+ QPID_LOG(error, "BrokerProxyImpl::handleSchemaResponse received unknown class kind: " << (int) kind);
+ }
+
+ decOutstanding();
+}
+
+void BrokerProxyImpl::handleObjectIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/, bool /*prop*/, bool /*stat*/)
+{
+ // TODO
+}
+
+void BrokerProxyImpl::incOutstandingLH()
+{
+ requestsOutstanding++;
+}
+
+void BrokerProxyImpl::decOutstanding()
+{
+ Mutex::ScopedLock _lock(lock);
+ requestsOutstanding--;
+ if (requestsOutstanding == 0 && !topicBound) {
+ topicBound = true;
+ for (vector<pair<string, string> >::const_iterator iter = console->bindingList.begin();
+ iter != console->bindingList.end(); iter++) {
+ string exchange(iter->first.empty() ? QMF_EXCHANGE : iter->first);
+ string key(iter->second);
+ eventQueue.push_back(eventBind(exchange, queueName, key));
+ }
+ eventQueue.push_back(eventStable());
+ }
+}
+
+MethodResponseImpl::MethodResponseImpl(Buffer& buf) : envelope(new MethodResponse(this))
+{
+ string text;
+
+ status = buf.getLong();
+ buf.getMediumString(text);
+ exception.reset(new Value(TYPE_LSTR));
+ exception->setString(text.c_str());
+
+ // TODO: Parse schema-specific output arguments.
+ arguments.reset(new Value(TYPE_MAP));
+}
+
+ConsoleEngineImpl::ConsoleEngineImpl(ConsoleEngine* e, const ConsoleSettings& s) :
+ envelope(e), settings(s)
+{
+ bindingList.push_back(pair<string, string>(string(), "schema.#"));
+ if (settings.rcvObjects && settings.rcvEvents && settings.rcvHeartbeats && !settings.userBindings) {
+ bindingList.push_back(pair<string, string>(string(), "console.#"));
+ } else {
+ if (settings.rcvObjects && !settings.userBindings)
+ bindingList.push_back(pair<string, string>(string(), "console.obj.#"));
+ else
+ bindingList.push_back(pair<string, string>(string(), "console.obj.*.*.org.apache.qpid.broker.agent"));
+ if (settings.rcvEvents)
+ bindingList.push_back(pair<string, string>(string(), "console.event.#"));
+ if (settings.rcvHeartbeats)
+ bindingList.push_back(pair<string, string>(string(), "console.heartbeat.#"));
+ }
+}
+
+ConsoleEngineImpl::~ConsoleEngineImpl()
+{
+ // This function intentionally left blank.
+}
+
+bool ConsoleEngineImpl::getEvent(ConsoleEvent& event) const
+{
+ Mutex::ScopedLock _lock(lock);
+ if (eventQueue.empty())
+ return false;
+ event = eventQueue.front()->copy();
+ return true;
+}
+
+void ConsoleEngineImpl::popEvent()
+{
+ Mutex::ScopedLock _lock(lock);
+ if (!eventQueue.empty())
+ eventQueue.pop_front();
+}
+
+void ConsoleEngineImpl::addConnection(BrokerProxy& broker, void* /*context*/)
+{
+ Mutex::ScopedLock _lock(lock);
+ brokerList.push_back(broker.impl);
+}
+
+void ConsoleEngineImpl::delConnection(BrokerProxy& broker)
+{
+ Mutex::ScopedLock _lock(lock);
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ if (*iter == broker.impl) {
+ brokerList.erase(iter);
+ break;
+ }
+}
+
+uint32_t ConsoleEngineImpl::packageCount() const
+{
+ Mutex::ScopedLock _lock(lock);
+ return packages.size();
+}
+
+const string& ConsoleEngineImpl::getPackageName(uint32_t idx) const
+{
+ const static string empty;
+
+ Mutex::ScopedLock _lock(lock);
+ if (idx >= packages.size())
+ return empty;
+
+ PackageList::const_iterator iter = packages.begin();
+ for (uint32_t i = 0; i < idx; i++) iter++;
+ return iter->first;
+}
+
+uint32_t ConsoleEngineImpl::classCount(const char* packageName) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+
+ return oList.size() + eList.size();
+}
+
+const SchemaClassKey* ConsoleEngineImpl::getClass(const char* packageName, uint32_t idx) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(packageName);
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+ uint32_t count = 0;
+
+ for (ObjectClassList::const_iterator oIter = oList.begin();
+ oIter != oList.end(); oIter++) {
+ if (count == idx)
+ return oIter->second->getClassKey();
+ count++;
+ }
+
+ for (EventClassList::const_iterator eIter = eList.begin();
+ eIter != eList.end(); eIter++) {
+ if (count == idx)
+ return eIter->second->getClassKey();
+ count++;
+ }
+
+ return 0;
+}
+
+ClassKind ConsoleEngineImpl::getClassKind(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return CLASS_OBJECT;
+
+ const EventClassList& eList = pIter->second.second;
+ if (eList.find(key->impl) != eList.end())
+ return CLASS_EVENT;
+ return CLASS_OBJECT;
+}
+
+const SchemaObjectClass* ConsoleEngineImpl::getObjectClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const ObjectClassList& oList = pIter->second.first;
+ ObjectClassList::const_iterator iter = oList.find(key->impl);
+ if (iter == oList.end())
+ return 0;
+ return iter->second->envelope;
+}
+
+const SchemaEventClass* ConsoleEngineImpl::getEventClass(const SchemaClassKey* key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return 0;
+
+ const EventClassList& eList = pIter->second.second;
+ EventClassList::const_iterator iter = eList.find(key->impl);
+ if (iter == eList.end())
+ return 0;
+ return iter->second->envelope;
+}
+
+void ConsoleEngineImpl::bindPackage(const char* packageName)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+void ConsoleEngineImpl::bindClass(const SchemaClassKey* classKey)
+{
+ stringstream key;
+ key << "console.obj.*.*." << classKey->getPackageName() << "." << classKey->getClassName() << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+void ConsoleEngineImpl::bindClass(const char* packageName, const char* className)
+{
+ stringstream key;
+ key << "console.obj.*.*." << packageName << "." << className << ".#";
+ Mutex::ScopedLock _lock(lock);
+ bindingList.push_back(pair<string, string>(string(), key.str()));
+ for (vector<BrokerProxyImpl*>::iterator iter = brokerList.begin();
+ iter != brokerList.end(); iter++)
+ (*iter)->addBinding(QMF_EXCHANGE, key.str());
+}
+
+uint32_t ConsoleEngineImpl::agentCount() const
+{
+ // TODO
+ return 0;
+}
+
+const AgentProxy* ConsoleEngineImpl::getAgent(uint32_t /*idx*/) const
+{
+ // TODO
+ return 0;
+}
+
+void ConsoleEngineImpl::sendQuery(const Query& /*query*/, void* /*context*/)
+{
+ // TODO
+}
+
+/*
+void ConsoleEngineImpl::startSync(const Query& query, void* context, SyncQuery& sync)
+{
+}
+
+void ConsoleEngineImpl::touchSync(SyncQuery& sync)
+{
+}
+
+void ConsoleEngineImpl::endSync(SyncQuery& sync)
+{
+}
+*/
+
+void ConsoleEngineImpl::learnPackage(const string& packageName)
+{
+ Mutex::ScopedLock _lock(lock);
+ if (packages.find(packageName) == packages.end())
+ packages.insert(pair<string, pair<ObjectClassList, EventClassList> >
+ (packageName, pair<ObjectClassList, EventClassList>(ObjectClassList(), EventClassList())));
+}
+
+void ConsoleEngineImpl::learnClass(SchemaObjectClassImpl::Ptr cls)
+{
+ Mutex::ScopedLock _lock(lock);
+ const SchemaClassKey* key = cls->getClassKey();
+ PackageList::iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return;
+
+ ObjectClassList& list = pIter->second.first;
+ if (list.find(key->impl) == list.end())
+ list[key->impl] = cls;
+}
+
+void ConsoleEngineImpl::learnClass(SchemaEventClassImpl::Ptr cls)
+{
+ Mutex::ScopedLock _lock(lock);
+ const SchemaClassKey* key = cls->getClassKey();
+ PackageList::iterator pIter = packages.find(key->getPackageName());
+ if (pIter == packages.end())
+ return;
+
+ EventClassList& list = pIter->second.second;
+ if (list.find(key->impl) == list.end())
+ list[key->impl] = cls;
+}
+
+bool ConsoleEngineImpl::haveClass(const SchemaClassKeyImpl& key) const
+{
+ Mutex::ScopedLock _lock(lock);
+ PackageList::const_iterator pIter = packages.find(key.getPackageName());
+ if (pIter == packages.end())
+ return false;
+
+ const ObjectClassList& oList = pIter->second.first;
+ const EventClassList& eList = pIter->second.second;
+
+ return oList.find(&key) != oList.end() || eList.find(&key) != eList.end();
+}
+
+
+//==================================================================
+// Wrappers
+//==================================================================
+
+BrokerProxy::BrokerProxy(ConsoleEngine& console) : impl(new BrokerProxyImpl(this, console)) {}
+BrokerProxy::~BrokerProxy() { delete impl; }
+void BrokerProxy::sessionOpened(SessionHandle& sh) { impl->sessionOpened(sh); }
+void BrokerProxy::sessionClosed() { impl->sessionClosed(); }
+void BrokerProxy::startProtocol() { impl->startProtocol(); }
+void BrokerProxy::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); }
+bool BrokerProxy::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); }
+void BrokerProxy::popXmt() { impl->popXmt(); }
+bool BrokerProxy::getEvent(BrokerEvent& event) const { return impl->getEvent(event); }
+void BrokerProxy::popEvent() { impl->popEvent(); }
+
+AgentProxy::AgentProxy(ConsoleEngine& console) : impl(new AgentProxyImpl(this, console)) {}
+AgentProxy::~AgentProxy() { delete impl; }
+
+MethodResponse::MethodResponse(MethodResponseImpl* i) : impl(i) {}
+MethodResponse::~MethodResponse() { delete impl; } // TODO: correct to delete here?
+uint32_t MethodResponse::getStatus() const { return impl->getStatus(); }
+const Value* MethodResponse::getException() const { return impl->getException(); }
+const Value* MethodResponse::getArgs() const { return impl->getArgs(); }
+
+ConsoleEngine::ConsoleEngine(const ConsoleSettings& settings) : impl(new ConsoleEngineImpl(this, settings)) {}
+ConsoleEngine::~ConsoleEngine() { delete impl; }
+bool ConsoleEngine::getEvent(ConsoleEvent& event) const { return impl->getEvent(event); }
+void ConsoleEngine::popEvent() { impl->popEvent(); }
+void ConsoleEngine::addConnection(BrokerProxy& broker, void* context) { impl->addConnection(broker, context); }
+void ConsoleEngine::delConnection(BrokerProxy& broker) { impl->delConnection(broker); }
+uint32_t ConsoleEngine::packageCount() const { return impl->packageCount(); }
+const char* ConsoleEngine::getPackageName(uint32_t idx) const { return impl->getPackageName(idx).c_str(); }
+uint32_t ConsoleEngine::classCount(const char* packageName) const { return impl->classCount(packageName); }
+const SchemaClassKey* ConsoleEngine::getClass(const char* packageName, uint32_t idx) const { return impl->getClass(packageName, idx); }
+ClassKind ConsoleEngine::getClassKind(const SchemaClassKey* key) const { return impl->getClassKind(key); }
+const SchemaObjectClass* ConsoleEngine::getObjectClass(const SchemaClassKey* key) const { return impl->getObjectClass(key); }
+const SchemaEventClass* ConsoleEngine::getEventClass(const SchemaClassKey* key) const { return impl->getEventClass(key); }
+void ConsoleEngine::bindPackage(const char* packageName) { impl->bindPackage(packageName); }
+void ConsoleEngine::bindClass(const SchemaClassKey* key) { impl->bindClass(key); }
+void ConsoleEngine::bindClass(const char* packageName, const char* className) { impl->bindClass(packageName, className); }
+uint32_t ConsoleEngine::agentCount() const { return impl->agentCount(); }
+const AgentProxy* ConsoleEngine::getAgent(uint32_t idx) const { return impl->getAgent(idx); }
+void ConsoleEngine::sendQuery(const Query& query, void* context) { impl->sendQuery(query, context); }
+//void ConsoleEngine::startSync(const Query& query, void* context, SyncQuery& sync) { impl->startSync(query, context, sync); }
+//void ConsoleEngine::touchSync(SyncQuery& sync) { impl->touchSync(sync); }
+//void ConsoleEngine::endSync(SyncQuery& sync) { impl->endSync(sync); }
+
+
diff --git a/qpid/cpp/src/qmf/ConsoleEngine.h b/qpid/cpp/src/qmf/ConsoleEngine.h
new file mode 100644
index 0000000000..84ac78cd69
--- /dev/null
+++ b/qpid/cpp/src/qmf/ConsoleEngine.h
@@ -0,0 +1,200 @@
+#ifndef _QmfConsoleEngine_
+#define _QmfConsoleEngine_
+
+/*
+ * 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 <qmf/ResilientConnection.h>
+#include <qmf/Schema.h>
+#include <qmf/ObjectId.h>
+#include <qmf/Object.h>
+#include <qmf/Event.h>
+#include <qmf/Query.h>
+#include <qmf/Value.h>
+#include <qmf/Message.h>
+
+namespace qmf {
+
+ class ConsoleEngine;
+ class ConsoleEngineImpl;
+ class BrokerProxyImpl;
+ class AgentProxy;
+ class AgentProxyImpl;
+ class MethodResponseImpl;
+
+ /**
+ *
+ */
+ class MethodResponse {
+ public:
+ MethodResponse(MethodResponseImpl* impl);
+ ~MethodResponse();
+ uint32_t getStatus() const;
+ const Value* getException() const;
+ const Value* getArgs() const;
+
+ private:
+ friend class ConsoleEngineImpl;
+ MethodResponseImpl* impl;
+ };
+
+ /**
+ *
+ */
+ struct ConsoleEvent {
+ enum EventKind {
+ AGENT_ADDED = 1,
+ AGENT_DELETED = 2,
+ NEW_PACKAGE = 3,
+ NEW_CLASS = 4,
+ OBJECT_UPDATE = 5,
+ QUERY_COMPLETE = 6,
+ EVENT_RECEIVED = 7,
+ AGENT_HEARTBEAT = 8,
+ METHOD_RESPONSE = 9
+ };
+
+ EventKind kind;
+ AgentProxy* agent; // (AGENT_[ADDED|DELETED|HEARTBEAT])
+ char* name; // (NEW_PACKAGE)
+ SchemaClassKey* classKey; // (NEW_CLASS)
+ Object* object; // (OBJECT_UPDATE)
+ void* context; // (OBJECT_UPDATE, QUERY_COMPLETE)
+ Event* event; // (EVENT_RECEIVED)
+ uint64_t timestamp; // (AGENT_HEARTBEAT)
+ uint32_t methodHandle; // (METHOD_RESPONSE)
+ MethodResponse* methodResponse; // (METHOD_RESPONSE)
+ };
+
+ /**
+ *
+ */
+ struct BrokerEvent {
+ enum EventKind {
+ BROKER_INFO = 10,
+ DECLARE_QUEUE = 11,
+ DELETE_QUEUE = 12,
+ BIND = 13,
+ UNBIND = 14,
+ SETUP_COMPLETE = 15,
+ STABLE = 16
+ };
+
+ EventKind kind;
+ char* name; // ([DECLARE|DELETE]_QUEUE, [UN]BIND)
+ char* exchange; // ([UN]BIND)
+ char* bindingKey; // ([UN]BIND)
+ };
+
+ /**
+ *
+ */
+ class BrokerProxy {
+ public:
+ BrokerProxy(ConsoleEngine& console);
+ ~BrokerProxy();
+
+ void sessionOpened(SessionHandle& sh);
+ void sessionClosed();
+ void startProtocol();
+
+ void handleRcvMessage(Message& message);
+ bool getXmtMessage(Message& item) const;
+ void popXmt();
+
+ bool getEvent(BrokerEvent& event) const;
+ void popEvent();
+
+ private:
+ friend class ConsoleEngineImpl;
+ BrokerProxyImpl* impl;
+ };
+
+ /**
+ *
+ */
+ class AgentProxy {
+ public:
+ AgentProxy(ConsoleEngine& console);
+ ~AgentProxy();
+
+ private:
+ friend class ConsoleEngineImpl;
+ AgentProxyImpl* impl;
+ };
+
+ // TODO - move this to a public header
+ struct ConsoleSettings {
+ bool rcvObjects;
+ bool rcvEvents;
+ bool rcvHeartbeats;
+ bool userBindings;
+
+ ConsoleSettings() :
+ rcvObjects(true),
+ rcvEvents(true),
+ rcvHeartbeats(true),
+ userBindings(false) {}
+ };
+
+ class ConsoleEngine {
+ public:
+ ConsoleEngine(const ConsoleSettings& settings = ConsoleSettings());
+ ~ConsoleEngine();
+
+ bool getEvent(ConsoleEvent& event) const;
+ void popEvent();
+
+ void addConnection(BrokerProxy& broker, void* context);
+ void delConnection(BrokerProxy& broker);
+
+ uint32_t packageCount() const;
+ const char* getPackageName(uint32_t idx) const;
+
+ uint32_t classCount(const char* packageName) const;
+ const SchemaClassKey* getClass(const char* packageName, uint32_t idx) const;
+
+ ClassKind getClassKind(const SchemaClassKey* key) const;
+ const SchemaObjectClass* getObjectClass(const SchemaClassKey* key) const;
+ const SchemaEventClass* getEventClass(const SchemaClassKey* key) const;
+
+ void bindPackage(const char* packageName);
+ void bindClass(const SchemaClassKey* key);
+ void bindClass(const char* packageName, const char* className);
+
+ uint32_t agentCount() const;
+ const AgentProxy* getAgent(uint32_t idx) const;
+
+ void sendQuery(const Query& query, void* context);
+
+ /*
+ void startSync(const Query& query, void* context, SyncQuery& sync);
+ void touchSync(SyncQuery& sync);
+ void endSync(SyncQuery& sync);
+ */
+
+ private:
+ friend class BrokerProxyImpl;
+ friend class AgentProxyImpl;
+ ConsoleEngineImpl* impl;
+ };
+}
+
+#endif
+
diff --git a/qpid/cpp/src/qmf/Object.h b/qpid/cpp/src/qmf/Object.h
index 8caab8d6dc..eb92cbbe45 100644
--- a/qpid/cpp/src/qmf/Object.h
+++ b/qpid/cpp/src/qmf/Object.h
@@ -31,7 +31,7 @@ namespace qmf {
public:
Object(const SchemaObjectClass* type);
Object(ObjectImpl* impl);
- ~Object();
+ virtual ~Object();
void destroy();
const ObjectId* getObjectId() const;
diff --git a/qpid/cpp/src/qmf/ObjectId.h b/qpid/cpp/src/qmf/ObjectId.h
index 1ceae20bd8..ffd1b6978b 100644
--- a/qpid/cpp/src/qmf/ObjectId.h
+++ b/qpid/cpp/src/qmf/ObjectId.h
@@ -39,7 +39,6 @@ namespace qmf {
bool isDurable() const;
bool operator==(const ObjectId& other) const;
- bool operator!=(const ObjectId& other) const;
bool operator<(const ObjectId& other) const;
bool operator>(const ObjectId& other) const;
bool operator<=(const ObjectId& other) const;
diff --git a/qpid/cpp/src/qmf/ObjectIdImpl.cpp b/qpid/cpp/src/qmf/ObjectIdImpl.cpp
index efa8e7119b..75661fdb47 100644
--- a/qpid/cpp/src/qmf/ObjectIdImpl.cpp
+++ b/qpid/cpp/src/qmf/ObjectIdImpl.cpp
@@ -166,11 +166,6 @@ bool ObjectId::operator==(const ObjectId& other) const
return *impl == *other.impl;
}
-bool ObjectId::operator!=(const ObjectId& other) const
-{
- return !(*impl == *other.impl);
-}
-
bool ObjectId::operator<(const ObjectId& other) const
{
return *impl < *other.impl;
diff --git a/qpid/cpp/src/qmf/ObjectImpl.cpp b/qpid/cpp/src/qmf/ObjectImpl.cpp
index d3882935e4..645ccd5c81 100644
--- a/qpid/cpp/src/qmf/ObjectImpl.cpp
+++ b/qpid/cpp/src/qmf/ObjectImpl.cpp
@@ -123,9 +123,9 @@ void ObjectImpl::parsePresenceMasks(Buffer& buffer, set<string>& excludeList)
void ObjectImpl::encodeSchemaKey(qpid::framing::Buffer& buffer) const
{
- buffer.putShortString(objectClass->getPackage());
- buffer.putShortString(objectClass->getName());
- buffer.putBin128(const_cast<uint8_t*>(objectClass->getHash()));
+ buffer.putShortString(objectClass->getClassKey()->getPackageName());
+ buffer.putShortString(objectClass->getClassKey()->getClassName());
+ buffer.putBin128(const_cast<uint8_t*>(objectClass->getClassKey()->getHash()));
}
void ObjectImpl::encodeManagedObjectData(qpid::framing::Buffer& buffer) const
diff --git a/qpid/cpp/src/qmf/Protocol.cpp b/qpid/cpp/src/qmf/Protocol.cpp
new file mode 100644
index 0000000000..0a3beeb276
--- /dev/null
+++ b/qpid/cpp/src/qmf/Protocol.cpp
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "qmf/Protocol.h"
+#include "qpid/framing/Buffer.h"
+
+using namespace std;
+using namespace qmf;
+using namespace qpid::framing;
+
+
+bool Protocol::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq)
+{
+ if (buf.available() < 8)
+ return false;
+
+ uint8_t h1 = buf.getOctet();
+ uint8_t h2 = buf.getOctet();
+ uint8_t h3 = buf.getOctet();
+
+ *opcode = buf.getOctet();
+ *seq = buf.getLong();
+
+ return h1 == 'A' && h2 == 'M' && h3 == '3';
+}
+
+void Protocol::encodeHeader(qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq)
+{
+ buf.putOctet('A');
+ buf.putOctet('M');
+ buf.putOctet('3');
+ buf.putOctet(opcode);
+ buf.putLong (seq);
+}
+
+
diff --git a/qpid/cpp/src/qmf/Protocol.h b/qpid/cpp/src/qmf/Protocol.h
new file mode 100644
index 0000000000..d5da08c1db
--- /dev/null
+++ b/qpid/cpp/src/qmf/Protocol.h
@@ -0,0 +1,67 @@
+#ifndef _QmfProtocol_
+#define _QmfProtocol_
+
+/*
+ * 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 <qpid/sys/IntegerTypes.h>
+
+namespace qpid {
+ namespace framing {
+ class Buffer;
+ }
+}
+
+namespace qmf {
+
+ class Protocol {
+ public:
+ static bool checkHeader(qpid::framing::Buffer& buf, uint8_t *opcode, uint32_t *seq);
+ static void encodeHeader(qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0);
+
+ const static uint8_t OP_ATTACH_REQUEST = 'A';
+ const static uint8_t OP_ATTACH_RESPONSE = 'a';
+
+ const static uint8_t OP_BROKER_REQUEST = 'B';
+ const static uint8_t OP_BROKER_RESPONSE = 'b';
+
+ const static uint8_t OP_CONSOLE_ADDED_INDICATION = 'x';
+ const static uint8_t OP_COMMAND_COMPLETE = 'z';
+ const static uint8_t OP_HEARTBEAT_INDICATION = 'h';
+
+ const static uint8_t OP_PACKAGE_REQUEST = 'P';
+ const static uint8_t OP_PACKAGE_INDICATION = 'p';
+ const static uint8_t OP_CLASS_QUERY = 'Q';
+ const static uint8_t OP_CLASS_INDICATION = 'q';
+ const static uint8_t OP_SCHEMA_REQUEST = 'S';
+ const static uint8_t OP_SCHEMA_RESPONSE = 's';
+
+ const static uint8_t OP_METHOD_REQUEST = 'M';
+ const static uint8_t OP_METHOD_RESPONSE = 'm';
+ const static uint8_t OP_GET_QUERY = 'G';
+ const static uint8_t OP_OBJECT_INDICATION = 'g';
+ const static uint8_t OP_PROPERTY_INDICATION = 'c';
+ const static uint8_t OP_STATISTIC_INDICATION = 'i';
+ const static uint8_t OP_EVENT_INDICATION = 'e';
+ };
+
+}
+
+#endif
+
diff --git a/qpid/cpp/src/qmf/ResilientConnection.cpp b/qpid/cpp/src/qmf/ResilientConnection.cpp
index 610306f896..7ec03cf4da 100644
--- a/qpid/cpp/src/qmf/ResilientConnection.cpp
+++ b/qpid/cpp/src/qmf/ResilientConnection.cpp
@@ -19,6 +19,8 @@
#include "qmf/ResilientConnection.h"
#include "qmf/MessageImpl.h"
+#include "qmf/ConnectionSettingsImpl.h"
+#include <qpid/client/Connection.h>
#include <qpid/client/Session.h>
#include <qpid/client/MessageListener.h>
#include <qpid/client/SubscriptionManager.h>
@@ -39,7 +41,7 @@
using namespace std;
using namespace qmf;
-using namespace qpid::client;
+using namespace qpid;
using qpid::sys::Mutex;
namespace qmf {
@@ -55,30 +57,29 @@ namespace qmf {
ResilientConnectionEvent copy();
};
- struct RCSession : public MessageListener, public qpid::sys::Runnable, public qpid::RefCounted {
+ struct RCSession : public client::MessageListener, public qpid::sys::Runnable, public qpid::RefCounted {
typedef boost::intrusive_ptr<RCSession> Ptr;
ResilientConnectionImpl& connImpl;
string name;
- Connection& connection;
- Session session;
- SubscriptionManager* subscriptions;
+ client::Connection& connection;
+ client::Session session;
+ client::SubscriptionManager* subscriptions;
void* userContext;
vector<string> dests;
qpid::sys::Thread thread;
- RCSession(ResilientConnectionImpl& ci, const string& n, Connection& c, void* uc) :
+ RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc) :
connImpl(ci), name(n), connection(c), session(connection.newSession(name)),
- subscriptions(new SubscriptionManager(session)), userContext(uc), thread(*this) {}
+ subscriptions(new client::SubscriptionManager(session)), userContext(uc), thread(*this) {}
~RCSession();
- void received(qpid::client::Message& msg);
+ void received(client::Message& msg);
void run();
void stop();
};
class ResilientConnectionImpl : public qpid::sys::Runnable {
public:
- ResilientConnectionImpl(ConnectionSettings& settings,
- int dmin, int dmax, int dfactor);
+ ResilientConnectionImpl(const ConnectionSettings& settings);
~ResilientConnectionImpl();
bool isConnected() const;
@@ -107,8 +108,8 @@ namespace qmf {
bool connected;
bool shutdown;
string lastError;
- ConnectionSettings settings;
- Connection connection;
+ const ConnectionSettings settings;
+ client::Connection connection;
mutable qpid::sys::Mutex lock;
int delayMin;
int delayMax;
@@ -155,7 +156,7 @@ void RCSession::stop()
subscriptions->stop();
}
-void RCSession::received(qpid::client::Message& msg)
+void RCSession::received(client::Message& msg)
{
qmf::MessageImpl qmsg;
qmsg.body = msg.getData();
@@ -174,12 +175,11 @@ void RCSession::received(qpid::client::Message& msg)
connImpl.EnqueueEvent(ResilientConnectionEvent::RECV, userContext, qmsg);
}
-ResilientConnectionImpl::ResilientConnectionImpl(ConnectionSettings& _settings,
- int dmin, int dmax, int dfactor) :
- notifyFd(-1), connected(false), shutdown(false), settings(_settings),
- delayMin(dmin), delayMax(dmax), delayFactor(dfactor), connThread(*this)
+ResilientConnectionImpl::ResilientConnectionImpl(const ConnectionSettings& _settings) :
+ notifyFd(-1), connected(false), shutdown(false), settings(_settings), delayMin(1), connThread(*this)
{
connection.registerFailureCallback(boost::bind(&ResilientConnectionImpl::failure, this));
+ settings.impl->getRetrySettings(&delayMin, &delayMax, &delayFactor);
}
ResilientConnectionImpl::~ResilientConnectionImpl()
@@ -222,7 +222,7 @@ bool ResilientConnectionImpl::createSession(const char* name, void* sessionConte
RCSession::Ptr sess = RCSession::Ptr(new RCSession(*this, name, connection, sessionContext));
- handle.handle = (void*) sess.get();
+ handle.impl = (void*) sess.get();
sessions.insert(sess);
return true;
@@ -231,7 +231,7 @@ bool ResilientConnectionImpl::createSession(const char* name, void* sessionConte
void ResilientConnectionImpl::destroySession(SessionHandle handle)
{
Mutex::ScopedLock _lock(lock);
- RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.handle);
+ RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl);
set<RCSession::Ptr>::iterator iter = sessions.find(sess);
if (iter != sessions.end()) {
for (vector<string>::iterator dIter = sess->dests.begin(); dIter != sess->dests.end(); dIter++)
@@ -247,7 +247,7 @@ void ResilientConnectionImpl::destroySession(SessionHandle handle)
void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& message)
{
Mutex::ScopedLock _lock(lock);
- RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.handle);
+ RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl);
set<RCSession::Ptr>::iterator iter = sessions.find(sess);
qpid::client::Message msg;
string data(message.body, message.length);
@@ -256,7 +256,7 @@ void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& me
msg.setData(data);
try {
- sess->session.messageTransfer(arg::content=msg, arg::destination=message.destination);
+ sess->session.messageTransfer(client::arg::content=msg, client::arg::destination=message.destination);
} catch(exception& e) {
QPID_LOG(error, "Session Exception during message-transfer: " << e.what());
sessions.erase(iter);
@@ -267,19 +267,22 @@ void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& me
void ResilientConnectionImpl::declareQueue(SessionHandle handle, char* queue)
{
Mutex::ScopedLock _lock(lock);
- RCSession* sess = (RCSession*) handle.handle;
+ RCSession* sess = (RCSession*) handle.impl;
- sess->session.queueDeclare(arg::queue=queue, arg::autoDelete=true, arg::exclusive=true);
+ sess->session.queueDeclare(client::arg::queue=queue, client::arg::autoDelete=true, client::arg::exclusive=true);
+ sess->subscriptions->setAcceptMode(client::ACCEPT_MODE_NONE);
+ sess->subscriptions->setAcquireMode(client::ACQUIRE_MODE_PRE_ACQUIRED);
sess->subscriptions->subscribe(*sess, queue, queue);
+ sess->subscriptions->setFlowControl(queue, client::FlowControl::unlimited());
sess->dests.push_back(string(queue));
}
void ResilientConnectionImpl::deleteQueue(SessionHandle handle, char* queue)
{
Mutex::ScopedLock _lock(lock);
- RCSession* sess = (RCSession*) handle.handle;
+ RCSession* sess = (RCSession*) handle.impl;
- sess->session.queueDelete(arg::queue=queue);
+ sess->session.queueDelete(client::arg::queue=queue);
for (vector<string>::iterator iter = sess->dests.begin();
iter != sess->dests.end(); iter++)
if (*iter == queue) {
@@ -293,18 +296,18 @@ void ResilientConnectionImpl::bind(SessionHandle handle,
char* exchange, char* queue, char* key)
{
Mutex::ScopedLock _lock(lock);
- RCSession* sess = (RCSession*) handle.handle;
+ RCSession* sess = (RCSession*) handle.impl;
- sess->session.exchangeBind(arg::exchange=exchange, arg::queue=queue, arg::bindingKey=key);
+ sess->session.exchangeBind(client::arg::exchange=exchange, client::arg::queue=queue, client::arg::bindingKey=key);
}
void ResilientConnectionImpl::unbind(SessionHandle handle,
char* exchange, char* queue, char* key)
{
Mutex::ScopedLock _lock(lock);
- RCSession* sess = (RCSession*) handle.handle;
+ RCSession* sess = (RCSession*) handle.impl;
- sess->session.exchangeUnbind(arg::exchange=exchange, arg::queue=queue, arg::bindingKey=key);
+ sess->session.exchangeUnbind(client::arg::exchange=exchange, client::arg::queue=queue, client::arg::bindingKey=key);
}
void ResilientConnectionImpl::setNotifyFd(int fd)
@@ -318,7 +321,8 @@ void ResilientConnectionImpl::run()
while (true) {
try {
- connection.open(settings);
+ QPID_LOG(trace, "Trying to open connection...");
+ connection.open(settings.impl->getClientSettings());
{
Mutex::ScopedLock _lock(lock);
connected = true;
@@ -326,6 +330,7 @@ void ResilientConnectionImpl::run()
while (connected)
cond.wait(lock);
+ delay = delayMin;
while (!sessions.empty()) {
set<RCSession::Ptr>::iterator iter = sessions.begin();
@@ -334,6 +339,11 @@ void ResilientConnectionImpl::run()
EnqueueEvent(ResilientConnectionEvent::SESSION_CLOSED, sess->userContext);
Mutex::ScopedUnlock _u(lock);
sess->stop();
+
+ // Nullify the intrusive pointer within the scoped unlock, otherwise,
+ // the reference is held until overwritted above (under lock) which causes
+ // the session destructor to be called with the lock held.
+ sess = 0;
}
EnqueueEvent(ResilientConnectionEvent::DISCONNECTED);
@@ -341,7 +351,6 @@ void ResilientConnectionImpl::run()
if (shutdown)
return;
}
- delay = delayMin;
connection.close();
} catch (exception &e) {
QPID_LOG(debug, "connection.open exception: " << e.what());
@@ -396,10 +405,9 @@ void ResilientConnectionImpl::EnqueueEvent(ResilientConnectionEvent::EventKind k
// Wrappers
//==================================================================
-ResilientConnection::ResilientConnection(ConnectionSettings& settings,
- int delayMin, int delayMax, int delayFactor)
+ResilientConnection::ResilientConnection(const ConnectionSettings& settings)
{
- impl = new ResilientConnectionImpl(settings, delayMin, delayMax, delayFactor);
+ impl = new ResilientConnectionImpl(settings);
}
ResilientConnection::~ResilientConnection()
diff --git a/qpid/cpp/src/qmf/ResilientConnection.h b/qpid/cpp/src/qmf/ResilientConnection.h
index bb565e27ae..03f1b9c0d5 100644
--- a/qpid/cpp/src/qmf/ResilientConnection.h
+++ b/qpid/cpp/src/qmf/ResilientConnection.h
@@ -21,12 +21,13 @@
*/
#include <qmf/Message.h>
-#include <qpid/client/Connection.h>
-#include <qpid/client/ConnectionSettings.h>
+#include <qmf/ConnectionSettings.h>
#include <string>
namespace qmf {
+ class ResilientConnectionImpl;
+
/**
* Represents events that occur, unsolicited, from ResilientConnection.
*/
@@ -44,12 +45,11 @@ namespace qmf {
Message message; // RECV
};
- struct SessionHandle {
- void* handle;
+ class SessionHandle {
+ friend class ResilientConnectionImpl;
+ void* impl;
};
- class ResilientConnectionImpl;
-
/**
* ResilientConnection represents a Qpid connection that is resilient.
*
@@ -68,10 +68,7 @@ namespace qmf {
*@param delayMax Maximum delay (in seconds) between retries.
*@param delayFactor Factor to multiply retry delay by after each failure.
*/
- ResilientConnection(qpid::client::ConnectionSettings& settings,
- int delayMin = 1,
- int delayMax = 128,
- int delayFactor = 2);
+ ResilientConnection(const ConnectionSettings& settings);
~ResilientConnection();
/**
diff --git a/qpid/cpp/src/qmf/Schema.h b/qpid/cpp/src/qmf/Schema.h
index e3ab90e3e3..1123acc3b8 100644
--- a/qpid/cpp/src/qmf/Schema.h
+++ b/qpid/cpp/src/qmf/Schema.h
@@ -35,6 +35,7 @@ namespace qmf {
struct SchemaStatisticImpl;
struct SchemaObjectClassImpl;
struct SchemaEventClassImpl;
+ struct SchemaClassKeyImpl;
/**
*/
@@ -114,6 +115,20 @@ namespace qmf {
/**
*/
+ class SchemaClassKey {
+ public:
+ SchemaClassKey(SchemaClassKeyImpl* impl);
+ ~SchemaClassKey();
+
+ const char* getPackageName() const;
+ const char* getClassName() const;
+ const uint8_t* getHash() const;
+
+ SchemaClassKeyImpl* impl;
+ };
+
+ /**
+ */
class SchemaObjectClass {
public:
SchemaObjectClass(const char* package, const char* name);
@@ -123,9 +138,7 @@ namespace qmf {
void addStatistic(const SchemaStatistic& statistic);
void addMethod(const SchemaMethod& method);
- const char* getPackage() const;
- const char* getName() const;
- const uint8_t* getHash() const;
+ const SchemaClassKey* getClassKey() const;
int getPropertyCount() const;
int getStatisticCount() const;
int getMethodCount() const;
@@ -146,9 +159,7 @@ namespace qmf {
void addArgument(const SchemaArgument& argument);
void setDesc(const char* desc);
- const char* getPackage() const;
- const char* getName() const;
- const uint8_t* getHash() const;
+ const SchemaClassKey* getClassKey() const;
int getArgumentCount() const;
const SchemaArgument* getArgument(int idx) const;
diff --git a/qpid/cpp/src/qmf/SchemaImpl.cpp b/qpid/cpp/src/qmf/SchemaImpl.cpp
index 665c94f2a1..ae7d6ca689 100644
--- a/qpid/cpp/src/qmf/SchemaImpl.cpp
+++ b/qpid/cpp/src/qmf/SchemaImpl.cpp
@@ -20,6 +20,8 @@
#include "qmf/SchemaImpl.h"
#include <qpid/framing/Buffer.h>
#include <qpid/framing/FieldTable.h>
+#include <qpid/framing/Uuid.h>
+#include <string.h>
#include <string>
#include <vector>
@@ -27,6 +29,7 @@ using namespace std;
using namespace qmf;
using qpid::framing::Buffer;
using qpid::framing::FieldTable;
+using qpid::framing::Uuid;
SchemaHash::SchemaHash()
{
@@ -34,7 +37,7 @@ SchemaHash::SchemaHash()
hash[idx] = 0x5A;
}
-void SchemaHash::encode(Buffer& buffer)
+void SchemaHash::encode(Buffer& buffer) const
{
buffer.putBin128(hash);
}
@@ -63,6 +66,21 @@ void SchemaHash::update(const char* data, uint32_t len)
}
}
+bool SchemaHash::operator==(const SchemaHash& other) const
+{
+ return ::memcmp(&hash, &other.hash, 16) == 0;
+}
+
+bool SchemaHash::operator<(const SchemaHash& other) const
+{
+ return ::memcmp(&hash, &other.hash, 16) < 0;
+}
+
+bool SchemaHash::operator>(const SchemaHash& other) const
+{
+ return ::memcmp(&hash, &other.hash, 16) > 0;
+}
+
SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer) : envelope(new SchemaArgument(this))
{
FieldTable map;
@@ -240,15 +258,51 @@ void SchemaStatisticImpl::updateHash(SchemaHash& hash) const
hash.update(description);
}
-SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) : envelope(new SchemaObjectClass(this)), hasHash(true)
+SchemaClassKeyImpl::SchemaClassKeyImpl(const string& p, const string& n, const SchemaHash& h) :
+ envelope(new SchemaClassKey(this)), package(p), name(n), hash(h) {}
+
+void SchemaClassKeyImpl::encode(qpid::framing::Buffer& buffer) const
+{
+ buffer.putShortString(package);
+ buffer.putShortString(name);
+ hash.encode(buffer);
+}
+
+bool SchemaClassKeyImpl::operator==(const SchemaClassKeyImpl& other) const
+{
+ return package == other.package &&
+ name == other.name &&
+ hash == other.hash;
+}
+
+bool SchemaClassKeyImpl::operator<(const SchemaClassKeyImpl& other) const
+{
+ if (package < other.package) return true;
+ if (package > other.package) return false;
+ if (name < other.name) return true;
+ if (name > other.name) return false;
+ return hash < other.hash;
+}
+
+string SchemaClassKeyImpl::str() const
+{
+ Uuid printableHash(hash.get());
+ stringstream str;
+ str << package << ":" << name << "(" << printableHash << ")";
+ return str.str();
+}
+
+SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) :
+ envelope(new SchemaObjectClass(this)), hasHash(true), classKey(package, name, hash)
{
buffer.getShortString(package);
buffer.getShortString(name);
hash.decode(buffer);
- uint16_t propCount = buffer.getShort();
- uint16_t statCount = buffer.getShort();
- uint16_t methodCount = buffer.getShort();
+ /*uint8_t hasParentClass =*/ buffer.getOctet(); // TODO: Parse parent-class indicator
+ uint16_t propCount = buffer.getShort();
+ uint16_t statCount = buffer.getShort();
+ uint16_t methodCount = buffer.getShort();
for (uint16_t idx = 0; idx < propCount; idx++) {
SchemaPropertyImpl* property = new SchemaPropertyImpl(buffer);
@@ -288,7 +342,7 @@ void SchemaObjectClassImpl::encode(Buffer& buffer) const
(*iter)->encode(buffer);
}
-const uint8_t* SchemaObjectClassImpl::getHash() const
+const SchemaClassKey* SchemaObjectClassImpl::getClassKey() const
{
if (!hasHash) {
hasHash = true;
@@ -305,7 +359,7 @@ const uint8_t* SchemaObjectClassImpl::getHash() const
(*iter)->updateHash(hash);
}
- return hash.get();
+ return classKey.envelope;
}
void SchemaObjectClassImpl::addProperty(const SchemaProperty& property)
@@ -353,7 +407,8 @@ const SchemaMethod* SchemaObjectClassImpl::getMethod(int idx) const
return 0;
}
-SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) : envelope(new SchemaEventClass(this)), hasHash(true)
+SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) :
+ envelope(new SchemaEventClass(this)), hasHash(true), classKey(package, name, hash)
{
buffer.getShortString(package);
buffer.getShortString(name);
@@ -380,7 +435,7 @@ void SchemaEventClassImpl::encode(Buffer& buffer) const
(*iter)->encode(buffer);
}
-const uint8_t* SchemaEventClassImpl::getHash() const
+const SchemaClassKey* SchemaEventClassImpl::getClassKey() const
{
if (!hasHash) {
hasHash = true;
@@ -390,7 +445,7 @@ const uint8_t* SchemaEventClassImpl::getHash() const
iter != arguments.end(); iter++)
(*iter)->updateHash(hash);
}
- return hash.get();
+ return classKey.envelope;
}
void SchemaEventClassImpl::addArgument(const SchemaArgument& argument)
@@ -408,334 +463,79 @@ const SchemaArgument* SchemaEventClassImpl::getArgument(int idx) const
return 0;
}
+
//==================================================================
// Wrappers
//==================================================================
-SchemaArgument::SchemaArgument(const char* name, Typecode typecode)
-{
- impl = new SchemaArgumentImpl(this, name, typecode);
-}
-
+SchemaArgument::SchemaArgument(const char* name, Typecode typecode) { impl = new SchemaArgumentImpl(this, name, typecode); }
SchemaArgument::SchemaArgument(SchemaArgumentImpl* i) : impl(i) {}
-
-SchemaArgument::~SchemaArgument()
-{
- delete impl;
-}
-
-void SchemaArgument::setDirection(Direction dir)
-{
- impl->setDirection(dir);
-}
-
-void SchemaArgument::setUnit(const char* val)
-{
- impl->setUnit(val);
-}
-
-void SchemaArgument::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaArgument::getName() const
-{
- return impl->getName().c_str();
-}
-
-Typecode SchemaArgument::getType() const
-{
- return impl->getType();
-}
-
-Direction SchemaArgument::getDirection() const
-{
- return impl->getDirection();
-}
-
-const char* SchemaArgument::getUnit() const
-{
- return impl->getUnit().c_str();
-}
-
-const char* SchemaArgument::getDesc() const
-{
- return impl->getDesc().c_str();
-}
-
-SchemaMethod::SchemaMethod(const char* name)
-{
- impl = new SchemaMethodImpl(this, name);
-}
-
+SchemaArgument::~SchemaArgument() { delete impl; }
+void SchemaArgument::setDirection(Direction dir) { impl->setDirection(dir); }
+void SchemaArgument::setUnit(const char* val) { impl->setUnit(val); }
+void SchemaArgument::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaArgument::getName() const { return impl->getName().c_str(); }
+Typecode SchemaArgument::getType() const { return impl->getType(); }
+Direction SchemaArgument::getDirection() const { return impl->getDirection(); }
+const char* SchemaArgument::getUnit() const { return impl->getUnit().c_str(); }
+const char* SchemaArgument::getDesc() const { return impl->getDesc().c_str(); }
+SchemaMethod::SchemaMethod(const char* name) { impl = new SchemaMethodImpl(this, name); }
SchemaMethod::SchemaMethod(SchemaMethodImpl* i) : impl(i) {}
-
-SchemaMethod::~SchemaMethod()
-{
- delete impl;
-}
-
-void SchemaMethod::addArgument(const SchemaArgument& argument)
-{
- impl->addArgument(argument);
-}
-
-void SchemaMethod::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaMethod::getName() const
-{
- return impl->getName().c_str();
-}
-
-const char* SchemaMethod::getDesc() const
-{
- return impl->getDesc().c_str();
-}
-
-int SchemaMethod::getArgumentCount() const
-{
- return impl->getArgumentCount();
-}
-
-const SchemaArgument* SchemaMethod::getArgument(int idx) const
-{
- return impl->getArgument(idx);
-}
-
-SchemaProperty::SchemaProperty(const char* name, Typecode typecode)
-{
- impl = new SchemaPropertyImpl(this, name, typecode);
-}
-
+SchemaMethod::~SchemaMethod() { delete impl; }
+void SchemaMethod::addArgument(const SchemaArgument& argument) { impl->addArgument(argument); }
+void SchemaMethod::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaMethod::getName() const { return impl->getName().c_str(); }
+const char* SchemaMethod::getDesc() const { return impl->getDesc().c_str(); }
+int SchemaMethod::getArgumentCount() const { return impl->getArgumentCount(); }
+const SchemaArgument* SchemaMethod::getArgument(int idx) const { return impl->getArgument(idx); }
+SchemaProperty::SchemaProperty(const char* name, Typecode typecode) { impl = new SchemaPropertyImpl(this, name, typecode); }
SchemaProperty::SchemaProperty(SchemaPropertyImpl* i) : impl(i) {}
-
-SchemaProperty::~SchemaProperty()
-{
- delete impl;
-}
-
-void SchemaProperty::setAccess(Access access)
-{
- impl->setAccess(access);
-}
-
-void SchemaProperty::setIndex(bool val)
-{
- impl->setIndex(val);
-}
-
-void SchemaProperty::setOptional(bool val)
-{
- impl->setOptional(val);
-}
-
-void SchemaProperty::setUnit(const char* val)
-{
- impl->setUnit(val);
-}
-
-void SchemaProperty::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaProperty::getName() const
-{
- return impl->getName().c_str();
-}
-
-Typecode SchemaProperty::getType() const
-{
- return impl->getType();
-}
-
-Access SchemaProperty::getAccess() const
-{
- return impl->getAccess();
-}
-
-bool SchemaProperty::isIndex() const
-{
- return impl->isIndex();
-}
-
-bool SchemaProperty::isOptional() const
-{
- return impl->isOptional();
-}
-
-const char* SchemaProperty::getUnit() const
-{
- return impl->getUnit().c_str();
-}
-
-const char* SchemaProperty::getDesc() const
-{
- return impl->getDesc().c_str();
-}
-
-SchemaStatistic::SchemaStatistic(const char* name, Typecode typecode)
-{
- impl = new SchemaStatisticImpl(this, name, typecode);
-}
-
+SchemaProperty::~SchemaProperty() { delete impl; }
+void SchemaProperty::setAccess(Access access) { impl->setAccess(access); }
+void SchemaProperty::setIndex(bool val) { impl->setIndex(val); }
+void SchemaProperty::setOptional(bool val) { impl->setOptional(val); }
+void SchemaProperty::setUnit(const char* val) { impl->setUnit(val); }
+void SchemaProperty::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaProperty::getName() const { return impl->getName().c_str(); }
+Typecode SchemaProperty::getType() const { return impl->getType(); }
+Access SchemaProperty::getAccess() const { return impl->getAccess(); }
+bool SchemaProperty::isIndex() const { return impl->isIndex(); }
+bool SchemaProperty::isOptional() const { return impl->isOptional(); }
+const char* SchemaProperty::getUnit() const { return impl->getUnit().c_str(); }
+const char* SchemaProperty::getDesc() const { return impl->getDesc().c_str(); }
+SchemaStatistic::SchemaStatistic(const char* name, Typecode typecode) { impl = new SchemaStatisticImpl(this, name, typecode); }
SchemaStatistic::SchemaStatistic(SchemaStatisticImpl* i) : impl(i) {}
-
-SchemaStatistic::~SchemaStatistic()
-{
- delete impl;
-}
-
-void SchemaStatistic::setUnit(const char* val)
-{
- impl->setUnit(val);
-}
-
-void SchemaStatistic::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaStatistic::getName() const
-{
- return impl->getName().c_str();
-}
-
-Typecode SchemaStatistic::getType() const
-{
- return impl->getType();
-}
-
-const char* SchemaStatistic::getUnit() const
-{
- return impl->getUnit().c_str();
-}
-
-const char* SchemaStatistic::getDesc() const
-{
- return impl->getDesc().c_str();
-}
-
-SchemaObjectClass::SchemaObjectClass(const char* package, const char* name)
-{
- impl = new SchemaObjectClassImpl(this, package, name);
-}
-
+SchemaStatistic::~SchemaStatistic() { delete impl; }
+void SchemaStatistic::setUnit(const char* val) { impl->setUnit(val); }
+void SchemaStatistic::setDesc(const char* desc) { impl->setDesc(desc); }
+const char* SchemaStatistic::getName() const { return impl->getName().c_str(); }
+Typecode SchemaStatistic::getType() const { return impl->getType(); }
+const char* SchemaStatistic::getUnit() const { return impl->getUnit().c_str(); }
+const char* SchemaStatistic::getDesc() const { return impl->getDesc().c_str(); }
+SchemaClassKey::SchemaClassKey(SchemaClassKeyImpl* i) : impl(i) {}
+SchemaClassKey::~SchemaClassKey() { delete impl; }
+const char* SchemaClassKey::getPackageName() const { return impl->getPackageName().c_str(); }
+const char* SchemaClassKey::getClassName() const { return impl->getClassName().c_str(); }
+const uint8_t* SchemaClassKey::getHash() const { return impl->getHash(); }
+SchemaObjectClass::SchemaObjectClass(const char* package, const char* name) { impl = new SchemaObjectClassImpl(this, package, name); }
SchemaObjectClass::SchemaObjectClass(SchemaObjectClassImpl* i) : impl(i) {}
-
-SchemaObjectClass::~SchemaObjectClass()
-{
- delete impl;
-}
-
-void SchemaObjectClass::addProperty(const SchemaProperty& property)
-{
- impl->addProperty(property);
-}
-
-void SchemaObjectClass::addStatistic(const SchemaStatistic& statistic)
-{
- impl->addStatistic(statistic);
-}
-
-void SchemaObjectClass::addMethod(const SchemaMethod& method)
-{
- impl->addMethod(method);
-}
-
-const char* SchemaObjectClass::getPackage() const
-{
- return impl->getPackage().c_str();
-}
-
-const char* SchemaObjectClass::getName() const
-{
- return impl->getName().c_str();
-}
-
-const uint8_t* SchemaObjectClass::getHash() const
-{
- return impl->getHash();
-}
-
-int SchemaObjectClass::getPropertyCount() const
-{
- return impl->getPropertyCount();
-}
-
-int SchemaObjectClass::getStatisticCount() const
-{
- return impl->getStatisticCount();
-}
-
-int SchemaObjectClass::getMethodCount() const
-{
- return impl->getMethodCount();
-}
-
-const SchemaProperty* SchemaObjectClass::getProperty(int idx) const
-{
- return impl->getProperty(idx);
-}
-
-const SchemaStatistic* SchemaObjectClass::getStatistic(int idx) const
-{
- return impl->getStatistic(idx);
-}
-
-const SchemaMethod* SchemaObjectClass::getMethod(int idx) const
-{
- return impl->getMethod(idx);
-}
-
-SchemaEventClass::SchemaEventClass(const char* package, const char* name)
-{
- impl = new SchemaEventClassImpl(this, package, name);
-}
-
+SchemaObjectClass::~SchemaObjectClass() { delete impl; }
+void SchemaObjectClass::addProperty(const SchemaProperty& property) { impl->addProperty(property); }
+void SchemaObjectClass::addStatistic(const SchemaStatistic& statistic) { impl->addStatistic(statistic); }
+void SchemaObjectClass::addMethod(const SchemaMethod& method) { impl->addMethod(method); }
+const SchemaClassKey* SchemaObjectClass::getClassKey() const { return impl->getClassKey(); }
+int SchemaObjectClass::getPropertyCount() const { return impl->getPropertyCount(); }
+int SchemaObjectClass::getStatisticCount() const { return impl->getStatisticCount(); }
+int SchemaObjectClass::getMethodCount() const { return impl->getMethodCount(); }
+const SchemaProperty* SchemaObjectClass::getProperty(int idx) const { return impl->getProperty(idx); }
+const SchemaStatistic* SchemaObjectClass::getStatistic(int idx) const { return impl->getStatistic(idx); }
+const SchemaMethod* SchemaObjectClass::getMethod(int idx) const { return impl->getMethod(idx); }
+SchemaEventClass::SchemaEventClass(const char* package, const char* name) { impl = new SchemaEventClassImpl(this, package, name); }
SchemaEventClass::SchemaEventClass(SchemaEventClassImpl* i) : impl(i) {}
-
-SchemaEventClass::~SchemaEventClass()
-{
- delete impl;
-}
-
-void SchemaEventClass::addArgument(const SchemaArgument& argument)
-{
- impl->addArgument(argument);
-}
-
-void SchemaEventClass::setDesc(const char* desc)
-{
- impl->setDesc(desc);
-}
-
-const char* SchemaEventClass::getPackage() const
-{
- return impl->getPackage().c_str();
-}
-
-const char* SchemaEventClass::getName() const
-{
- return impl->getName().c_str();
-}
-
-const uint8_t* SchemaEventClass::getHash() const
-{
- return impl->getHash();
-}
-
-int SchemaEventClass::getArgumentCount() const
-{
- return impl->getArgumentCount();
-}
-
-const SchemaArgument* SchemaEventClass::getArgument(int idx) const
-{
- return impl->getArgument(idx);
-}
+SchemaEventClass::~SchemaEventClass() { delete impl; }
+void SchemaEventClass::addArgument(const SchemaArgument& argument) { impl->addArgument(argument); }
+void SchemaEventClass::setDesc(const char* desc) { impl->setDesc(desc); }
+const SchemaClassKey* SchemaEventClass::getClassKey() const { return impl->getClassKey(); }
+int SchemaEventClass::getArgumentCount() const { return impl->getArgumentCount(); }
+const SchemaArgument* SchemaEventClass::getArgument(int idx) const { return impl->getArgument(idx); }
diff --git a/qpid/cpp/src/qmf/SchemaImpl.h b/qpid/cpp/src/qmf/SchemaImpl.h
index 2c30a8851f..3e9677d1fa 100644
--- a/qpid/cpp/src/qmf/SchemaImpl.h
+++ b/qpid/cpp/src/qmf/SchemaImpl.h
@@ -21,6 +21,7 @@
*/
#include "qmf/Schema.h"
+#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
#include <qpid/framing/Buffer.h>
@@ -35,7 +36,7 @@ namespace qmf {
uint8_t hash[16];
public:
SchemaHash();
- void encode(qpid::framing::Buffer& buffer);
+ void encode(qpid::framing::Buffer& buffer) const;
void decode(qpid::framing::Buffer& buffer);
void update(const char* data, uint32_t len);
void update(uint8_t data);
@@ -45,6 +46,9 @@ namespace qmf {
void update(Access a) { update((uint8_t) a); }
void update(bool b) { update((uint8_t) (b ? 1 : 0)); }
const uint8_t* get() const { return hash; }
+ bool operator==(const SchemaHash& other) const;
+ bool operator<(const SchemaHash& other) const;
+ bool operator>(const SchemaHash& other) const;
};
struct SchemaArgumentImpl {
@@ -138,27 +142,45 @@ namespace qmf {
void updateHash(SchemaHash& hash) const;
};
+ struct SchemaClassKeyImpl {
+ const SchemaClassKey* envelope;
+ const std::string& package;
+ const std::string& name;
+ const SchemaHash& hash;
+
+ SchemaClassKeyImpl(const std::string& package, const std::string& name, const SchemaHash& hash);
+
+ const std::string& getPackageName() const { return package; }
+ const std::string& getClassName() const { return name; }
+ const uint8_t* getHash() const { return hash.get(); }
+
+ void encode(qpid::framing::Buffer& buffer) const;
+ bool operator==(const SchemaClassKeyImpl& other) const;
+ bool operator<(const SchemaClassKeyImpl& other) const;
+ std::string str() const;
+ };
+
struct SchemaObjectClassImpl {
+ typedef boost::shared_ptr<SchemaObjectClassImpl> Ptr;
SchemaObjectClass* envelope;
std::string package;
std::string name;
mutable SchemaHash hash;
mutable bool hasHash;
+ SchemaClassKeyImpl classKey;
std::vector<SchemaPropertyImpl*> properties;
std::vector<SchemaStatisticImpl*> statistics;
std::vector<SchemaMethodImpl*> methods;
SchemaObjectClassImpl(SchemaObjectClass* e, const char* p, const char* n) :
- envelope(e), package(p), name(n), hasHash(false) {}
+ envelope(e), package(p), name(n), hasHash(false), classKey(package, name, hash) {}
SchemaObjectClassImpl(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
void addProperty(const SchemaProperty& property);
void addStatistic(const SchemaStatistic& statistic);
void addMethod(const SchemaMethod& method);
- const std::string& getPackage() const { return package; }
- const std::string& getName() const { return name; }
- const uint8_t* getHash() const;
+ const SchemaClassKey* getClassKey() const;
int getPropertyCount() const { return properties.size(); }
int getStatisticCount() const { return statistics.size(); }
int getMethodCount() const { return methods.size(); }
@@ -168,24 +190,24 @@ namespace qmf {
};
struct SchemaEventClassImpl {
+ typedef boost::shared_ptr<SchemaEventClassImpl> Ptr;
SchemaEventClass* envelope;
std::string package;
std::string name;
mutable SchemaHash hash;
mutable bool hasHash;
+ SchemaClassKeyImpl classKey;
std::string description;
std::vector<SchemaArgumentImpl*> arguments;
SchemaEventClassImpl(SchemaEventClass* e, const char* p, const char* n) :
- envelope(e), package(p), name(n), hasHash(false) {}
+ envelope(e), package(p), name(n), hasHash(false), classKey(package, name, hash) {}
SchemaEventClassImpl(qpid::framing::Buffer& buffer);
void encode(qpid::framing::Buffer& buffer) const;
void addArgument(const SchemaArgument& argument);
void setDesc(const char* desc) { description = desc; }
- const std::string& getPackage() const { return package; }
- const std::string& getName() const { return name; }
- const uint8_t* getHash() const;
+ const SchemaClassKey* getClassKey() const;
int getArgumentCount() const { return arguments.size(); }
const SchemaArgument* getArgument(int idx) const;
};
diff --git a/qpid/cpp/src/qmf/SequenceManager.cpp b/qpid/cpp/src/qmf/SequenceManager.cpp
new file mode 100644
index 0000000000..f51ce9d8b8
--- /dev/null
+++ b/qpid/cpp/src/qmf/SequenceManager.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 "qmf/SequenceManager.h"
+
+using namespace std;
+using namespace qmf;
+using namespace qpid::sys;
+
+SequenceManager::SequenceManager() : nextSequence(1) {}
+
+uint32_t SequenceManager::reserve(SequenceContext* ctx)
+{
+ Mutex::ScopedLock _lock(lock);
+ uint32_t seq = nextSequence;
+ while (contextMap.find(seq) != contextMap.end())
+ seq = seq < 0xFFFFFFFF ? seq + 1 : 1;
+ nextSequence = seq < 0xFFFFFFFF ? seq + 1 : 1;
+ contextMap[seq] = ctx;
+ return seq;
+}
+
+void SequenceManager::release(uint32_t sequence)
+{
+ Mutex::ScopedLock _lock(lock);
+ map<uint32_t, SequenceContext*>::iterator iter = contextMap.find(sequence);
+ if (iter != contextMap.end()) {
+ if (iter->second != 0)
+ iter->second->complete();
+ contextMap.erase(iter);
+ }
+}
+
+
diff --git a/qpid/cpp/src/qmf/SequenceManager.h b/qpid/cpp/src/qmf/SequenceManager.h
new file mode 100644
index 0000000000..c027872313
--- /dev/null
+++ b/qpid/cpp/src/qmf/SequenceManager.h
@@ -0,0 +1,52 @@
+#ifndef _QmfSequenceManager_
+#define _QmfSequenceManager_
+
+/*
+ * 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 "qpid/sys/Mutex.h"
+#include <map>
+
+namespace qmf {
+
+ class SequenceContext {
+ public:
+ SequenceContext() {}
+ virtual ~SequenceContext() {}
+
+ virtual void complete() = 0;
+ };
+
+ class SequenceManager {
+ public:
+ SequenceManager();
+
+ uint32_t reserve(SequenceContext* ctx);
+ void release(uint32_t sequence);
+
+ private:
+ mutable qpid::sys::Mutex lock;
+ uint32_t nextSequence;
+ std::map<uint32_t, SequenceContext*> contextMap;
+ };
+
+}
+
+#endif
+
diff --git a/qpid/cpp/src/qmf/Value.h b/qpid/cpp/src/qmf/Value.h
index a45df14ea9..bb946d31d3 100644
--- a/qpid/cpp/src/qmf/Value.h
+++ b/qpid/cpp/src/qmf/Value.h
@@ -30,7 +30,7 @@ namespace qmf {
class Value {
public:
- Value();
+ // Value();
Value(Typecode t, Typecode arrayType = TYPE_UINT8);
Value(ValueImpl* impl);
~Value();
diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
index 4a6590fb5f..093e9cea32 100644
--- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
+++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp
@@ -435,8 +435,8 @@ void ManagementAgentImpl::invokeMethodRequest(Buffer& inBuffer, uint32_t sequenc
} else {
if ((iter->second->getPackageName() != packageName) ||
(iter->second->getClassName() != className)) {
- outBuffer.putLong (Manageable::STATUS_INVALID_PARAMETER);
- outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_INVALID_PARAMETER));
+ outBuffer.putLong (Manageable::STATUS_PARAMETER_INVALID);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_PARAMETER_INVALID));
}
else
try {
diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp
index 8b6cb5e049..13cf88fb11 100644
--- a/qpid/cpp/src/qpid/broker/Broker.cpp
+++ b/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -386,7 +386,7 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId,
if (queueMoveMessages(moveArgs.i_srcQueue, moveArgs.i_destQueue, moveArgs.i_qty))
status = Manageable::STATUS_OK;
else
- return Manageable::STATUS_INVALID_PARAMETER;
+ return Manageable::STATUS_PARAMETER_INVALID;
break;
}
default:
diff --git a/qpid/cpp/src/qpid/broker/Connection.cpp b/qpid/cpp/src/qpid/broker/Connection.cpp
index a1a3c6ada7..3b8a6c71d4 100644
--- a/qpid/cpp/src/qpid/broker/Connection.cpp
+++ b/qpid/cpp/src/qpid/broker/Connection.cpp
@@ -269,11 +269,13 @@ bool Connection::doOutput() {
cb(); // Lend the IO thread for management processing
}
}
- if (mgmtClosing)
+ if (mgmtClosing) {
+ closed();
close(connection::CLOSE_CODE_CONNECTION_FORCED, "Closed by Management Request");
- else
+ } else {
//then do other output as needed:
return outputTasks.doOutput();
+ }
}catch(ConnectionException& e){
close(e.code, e.getMessage());
}catch(std::exception& e){
diff --git a/qpid/cpp/src/qpid/broker/Daemon.cpp b/qpid/cpp/src/qpid/broker/Daemon.cpp
index aa8dd8855b..21848e23de 100644
--- a/qpid/cpp/src/qpid/broker/Daemon.cpp
+++ b/qpid/cpp/src/qpid/broker/Daemon.cpp
@@ -85,7 +85,7 @@ void Daemon::fork()
child();
}
catch (const exception& e) {
- QPID_LOG(critical, "Daemon startup failed: " << e.what());
+ QPID_LOG(critical, "Unexpected error: " << e.what());
uint16_t port = 0;
int unused_ret; //Supress warning about ignoring return value.
unused_ret = write(pipeFds[1], &port, sizeof(uint16_t));
diff --git a/qpid/cpp/src/qpid/broker/Exchange.cpp b/qpid/cpp/src/qpid/broker/Exchange.cpp
index 17fc0e23ca..b1fc1295f3 100644
--- a/qpid/cpp/src/qpid/broker/Exchange.cpp
+++ b/qpid/cpp/src/qpid/broker/Exchange.cpp
@@ -91,7 +91,9 @@ Exchange::Exchange (const string& _name, Manageable* parent, Broker* b) :
ManagementAgent* agent = broker->getManagementAgent();
if (agent != 0)
{
- mgmtExchange = new _qmf::Exchange (agent, this, parent, _name, durable);
+ mgmtExchange = new _qmf::Exchange (agent, this, parent, _name);
+ mgmtExchange->set_durable(durable);
+ mgmtExchange->set_autoDelete(false);
agent->addObject (mgmtExchange);
}
}
@@ -109,7 +111,9 @@ Exchange::Exchange(const string& _name, bool _durable, const qpid::framing::Fiel
ManagementAgent* agent = broker->getManagementAgent();
if (agent != 0)
{
- mgmtExchange = new _qmf::Exchange (agent, this, parent, _name, durable);
+ mgmtExchange = new _qmf::Exchange (agent, this, parent, _name);
+ mgmtExchange->set_durable(durable);
+ mgmtExchange->set_autoDelete(false);
mgmtExchange->set_arguments(args);
if (!durable) {
if (name.empty()) {
@@ -139,6 +143,17 @@ Exchange::~Exchange ()
mgmtExchange->resourceDestroy ();
}
+void Exchange::setAlternate(Exchange::shared_ptr _alternate)
+{
+ alternate = _alternate;
+ if (mgmtExchange != 0) {
+ if (alternate.get() != 0)
+ mgmtExchange->set_altExchange(alternate->GetManagementObject()->getObjectId());
+ else
+ mgmtExchange->clr_altExchange();
+ }
+}
+
void Exchange::setPersistenceId(uint64_t id) const
{
if (mgmtExchange != 0 && persistenceId == 0)
diff --git a/qpid/cpp/src/qpid/broker/Exchange.h b/qpid/cpp/src/qpid/broker/Exchange.h
index ca8525d55e..c1e878200f 100644
--- a/qpid/cpp/src/qpid/broker/Exchange.h
+++ b/qpid/cpp/src/qpid/broker/Exchange.h
@@ -132,7 +132,7 @@ public:
qpid::framing::FieldTable& getArgs() { return args; }
Exchange::shared_ptr getAlternate() { return alternate; }
- void setAlternate(Exchange::shared_ptr _alternate) { alternate = _alternate; }
+ void setAlternate(Exchange::shared_ptr _alternate);
void incAlternateUsers() { alternateUsers++; }
void decAlternateUsers() { alternateUsers--; }
bool inUseAsAlternate() { return alternateUsers > 0; }
diff --git a/qpid/cpp/src/qpid/broker/Link.cpp b/qpid/cpp/src/qpid/broker/Link.cpp
index 9ce0c710bd..cdba18ccf9 100644
--- a/qpid/cpp/src/qpid/broker/Link.cpp
+++ b/qpid/cpp/src/qpid/broker/Link.cpp
@@ -200,8 +200,10 @@ void Link::destroy ()
// Move the bridges to be deleted into a local vector so there is no
// corruption of the iterator caused by bridge deletion.
- for (Bridges::iterator i = active.begin(); i != active.end(); i++)
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ (*i)->closed();
toDelete.push_back(*i);
+ }
active.clear();
for (Bridges::iterator i = created.begin(); i != created.end(); i++)
@@ -264,7 +266,6 @@ void Link::ioThreadProcessing()
}
if (!cancellations.empty()) {
for (Bridges::iterator i = cancellations.begin(); i != cancellations.end(); ++i) {
- active.push_back(*i);
(*i)->cancel(*connection);
}
cancellations.clear();
diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
index b0c5e9ea00..af07605552 100644
--- a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
+++ b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -121,9 +121,11 @@ void SessionAdapter::ExchangeHandlerImpl::checkType(Exchange::shared_ptr exchang
void SessionAdapter::ExchangeHandlerImpl::checkAlternate(Exchange::shared_ptr exchange, Exchange::shared_ptr alternate)
{
- if (alternate && alternate != exchange->getAlternate())
+ if (alternate && ((exchange->getAlternate() && alternate != exchange->getAlternate())
+ || !exchange->getAlternate()))
throw NotAllowedException(QPID_MSG("Exchange declared with alternate-exchange "
- << exchange->getAlternate()->getName() << ", requested "
+ << (exchange->getAlternate() ? exchange->getAlternate()->getName() : "<nonexistent>")
+ << ", requested "
<< alternate->getName()));
}
diff --git a/qpid/cpp/src/qpid/client/Demux.h b/qpid/cpp/src/qpid/client/Demux.h
index 7304e799bb..31dc3f9c06 100644
--- a/qpid/cpp/src/qpid/client/Demux.h
+++ b/qpid/cpp/src/qpid/client/Demux.h
@@ -25,6 +25,7 @@
#include "qpid/framing/FrameSet.h"
#include "qpid/sys/Mutex.h"
#include "qpid/sys/BlockingQueue.h"
+#include "qpid/client/ClientImportExport.h"
#ifndef _Demux_
#define _Demux_
@@ -49,17 +50,17 @@ public:
typedef sys::BlockingQueue<framing::FrameSet::shared_ptr> Queue;
typedef boost::shared_ptr<Queue> QueuePtr;
- Demux();
- ~Demux();
+ QPID_CLIENT_EXTERN Demux();
+ QPID_CLIENT_EXTERN ~Demux();
- void handle(framing::FrameSet::shared_ptr);
- void close(const sys::ExceptionHolder& ex);
- void open();
-
- QueuePtr add(const std::string& name, Condition);
- void remove(const std::string& name);
- QueuePtr get(const std::string& name);
- QueuePtr getDefault();
+ QPID_CLIENT_EXTERN void handle(framing::FrameSet::shared_ptr);
+ QPID_CLIENT_EXTERN void close(const sys::ExceptionHolder& ex);
+ QPID_CLIENT_EXTERN void open();
+
+ QPID_CLIENT_EXTERN QueuePtr add(const std::string& name, Condition);
+ QPID_CLIENT_EXTERN void remove(const std::string& name);
+ QPID_CLIENT_EXTERN QueuePtr get(const std::string& name);
+ QPID_CLIENT_EXTERN QueuePtr getDefault();
private:
struct Record
diff --git a/qpid/cpp/src/qpid/client/Results.cpp b/qpid/cpp/src/qpid/client/Results.cpp
index acb2684727..0de3e8bd04 100644
--- a/qpid/cpp/src/qpid/client/Results.cpp
+++ b/qpid/cpp/src/qpid/client/Results.cpp
@@ -24,7 +24,6 @@
#include "qpid/framing/SequenceSet.h"
using namespace qpid::framing;
-using namespace boost;
namespace qpid {
namespace client {
diff --git a/qpid/cpp/src/qpid/client/SessionImpl.cpp b/qpid/cpp/src/qpid/client/SessionImpl.cpp
index 43b62ec6dc..8ead44a172 100644
--- a/qpid/cpp/src/qpid/client/SessionImpl.cpp
+++ b/qpid/cpp/src/qpid/client/SessionImpl.cpp
@@ -202,6 +202,16 @@ bool SessionImpl::isCompleteUpTo(const SequenceNumber& id)
return f.result;
}
+framing::SequenceNumber SessionImpl::getCompleteUpTo()
+{
+ SequenceNumber firstIncomplete;
+ {
+ Lock l(state);
+ firstIncomplete = incompleteIn.front();
+ }
+ return --firstIncomplete;
+}
+
struct MarkCompleted
{
const SequenceNumber& id;
@@ -319,7 +329,7 @@ struct MethodContentAdaptor : MethodContent
}
-Future SessionImpl::send(const AMQBody& command, const FrameSet& content) {
+Future SessionImpl::send(const AMQBody& command, const FrameSet& content, bool reframe) {
Acquire a(sendLock);
SequenceNumber id = nextOut++;
{
@@ -337,7 +347,7 @@ Future SessionImpl::send(const AMQBody& command, const FrameSet& content) {
frame.setEof(false);
handleOut(frame);
- if (content.isComplete()) {
+ if (reframe) {
MethodContentAdaptor c(content);
sendContent(c);
} else {
diff --git a/qpid/cpp/src/qpid/client/SessionImpl.h b/qpid/cpp/src/qpid/client/SessionImpl.h
index cae1148e9f..49d268c44d 100644
--- a/qpid/cpp/src/qpid/client/SessionImpl.h
+++ b/qpid/cpp/src/qpid/client/SessionImpl.h
@@ -25,6 +25,7 @@
#include "qpid/client/Demux.h"
#include "qpid/client/Execution.h"
#include "qpid/client/Results.h"
+#include "qpid/client/ClientImportExport.h"
#include "qpid/SessionId.h"
#include "qpid/SessionState.h"
@@ -86,7 +87,15 @@ public:
Future send(const framing::AMQBody& command);
Future send(const framing::AMQBody& command, const framing::MethodContent& content);
- Future send(const framing::AMQBody& command, const framing::FrameSet& content);
+ /**
+ * This method takes the content as a FrameSet; if reframe=false,
+ * the caller is resposnible for ensuring that the header and
+ * content frames in that set are correct for this connection
+ * (right flags, right fragmentation etc). If reframe=true, then
+ * the header and content from the frameset will be copied and
+ * reframed correctly for the connection.
+ */
+ QPID_CLIENT_EXTERN Future send(const framing::AMQBody& command, const framing::FrameSet& content, bool reframe=false);
void sendRawFrame(framing::AMQFrame& frame);
Demux& getDemux();
@@ -94,6 +103,7 @@ public:
void markCompleted(const framing::SequenceSet& ids, bool notifyPeer);
bool isComplete(const framing::SequenceNumber& id);
bool isCompleteUpTo(const framing::SequenceNumber& id);
+ framing::SequenceNumber getCompleteUpTo();
void waitForCompletion(const framing::SequenceNumber& id);
void sendCompletion();
void sendFlush();
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
new file mode 100644
index 0000000000..9b9f06ec57
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
@@ -0,0 +1,461 @@
+/*
+ *
+ * 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 "qpid/client/amqp0_10/AddressResolution.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+#include "qpid/client/amqp0_10/MessageSource.h"
+#include "qpid/client/amqp0_10/MessageSink.h"
+#include "qpid/client/amqp0_10/OutgoingMessage.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Filter.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/enum.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/ReplyTo.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::Exception;
+using qpid::messaging::Address;
+using qpid::messaging::Filter;
+using qpid::messaging::Variant;
+using qpid::framing::FieldTable;
+using qpid::framing::ReplyTo;
+using namespace qpid::framing::message;
+
+
+namespace{
+const Variant EMPTY_VARIANT;
+const FieldTable EMPTY_FIELD_TABLE;
+const std::string EMPTY_STRING;
+
+//option names
+const std::string BROWSE("browse");
+const std::string EXCLUSIVE("exclusive");
+const std::string MODE("mode");
+const std::string NAME("name");
+const std::string UNACKNOWLEDGED("unacknowledged");
+
+const std::string QUEUE_ADDRESS("queue");
+const std::string TOPIC_ADDRESS("topic");
+const std::string TOPIC_ADDRESS_AND_SUBJECT("topic+");
+const std::string DIVIDER("/");
+
+const std::string SIMPLE_SUBSCRIPTION("simple");
+const std::string RELIABLE_SUBSCRIPTION("reliable");
+const std::string DURABLE_SUBSCRIPTION("durable");
+}
+
+class QueueSource : public MessageSource
+{
+ public:
+ QueueSource(const std::string& name, AcceptMode=ACCEPT_MODE_EXPLICIT, AcquireMode=ACQUIRE_MODE_PRE_ACQUIRED,
+ bool exclusive = false, const FieldTable& options = EMPTY_FIELD_TABLE);
+ void subscribe(qpid::client::AsyncSession& session, const std::string& destination);
+ void cancel(qpid::client::AsyncSession& session, const std::string& destination);
+ private:
+ const std::string name;
+ const AcceptMode acceptMode;
+ const AcquireMode acquireMode;
+ const bool exclusive;
+ const FieldTable options;
+};
+
+class Subscription : public MessageSource
+{
+ public:
+ enum SubscriptionMode {SIMPLE, RELIABLE, DURABLE};
+
+ Subscription(const std::string& name, SubscriptionMode mode = SIMPLE,
+ const FieldTable& queueOptions = EMPTY_FIELD_TABLE, const FieldTable& subscriptionOptions = EMPTY_FIELD_TABLE);
+ void add(const std::string& exchange, const std::string& key, const FieldTable& options = EMPTY_FIELD_TABLE);
+ void subscribe(qpid::client::AsyncSession& session, const std::string& destination);
+ void cancel(qpid::client::AsyncSession& session, const std::string& destination);
+
+ static SubscriptionMode getMode(const std::string& mode);
+ private:
+ struct Binding
+ {
+ Binding(const std::string& exchange, const std::string& key, const FieldTable& options = EMPTY_FIELD_TABLE);
+
+ std::string exchange;
+ std::string key;
+ FieldTable options;
+ };
+
+ typedef std::vector<Binding> Bindings;
+
+ const std::string name;
+ const bool autoDelete;
+ const bool durable;
+ const FieldTable queueOptions;
+ const FieldTable subscriptionOptions;
+ Bindings bindings;
+ std::string queue;
+};
+
+class Exchange : public MessageSink
+{
+ public:
+ Exchange(const std::string& name, const std::string& defaultSubject = EMPTY_STRING,
+ bool passive = true, const std::string& type = EMPTY_STRING, bool durable = false,
+ const FieldTable& options = EMPTY_FIELD_TABLE);
+ void declare(qpid::client::AsyncSession& session, const std::string& name);
+ void send(qpid::client::AsyncSession& session, const std::string& name, OutgoingMessage& message);
+ void cancel(qpid::client::AsyncSession& session, const std::string& name);
+ private:
+ const std::string name;
+ const std::string defaultSubject;
+ const bool passive;
+ const std::string type;
+ const bool durable;
+ const FieldTable options;
+};
+
+class QueueSink : public MessageSink
+{
+ public:
+ QueueSink(const std::string& name, bool passive=true, bool exclusive=false,
+ bool autoDelete=false, bool durable=false, const FieldTable& options = EMPTY_FIELD_TABLE);
+ void declare(qpid::client::AsyncSession& session, const std::string& name);
+ void send(qpid::client::AsyncSession& session, const std::string& name, OutgoingMessage& message);
+ void cancel(qpid::client::AsyncSession& session, const std::string& name);
+ private:
+ const std::string name;
+ const bool passive;
+ const bool exclusive;
+ const bool autoDelete;
+ const bool durable;
+ const FieldTable options;
+};
+
+
+bool isQueue(qpid::client::Session session, const qpid::messaging::Address& address);
+bool isTopic(qpid::client::Session session, const qpid::messaging::Address& address, std::string& subject);
+
+const Variant& getOption(const std::string& key, const Variant::Map& options)
+{
+ Variant::Map::const_iterator i = options.find(key);
+ if (i == options.end()) return EMPTY_VARIANT;
+ else return i->second;
+}
+
+std::auto_ptr<MessageSource> AddressResolution::resolveSource(qpid::client::Session session,
+ const Address& address,
+ const Filter* filter,
+ const Variant::Map& options)
+{
+ //TODO: handle case where there exists a queue and an exchange of
+ //the same name (hence an unqualified address is ambiguous)
+
+ //TODO: make sure specified address type gives sane error message
+ //if it does npt match the configuration on server
+
+ if (isQueue(session, address)) {
+ //TODO: support auto-created queue as source, if requested by specific option
+
+ AcceptMode accept = getOption(UNACKNOWLEDGED, options).asBool() ? ACCEPT_MODE_NONE : ACCEPT_MODE_EXPLICIT;
+ AcquireMode acquire = getOption(BROWSE, options).asBool() ? ACQUIRE_MODE_NOT_ACQUIRED : ACQUIRE_MODE_PRE_ACQUIRED;
+ bool exclusive = getOption(EXCLUSIVE, options).asBool();
+ FieldTable arguments;
+ //TODO: extract subscribe arguments from options (e.g. either
+ //filter out already processed keys and send the rest, or have
+ //a nested map)
+
+ std::auto_ptr<MessageSource> source =
+ std::auto_ptr<MessageSource>(new QueueSource(address.value, accept, acquire, exclusive, arguments));
+ return source;
+ } else {
+ //TODO: extract queue options (e.g. no-local) and subscription options (e.g. less important)
+ std::auto_ptr<Subscription> bindings =
+ std::auto_ptr<Subscription>(new Subscription(getOption(NAME, options).asString(),
+ Subscription::getMode(getOption(MODE, options).asString())));
+
+ qpid::framing::ExchangeQueryResult result = session.exchangeQuery(address.value);
+ if (result.getNotFound()) {
+ throw qpid::framing::NotFoundException(QPID_MSG("Address not known: " << address));
+ } else if (result.getType() == "topic") {
+ if (filter) {
+ if (filter->type != Filter::WILDCARD) {
+ throw qpid::framing::NotImplementedException(
+ QPID_MSG("Filters of type " << filter->type << " not supported by address " << address));
+
+ }
+ for (std::vector<std::string>::const_iterator i = filter->patterns.begin(); i != filter->patterns.end(); i++) {
+ bindings->add(address.value, *i, qpid::framing::FieldTable());
+ }
+ } else {
+ //default is to receive all messages
+ bindings->add(address.value, "*", qpid::framing::FieldTable());
+ }
+ } else if (result.getType() == "fanout") {
+ if (filter) {
+ throw qpid::framing::NotImplementedException(QPID_MSG("Filters are not supported by address " << address));
+ }
+ bindings->add(address.value, address.value, qpid::framing::FieldTable());
+ } else if (result.getType() == "direct") {
+ //TODO: ????
+ } else {
+ //TODO: xml and headers exchanges
+ throw qpid::framing::NotImplementedException(QPID_MSG("Address type not recognised for " << address));
+ }
+ std::auto_ptr<MessageSource> source = std::auto_ptr<MessageSource>(bindings.release());
+ return source;
+ }
+}
+
+
+std::auto_ptr<MessageSink> AddressResolution::resolveSink(qpid::client::Session session,
+ const qpid::messaging::Address& address,
+ const qpid::messaging::Variant::Map& /*options*/)
+{
+ std::auto_ptr<MessageSink> sink;
+ if (isQueue(session, address)) {
+ //TODO: support for auto-created queues as sink
+ sink = std::auto_ptr<MessageSink>(new QueueSink(address.value));
+ } else {
+ std::string subject;
+ if (isTopic(session, address, subject)) {
+ //TODO: support for auto-created exchanges as sink
+ sink = std::auto_ptr<MessageSink>(new Exchange(address.value, subject));
+ } else {
+ if (address.type.empty()) {
+ throw qpid::framing::NotFoundException(QPID_MSG("Address not known: " << address));
+ } else {
+ throw qpid::framing::NotImplementedException(QPID_MSG("Address type not recognised: " << address.type));
+ }
+ }
+ }
+ return sink;
+}
+
+QueueSource::QueueSource(const std::string& _name, AcceptMode _acceptMode, AcquireMode _acquireMode, bool _exclusive, const FieldTable& _options) :
+ name(_name), acceptMode(_acceptMode), acquireMode(_acquireMode), exclusive(_exclusive), options(_options) {}
+
+void QueueSource::subscribe(qpid::client::AsyncSession& session, const std::string& destination)
+{
+ session.messageSubscribe(arg::queue=name,
+ arg::destination=destination,
+ arg::acceptMode=acceptMode,
+ arg::acquireMode=acquireMode,
+ arg::exclusive=exclusive,
+ arg::arguments=options);
+}
+
+void QueueSource::cancel(qpid::client::AsyncSession& session, const std::string& destination)
+{
+ session.messageCancel(destination);
+}
+
+Subscription::Subscription(const std::string& _name, SubscriptionMode mode, const FieldTable& qOptions, const FieldTable& sOptions)
+ : name(_name), autoDelete(mode == SIMPLE), durable(mode == DURABLE),
+ queueOptions(qOptions), subscriptionOptions(sOptions) {}
+
+void Subscription::add(const std::string& exchange, const std::string& key, const FieldTable& options)
+{
+ bindings.push_back(Binding(exchange, key, options));
+}
+
+void Subscription::subscribe(qpid::client::AsyncSession& session, const std::string& destination)
+{
+ if (name.empty()) {
+ //TODO: use same scheme as JMS client for subscription queue name generation?
+ queue = session.getId().getName() + destination;
+ } else {
+ queue = name;
+ }
+ session.queueDeclare(arg::queue=queue, arg::exclusive=true,
+ arg::autoDelete=autoDelete, arg::durable=durable, arg::arguments=queueOptions);
+ for (Bindings::const_iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ session.exchangeBind(arg::queue=queue, arg::exchange=i->exchange, arg::bindingKey=i->key, arg::arguments=i->options);
+ }
+ AcceptMode accept = autoDelete ? ACCEPT_MODE_NONE : ACCEPT_MODE_EXPLICIT;
+ session.messageSubscribe(arg::queue=queue, arg::destination=destination,
+ arg::exclusive=true, arg::acceptMode=accept, arg::arguments=subscriptionOptions);
+}
+
+void Subscription::cancel(qpid::client::AsyncSession& session, const std::string& destination)
+{
+ session.messageCancel(destination);
+ session.queueDelete(arg::queue=queue);
+}
+
+Subscription::Binding::Binding(const std::string& e, const std::string& k, const FieldTable& o):
+ exchange(e), key(k), options(o) {}
+
+Subscription::SubscriptionMode Subscription::getMode(const std::string& s)
+{
+ if (s.empty() || s == SIMPLE_SUBSCRIPTION) return SIMPLE;
+ else if (s == RELIABLE_SUBSCRIPTION) return RELIABLE;
+ else if (s == DURABLE_SUBSCRIPTION) return DURABLE;
+ else throw Exception(QPID_MSG("Unrecognised subscription mode: " << s));
+}
+
+void convert(qpid::messaging::Message& from, qpid::client::Message& to);
+
+Exchange::Exchange(const std::string& _name, const std::string& _defaultSubject,
+ bool _passive, const std::string& _type, bool _durable, const FieldTable& _options) :
+ name(_name), defaultSubject(_defaultSubject), passive(_passive), type(_type), durable(_durable), options(_options) {}
+
+void Exchange::declare(qpid::client::AsyncSession& session, const std::string&)
+{
+ //TODO: should this really by synchronous? want to get error if not valid...
+ if (passive) {
+ sync(session).exchangeDeclare(arg::exchange=name, arg::passive=true);
+ } else {
+ sync(session).exchangeDeclare(arg::exchange=name, arg::type=type, arg::durable=durable, arg::arguments=options);
+ }
+}
+
+void Exchange::send(qpid::client::AsyncSession& session, const std::string&, OutgoingMessage& m)
+{
+ if (m.message.getDeliveryProperties().getRoutingKey().empty() && !defaultSubject.empty()) {
+ m.message.getDeliveryProperties().setRoutingKey(defaultSubject);
+ }
+ m.status = session.messageTransfer(arg::destination=name, arg::content=m.message);
+}
+
+void Exchange::cancel(qpid::client::AsyncSession&, const std::string&) {}
+
+QueueSink::QueueSink(const std::string& _name, bool _passive, bool _exclusive,
+ bool _autoDelete, bool _durable, const FieldTable& _options) :
+ name(_name), passive(_passive), exclusive(_exclusive),
+ autoDelete(_autoDelete), durable(_durable), options(_options) {}
+
+void QueueSink::declare(qpid::client::AsyncSession& session, const std::string&)
+{
+ //TODO: should this really by synchronous?
+ if (passive) {
+ sync(session).queueDeclare(arg::queue=name, arg::passive=true);
+ } else {
+ sync(session).queueDeclare(arg::queue=name, arg::exclusive=exclusive, arg::durable=durable,
+ arg::autoDelete=autoDelete, arg::arguments=options);
+ }
+}
+void QueueSink::send(qpid::client::AsyncSession& session, const std::string&, OutgoingMessage& m)
+{
+ m.message.getDeliveryProperties().setRoutingKey(name);
+ m.status = session.messageTransfer(arg::content=m.message);
+}
+
+void QueueSink::cancel(qpid::client::AsyncSession&, const std::string&) {}
+
+template <class T> void encode(qpid::messaging::Message& from)
+{
+ T codec;
+ from.encode(codec);
+ from.setContentType(T::contentType);
+}
+
+void translate(const Variant::Map& from, FieldTable& to);//implementation in Codecs.cpp
+
+void convert(qpid::messaging::Message& from, qpid::client::Message& to)
+{
+ //TODO: need to avoid copying as much as possible
+ if (from.getContent().isList()) encode<ListCodec>(from);
+ if (from.getContent().isMap()) encode<MapCodec>(from);
+ to.setData(from.getBytes());
+ to.getDeliveryProperties().setRoutingKey(from.getSubject());
+ //TODO: set other delivery properties
+ to.getMessageProperties().setContentType(from.getContentType());
+ const Address& address = from.getReplyTo();
+ if (!address.value.empty()) {
+ to.getMessageProperties().setReplyTo(AddressResolution::convert(address));
+ }
+ translate(from.getHeaders(), to.getMessageProperties().getApplicationHeaders());
+ //TODO: set other message properties
+}
+
+Address AddressResolution::convert(const qpid::framing::ReplyTo& rt)
+{
+ if (rt.getExchange().empty()) {
+ if (rt.getRoutingKey().empty()) {
+ return Address();//empty address
+ } else {
+ return Address(rt.getRoutingKey(), QUEUE_ADDRESS);
+ }
+ } else {
+ if (rt.getRoutingKey().empty()) {
+ return Address(rt.getExchange(), TOPIC_ADDRESS);
+ } else {
+ return Address(rt.getExchange() + DIVIDER + rt.getRoutingKey(), TOPIC_ADDRESS_AND_SUBJECT);
+ }
+ }
+}
+
+qpid::framing::ReplyTo AddressResolution::convert(const Address& address)
+{
+ if (address.type == QUEUE_ADDRESS || address.type.empty()) {
+ return ReplyTo(EMPTY_STRING, address.value);
+ } else if (address.type == TOPIC_ADDRESS) {
+ return ReplyTo(address.value, EMPTY_STRING);
+ } else if (address.type == TOPIC_ADDRESS_AND_SUBJECT) {
+ //need to split the value
+ string::size_type i = address.value.find(DIVIDER);
+ if (i != string::npos) {
+ std::string exchange = address.value.substr(0, i);
+ std::string routingKey;
+ if (i+1 < address.value.size()) {
+ routingKey = address.value.substr(i+1);
+ }
+ return ReplyTo(exchange, routingKey);
+ } else {
+ return ReplyTo(address.value, EMPTY_STRING);
+ }
+ } else {
+ QPID_LOG(notice, "Unrecognised type for reply-to: " << address.type);
+ //treat as queue
+ return ReplyTo(EMPTY_STRING, address.value);
+ }
+}
+
+bool isQueue(qpid::client::Session session, const qpid::messaging::Address& address)
+{
+ return address.type == QUEUE_ADDRESS ||
+ (address.type.empty() && session.queueQuery(address.value).getQueue() == address.value);
+}
+
+bool isTopic(qpid::client::Session session, const qpid::messaging::Address& address, std::string& subject)
+{
+ if (address.type.empty()) {
+ return !session.exchangeQuery(address.value).getNotFound();
+ } else if (address.type == TOPIC_ADDRESS) {
+ return true;
+ } else if (address.type == TOPIC_ADDRESS_AND_SUBJECT) {
+ string::size_type i = address.value.find(DIVIDER);
+ if (i != string::npos) {
+ std::string exchange = address.value.substr(0, i);
+ if (i+1 < address.value.size()) {
+ subject = address.value.substr(i+1);
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.h b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.h
new file mode 100644
index 0000000000..9d5657450d
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.h
@@ -0,0 +1,68 @@
+#ifndef QPID_CLIENT_AMQP0_10_ADDRESSRESOLUTION_H
+#define QPID_CLIENT_AMQP0_10_ADDRESSRESOLUTION_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/Session.h"
+
+namespace qpid {
+
+namespace framing{
+class ReplyTo;
+}
+
+namespace messaging {
+struct Address;
+struct Filter;
+}
+
+namespace client {
+namespace amqp0_10 {
+
+class MessageSource;
+class MessageSink;
+
+/**
+ * Maps from a generic Address and optional Filter to an AMQP 0-10
+ * MessageSource which will then be used by a ReceiverImpl instance
+ * created for the address.
+ */
+class AddressResolution
+{
+ public:
+ std::auto_ptr<MessageSource> resolveSource(qpid::client::Session session,
+ const qpid::messaging::Address& address,
+ const qpid::messaging::Filter* filter,
+ const qpid::messaging::Variant::Map& options);
+
+ std::auto_ptr<MessageSink> resolveSink(qpid::client::Session session,
+ const qpid::messaging::Address& address,
+ const qpid::messaging::Variant::Map& options);
+
+ static qpid::messaging::Address convert(const qpid::framing::ReplyTo&);
+ static qpid::framing::ReplyTo convert(const qpid::messaging::Address&);
+
+ private:
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_ADDRESSRESOLUTION_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp b/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp
new file mode 100644
index 0000000000..57184e3937
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/Codecs.cpp
@@ -0,0 +1,299 @@
+/*
+ *
+ * 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 "qpid/client/amqp0_10/Codecs.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/List.h"
+#include <algorithm>
+#include <functional>
+
+using namespace qpid::framing;
+using namespace qpid::messaging;
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+namespace {
+const std::string iso885915("iso-8859-15");
+const std::string utf8("utf8");
+const std::string utf16("utf16");
+const std::string amqp0_10_binary("amqp0-10:binary");
+const std::string amqp0_10_bit("amqp0-10:bit");
+const std::string amqp0_10_datetime("amqp0-10:datetime");
+const std::string amqp0_10_struct("amqp0-10:struct");
+}
+
+template <class T, class U, class F> void convert(const T& from, U& to, F f)
+{
+ std::transform(from.begin(), from.end(), std::inserter(to, to.begin()), f);
+}
+
+Variant::Map::value_type toVariantMapEntry(const FieldTable::value_type& in);
+FieldTable::value_type toFieldTableEntry(const Variant::Map::value_type& in);
+Variant toVariant(boost::shared_ptr<FieldValue> in);
+boost::shared_ptr<FieldValue> toFieldValue(const Variant& in);
+
+template <class T, class U, class F> void translate(boost::shared_ptr<FieldValue> in, U& u, F f)
+{
+ T t;
+ getEncodedValue<T>(in, t);
+ convert(t, u, f);
+}
+
+template <class T, class U, class F> T* toFieldValueCollection(const U& u, F f)
+{
+ typename T::ValueType t;
+ convert(u, t, f);
+ return new T(t);
+}
+
+FieldTableValue* toFieldTableValue(const Variant::Map& map)
+{
+ FieldTable ft;
+ convert(map, ft, &toFieldTableEntry);
+ return new FieldTableValue(ft);
+}
+
+ListValue* toListValue(const Variant::List& list)
+{
+ List l;
+ convert(list, l, &toFieldValue);
+ return new ListValue(l);
+}
+
+void setEncodingFor(Variant& out, uint8_t code)
+{
+ switch(code){
+ case 0x80:
+ case 0x90:
+ case 0xa0:
+ out.setEncoding(amqp0_10_binary);
+ break;
+ case 0x84:
+ case 0x94:
+ out.setEncoding(iso885915);
+ break;
+ case 0x85:
+ case 0x95:
+ out.setEncoding(utf8);
+ break;
+ case 0x86:
+ case 0x96:
+ out.setEncoding(utf16);
+ break;
+ case 0xab:
+ out.setEncoding(amqp0_10_struct);
+ break;
+ default:
+ //do nothing
+ break;
+ }
+}
+
+Variant toVariant(boost::shared_ptr<FieldValue> in)
+{
+ Variant out;
+ //based on AMQP 0-10 typecode, pick most appropriate variant type
+ switch (in->getType()) {
+ //Fixed Width types:
+ case 0x01: out.setEncoding(amqp0_10_binary);
+ case 0x02: out = in->getIntegerValue<int8_t, 1>(); break;
+ case 0x03: out = in->getIntegerValue<uint8_t, 1>(); break;
+ case 0x04: break; //TODO: iso-8859-15 char
+ case 0x08: out = in->getIntegerValue<bool, 1>(); break;
+ case 0x010: out.setEncoding(amqp0_10_binary);
+ case 0x011: out = in->getIntegerValue<int16_t, 2>(); break;
+ case 0x012: out = in->getIntegerValue<uint16_t, 2>(); break;
+ case 0x020: out.setEncoding(amqp0_10_binary);
+ case 0x021: out = in->getIntegerValue<int32_t, 4>(); break;
+ case 0x022: out = in->getIntegerValue<uint32_t, 4>(); break;
+ case 0x023: out = in->get<float>(); break;
+ case 0x027: break; //TODO: utf-32 char
+ case 0x030: out.setEncoding(amqp0_10_binary);
+ case 0x031: out = in->getIntegerValue<int64_t, 8>(); break;
+ case 0x038: out.setEncoding(amqp0_10_datetime); //treat datetime as uint64_t, but set encoding
+ case 0x032: out = in->getIntegerValue<uint64_t, 8>(); break;
+ case 0x033:out = in->get<double>(); break;
+
+ //TODO: figure out whether and how to map values with codes 0x40-0xd8
+
+ case 0xf0: break;//void, which is the default value for Variant
+ case 0xf1: out.setEncoding(amqp0_10_bit); break;//treat 'bit' as void, which is the default value for Variant
+
+ //Variable Width types:
+ //strings:
+ case 0x80:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x90:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0xa0:
+ case 0xab:
+ setEncodingFor(out, in->getType());
+ out = in->get<std::string>();
+ break;
+
+ case 0xa8:
+ out = Variant::Map();
+ translate<FieldTable>(in, out.asMap(), &toVariantMapEntry);
+ break;
+
+ case 0xa9:
+ out = Variant::List();
+ translate<List>(in, out.asList(), &toVariant);
+ break;
+ case 0xaa: //convert amqp0-10 array into variant list
+ out = Variant::List();
+ translate<Array>(in, out.asList(), &toVariant);
+ break;
+
+ default:
+ //error?
+ break;
+ }
+ return out;
+}
+
+boost::shared_ptr<FieldValue> toFieldValue(const Variant& in)
+{
+ boost::shared_ptr<FieldValue> out;
+ switch (in.getType()) {
+ case VAR_VOID: out = boost::shared_ptr<FieldValue>(new VoidValue()); break;
+ case VAR_BOOL: out = boost::shared_ptr<FieldValue>(new BoolValue(in.asBool())); break;
+ case VAR_UINT8: out = boost::shared_ptr<FieldValue>(new Unsigned8Value(in.asUint8())); break;
+ case VAR_UINT16: out = boost::shared_ptr<FieldValue>(new Unsigned16Value(in.asUint16())); break;
+ case VAR_UINT32: out = boost::shared_ptr<FieldValue>(new Unsigned32Value(in.asUint32())); break;
+ case VAR_UINT64: out = boost::shared_ptr<FieldValue>(new Unsigned64Value(in.asUint64())); break;
+ case VAR_INT8: out = boost::shared_ptr<FieldValue>(new Integer8Value(in.asInt8())); break;
+ case VAR_INT16: out = boost::shared_ptr<FieldValue>(new Integer16Value(in.asInt16())); break;
+ case VAR_INT32: out = boost::shared_ptr<FieldValue>(new Integer32Value(in.asInt32())); break;
+ case VAR_INT64: out = boost::shared_ptr<FieldValue>(new Integer64Value(in.asInt64())); break;
+ case VAR_FLOAT: out = boost::shared_ptr<FieldValue>(new FloatValue(in.asFloat())); break;
+ case VAR_DOUBLE: out = boost::shared_ptr<FieldValue>(new DoubleValue(in.asDouble())); break;
+ //TODO: check encoding (and length?) when deciding what AMQP type to treat string as
+ case VAR_STRING: out = boost::shared_ptr<FieldValue>(new Str16Value(in.asString())); break;
+ case VAR_MAP:
+ //out = boost::shared_ptr<FieldValue>(toFieldValueCollection<FieldTableValue>(in.asMap(), &toFieldTableEntry));
+ out = boost::shared_ptr<FieldValue>(toFieldTableValue(in.asMap()));
+ break;
+ case VAR_LIST:
+ //out = boost::shared_ptr<FieldValue>(toFieldValueCollection<ListValue>(in.asList(), &toFieldValue));
+ out = boost::shared_ptr<FieldValue>(toListValue(in.asList()));
+ break;
+ }
+ return out;
+}
+
+Variant::Map::value_type toVariantMapEntry(const FieldTable::value_type& in)
+{
+ return Variant::Map::value_type(in.first, toVariant(in.second));
+}
+
+FieldTable::value_type toFieldTableEntry(const Variant::Map::value_type& in)
+{
+ return FieldTable::value_type(in.first, toFieldValue(in.second));
+}
+
+struct EncodeBuffer
+{
+ char* data;
+ Buffer buffer;
+
+ EncodeBuffer(size_t size) : data(new char[size]), buffer(data, size) {}
+ ~EncodeBuffer() { delete[] data; }
+
+ template <class T> void encode(T& t) { t.encode(buffer); }
+
+ void getData(std::string& s) {
+ s.assign(data, buffer.getSize());
+ }
+};
+
+struct DecodeBuffer
+{
+ Buffer buffer;
+
+ DecodeBuffer(const std::string& s) : buffer(const_cast<char*>(s.data()), s.size()) {}
+
+ template <class T> void decode(T& t) { t.decode(buffer); }
+
+};
+
+template <class T, class U, class F> void _encode(const U& value, std::string& data, F f)
+{
+ T t;
+ convert(value, t, f);
+ EncodeBuffer buffer(t.encodedSize());
+ buffer.encode(t);
+ buffer.getData(data);
+}
+
+template <class T, class U, class F> void _decode(const std::string& data, U& value, F f)
+{
+ T t;
+ DecodeBuffer buffer(data);
+ buffer.decode(t);
+ convert(t, value, f);
+}
+
+void MapCodec::encode(const Variant& value, std::string& data)
+{
+ _encode<FieldTable>(value.asMap(), data, &toFieldTableEntry);
+}
+
+void MapCodec::decode(const std::string& data, Variant& value)
+{
+ value = Variant::Map();
+ _decode<FieldTable>(data, value.asMap(), &toVariantMapEntry);
+}
+
+void ListCodec::encode(const Variant& value, std::string& data)
+{
+ _encode<List>(value.asList(), data, &toFieldValue);
+}
+
+void ListCodec::decode(const std::string& data, Variant& value)
+{
+ value = Variant::List();
+ _decode<List>(data, value.asList(), &toVariant);
+}
+
+void translate(const Variant::Map& from, FieldTable& to)
+{
+ convert(from, to, &toFieldTableEntry);
+}
+
+void translate(const FieldTable& from, Variant::Map& to)
+{
+ convert(from, to, &toVariantMapEntry);
+}
+
+const std::string ListCodec::contentType("amqp0_10/list");
+const std::string MapCodec::contentType("amqp0_10/map");
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/CodecsInternal.h b/qpid/cpp/src/qpid/client/amqp0_10/CodecsInternal.h
new file mode 100644
index 0000000000..b5a561a9c3
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/CodecsInternal.h
@@ -0,0 +1,41 @@
+#ifndef QPID_CLIENT_AMQP0_10_CODECSINTERNAL_H
+#define QPID_CLIENT_AMQP0_10_CODECSINTERNAL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/FieldTable.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+/**
+ * Declarations of a couple of conversion functions implemented in
+ * Codecs.cpp but not exposed through API
+ */
+
+void translate(const qpid::messaging::Variant::Map& from, qpid::framing::FieldTable& to);
+void translate(const qpid::framing::FieldTable& from, qpid::messaging::Variant::Map& to);
+
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_CODECSINTERNAL_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.cpp b/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.cpp
new file mode 100644
index 0000000000..52b623b65c
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.cpp
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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 "CompletionTracker.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::framing::SequenceNumber;
+
+void CompletionTracker::track(SequenceNumber command, void* token)
+{
+ tokens[command] = token;
+}
+
+void CompletionTracker::completedTo(SequenceNumber command)
+{
+ Tokens::iterator i = tokens.lower_bound(command);
+ if (i != tokens.end()) {
+ lastCompleted = i->second;
+ tokens.erase(tokens.begin(), ++i);
+ }
+}
+
+void* CompletionTracker::getLastCompletedToken()
+{
+ return lastCompleted;
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.h b/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.h
new file mode 100644
index 0000000000..6147c5682e
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/CompletionTracker.h
@@ -0,0 +1,50 @@
+#ifndef QPID_CLIENT_AMQP0_10_COMPLETIONTRACKER_H
+#define QPID_CLIENT_AMQP0_10_COMPLETIONTRACKER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/framing/SequenceNumber.h"
+#include <map>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+/**
+ * Provides a mapping from command ids to application supplied
+ * 'tokens', and is used to determine when the sending or
+ * acknowledging of a specific message is complete.
+ */
+class CompletionTracker
+{
+ public:
+ void track(qpid::framing::SequenceNumber command, void* token);
+ void completedTo(qpid::framing::SequenceNumber command);
+ void* getLastCompletedToken();
+ private:
+ typedef std::map<qpid::framing::SequenceNumber, void*> Tokens;
+ Tokens tokens;
+ void* lastCompleted;
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_COMPLETIONTRACKER_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
new file mode 100644
index 0000000000..3a735b5698
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
@@ -0,0 +1,181 @@
+/*
+ *
+ * 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 "ConnectionImpl.h"
+#include "SessionImpl.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/client/PrivateImplRef.h"
+#include "qpid/log/Statement.h"
+#include <boost/intrusive_ptr.hpp>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::messaging::Variant;
+using namespace qpid::sys;
+
+template <class T> void setIfFound(const Variant::Map& map, const std::string& key, T& value)
+{
+ Variant::Map::const_iterator i = map.find(key);
+ if (i != map.end()) {
+ value = (T) i->second;
+ }
+}
+
+void convert(const Variant::Map& from, ConnectionSettings& to)
+{
+ setIfFound(from, "username", to.username);
+ setIfFound(from, "password", to.password);
+ setIfFound(from, "sasl-mechanism", to.mechanism);
+ setIfFound(from, "sasl-service", to.service);
+ setIfFound(from, "sasl-min-ssf", to.minSsf);
+ setIfFound(from, "sasl-max-ssf", to.maxSsf);
+
+ setIfFound(from, "heartbeat", to.heartbeat);
+ setIfFound(from, "tcp-nodelay", to.tcpNoDelay);
+
+ setIfFound(from, "locale", to.locale);
+ setIfFound(from, "max-channels", to.maxChannels);
+ setIfFound(from, "max-frame-size", to.maxFrameSize);
+ setIfFound(from, "bounds", to.bounds);
+}
+
+ConnectionImpl::ConnectionImpl(const std::string& u, const Variant::Map& options) :
+ url(u), reconnectionEnabled(true), timeout(-1),
+ minRetryInterval(1), maxRetryInterval(30)
+{
+ QPID_LOG(debug, "Opening connection to " << url << " with " << options);
+ convert(options, settings);
+ setIfFound(options, "reconnection-enabled", reconnectionEnabled);
+ setIfFound(options, "reconnection-timeout", timeout);
+ setIfFound(options, "min-retry-interval", minRetryInterval);
+ setIfFound(options, "max-retry-interval", maxRetryInterval);
+ connection.open(url, settings);
+}
+
+void ConnectionImpl::close()
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ connection.close();
+}
+
+boost::intrusive_ptr<SessionImpl> getImplPtr(qpid::messaging::Session& session)
+{
+ return boost::dynamic_pointer_cast<SessionImpl>(
+ qpid::client::PrivateImplRef<qpid::messaging::Session>::get(session)
+ );
+}
+
+void ConnectionImpl::closed(SessionImpl& s)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ for (Sessions::iterator i = sessions.begin(); i != sessions.end(); ++i) {
+ if (getImplPtr(*i).get() == &s) {
+ sessions.erase(i);
+ break;
+ }
+ }
+}
+
+qpid::messaging::Session ConnectionImpl::newSession()
+{
+ qpid::messaging::Session impl(new SessionImpl(*this));
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ sessions.push_back(impl);
+ }
+ try {
+ getImplPtr(impl)->setSession(connection.newSession());
+ } catch (const TransportFailure&) {
+ reconnect();
+ }
+ return impl;
+}
+
+void ConnectionImpl::reconnect()
+{
+ AbsTime start = now();
+ ScopedLock<Semaphore> l(semaphore);
+ if (!connection.isOpen()) connect(start);
+}
+
+bool expired(const AbsTime& start, int timeout)
+{
+ if (timeout == 0) return true;
+ if (timeout < 0) return false;
+ Duration used(start, now());
+ Duration allowed = timeout * TIME_SEC;
+ return allowed > used;
+}
+
+void ConnectionImpl::connect(const AbsTime& started)
+{
+ for (int i = minRetryInterval; !tryConnect(); i = std::min(i * 2, maxRetryInterval)) {
+ if (expired(started, timeout)) throw TransportFailure();
+ else qpid::sys::sleep(i);
+ }
+}
+
+bool ConnectionImpl::tryConnect()
+{
+ if (tryConnect(url) || tryConnect(connection.getKnownBrokers())) {
+ return resetSessions();
+ } else {
+ return false;
+ }
+}
+
+bool ConnectionImpl::tryConnect(const Url& u)
+{
+ try {
+ QPID_LOG(info, "Trying to connect to " << url << "...");
+ connection.open(u, settings);
+ return true;
+ } catch (const Exception& e) {
+ //TODO: need to fix timeout on open so that it throws TransportFailure
+ QPID_LOG(info, "Failed to connect to " << u << ": " << e.what());
+ }
+ return false;
+}
+
+bool ConnectionImpl::tryConnect(const std::vector<Url>& urls)
+{
+ for (std::vector<Url>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
+ if (tryConnect(*i)) return true;
+ }
+ return false;
+}
+
+bool ConnectionImpl::resetSessions()
+{
+ try {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ for (Sessions::iterator i = sessions.begin(); i != sessions.end(); ++i) {
+ getImplPtr(*i)->setSession(connection.newSession());
+ }
+ return true;
+ } catch (const TransportFailure&) {
+ QPID_LOG(debug, "Connection failed while re-inialising sessions");
+ return false;
+ }
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
new file mode 100644
index 0000000000..565f2ec7ec
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h
@@ -0,0 +1,69 @@
+#ifndef QPID_CLIENT_AMQP0_10_CONNECTIONIMPL_H
+#define QPID_CLIENT_AMQP0_10_CONNECTIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/ConnectionImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/Url.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/sys/Semaphore.h"
+#include <vector>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+class SessionImpl;
+
+class ConnectionImpl : public qpid::messaging::ConnectionImpl
+{
+ public:
+ ConnectionImpl(const std::string& url, const qpid::messaging::Variant::Map& options);
+ void close();
+ qpid::messaging::Session newSession();
+ void closed(SessionImpl&);
+ void reconnect();
+ private:
+ typedef std::vector<qpid::messaging::Session> Sessions;
+
+ qpid::sys::Mutex lock;//used to protect data structures
+ qpid::sys::Semaphore semaphore;//used to coordinate reconnection
+ qpid::client::Connection connection;
+ qpid::Url url;
+ qpid::client::ConnectionSettings settings;
+ Sessions sessions;
+ bool reconnectionEnabled;
+ int timeout;
+ int minRetryInterval;
+ int maxRetryInterval;
+
+ void connect(const qpid::sys::AbsTime& started);
+ bool tryConnect();
+ bool tryConnect(const std::vector<Url>& urls);
+ bool tryConnect(const Url&);
+ bool resetSessions();
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_CONNECTIONIMPL_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
new file mode 100644
index 0000000000..b0a16674e1
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp
@@ -0,0 +1,244 @@
+/*
+ *
+ * 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 "qpid/client/amqp0_10/IncomingMessages.h"
+#include "qpid/client/amqp0_10/AddressResolution.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+#include "qpid/client/amqp0_10/CodecsInternal.h"
+#include "qpid/client/SessionImpl.h"
+#include "qpid/client/SessionBase_0_10Access.h"
+#include "qpid/log/Statement.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/enum.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using namespace qpid::framing;
+using namespace qpid::framing::message;
+using qpid::sys::AbsTime;
+using qpid::sys::Duration;
+using qpid::messaging::MessageImplAccess;
+using qpid::messaging::Variant;
+
+namespace {
+const std::string EMPTY_STRING;
+
+
+struct GetNone : IncomingMessages::Handler
+{
+ bool accept(IncomingMessages::MessageTransfer&) { return false; }
+};
+
+struct GetAny : IncomingMessages::Handler
+{
+ bool accept(IncomingMessages::MessageTransfer& transfer)
+ {
+ transfer.retrieve(0);
+ return true;
+ }
+};
+
+struct MatchAndTrack
+{
+ const std::string destination;
+ SequenceSet ids;
+
+ MatchAndTrack(const std::string& d) : destination(d) {}
+
+ bool operator()(boost::shared_ptr<qpid::framing::FrameSet> command)
+ {
+ if (command->as<MessageTransferBody>()->getDestination() == destination) {
+ ids.add(command->getId());
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
+}
+
+void IncomingMessages::setSession(qpid::client::AsyncSession s)
+{
+ session = s;
+ incoming = SessionBase_0_10Access(session).get()->getDemux().getDefault();
+}
+
+bool IncomingMessages::get(Handler& handler, Duration timeout)
+{
+ //search through received list for any transfer of interest:
+ for (FrameSetQueue::iterator i = received.begin(); i != received.end(); i++)
+ {
+ MessageTransfer transfer(*i, *this);
+ if (handler.accept(transfer)) {
+ received.erase(i);
+ return true;
+ }
+ }
+ //none found, check incoming:
+ return process(&handler, timeout);
+}
+
+void IncomingMessages::accept()
+{
+ session.messageAccept(unaccepted);
+ unaccepted.clear();
+}
+
+void IncomingMessages::releaseAll()
+{
+ //first process any received messages...
+ while (!received.empty()) {
+ retrieve(received.front(), 0);
+ received.pop_front();
+ }
+ //then pump out any available messages from incoming queue...
+ GetAny handler;
+ while (process(&handler, 0)) ;
+ //now release all messages
+ session.messageRelease(unaccepted);
+ unaccepted.clear();
+}
+
+void IncomingMessages::releasePending(const std::string& destination)
+{
+ //first pump all available messages from incoming to received...
+ while (process(0, 0)) ;
+
+ //now remove all messages for this destination from received list, recording their ids...
+ MatchAndTrack match(destination);
+ for (FrameSetQueue::iterator i = received.begin(); i != received.end(); i = match(*i) ? received.erase(i) : ++i) ;
+ //now release those messages
+ session.messageRelease(match.ids);
+}
+
+/**
+ * Get a frameset from session queue, waiting for up to the specified
+ * duration and returning true if this could be achieved, false
+ * otherwise. If a destination is supplied, only return a message for
+ * that destination. In this case messages from other destinations
+ * will be held on a received queue.
+ */
+bool IncomingMessages::process(Handler* handler, qpid::sys::Duration duration)
+{
+ AbsTime deadline(AbsTime::now(), duration);
+ FrameSet::shared_ptr content;
+ for (Duration timeout = duration; incoming->pop(content, timeout); timeout = Duration(AbsTime::now(), deadline)) {
+ if (content->isA<MessageTransferBody>()) {
+ MessageTransfer transfer(content, *this);
+ if (handler && handler->accept(transfer)) {
+ QPID_LOG(debug, "Delivered " << *content->getMethod());
+ return true;
+ } else {
+ //received message for another destination, keep for later
+ QPID_LOG(debug, "Pushed " << *content->getMethod() << " to received queue");
+ received.push_back(content);
+ }
+ } else {
+ //TODO: handle other types of commands (e.g. message-accept, message-flow etc)
+ }
+ }
+ return false;
+}
+
+void populate(qpid::messaging::Message& message, FrameSet& command);
+
+/**
+ * Called when message is retrieved; records retrieval for subsequent
+ * acceptance, marks the command as completed and converts command to
+ * message if message is required
+ */
+void IncomingMessages::retrieve(FrameSetPtr command, qpid::messaging::Message* message)
+{
+ if (message) {
+ populate(*message, *command);
+ }
+ const MessageTransferBody* transfer = command->as<MessageTransferBody>();
+ if (transfer->getAcquireMode() == ACQUIRE_MODE_PRE_ACQUIRED && transfer->getAcceptMode() == ACCEPT_MODE_EXPLICIT) {
+ unaccepted.add(command->getId());
+ }
+ session.markCompleted(command->getId(), false, false);
+}
+
+IncomingMessages::MessageTransfer::MessageTransfer(FrameSetPtr c, IncomingMessages& p) : content(c), parent(p) {}
+
+const std::string& IncomingMessages::MessageTransfer::getDestination()
+{
+ return content->as<MessageTransferBody>()->getDestination();
+}
+void IncomingMessages::MessageTransfer::retrieve(qpid::messaging::Message* message)
+{
+ parent.retrieve(content, message);
+}
+
+void populateHeaders(qpid::messaging::Message& message,
+ const DeliveryProperties* deliveryProperties,
+ const MessageProperties* messageProperties)
+{
+ if (deliveryProperties) {
+ message.setSubject(deliveryProperties->getRoutingKey());
+ //TODO: convert other delivery properties
+ }
+ if (messageProperties) {
+ message.setContentType(messageProperties->getContentType());
+ if (messageProperties->hasReplyTo()) {
+ message.setReplyTo(AddressResolution::convert(messageProperties->getReplyTo()));
+ }
+ message.getHeaders().clear();
+ translate(messageProperties->getApplicationHeaders(), message.getHeaders());
+ //TODO: convert other message properties
+ }
+}
+
+void populateHeaders(qpid::messaging::Message& message, const AMQHeaderBody* headers)
+{
+ populateHeaders(message, headers->get<DeliveryProperties>(), headers->get<MessageProperties>());
+}
+
+void populate(qpid::messaging::Message& message, FrameSet& command)
+{
+ //need to be able to link the message back to the transfer it was delivered by
+ //e.g. for rejecting.
+ MessageImplAccess::get(message).setInternalId(command.getId());
+
+ command.getContent(message.getBytes());
+
+ populateHeaders(message, command.getHeaders());
+
+ //decode content if necessary
+ if (message.getContentType() == ListCodec::contentType) {
+ ListCodec codec;
+ message.decode(codec);
+ } else if (message.getContentType() == MapCodec::contentType) {
+ MapCodec codec;
+ message.decode(codec);
+ }
+}
+
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.h b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.h
new file mode 100644
index 0000000000..5e28877305
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.h
@@ -0,0 +1,91 @@
+#ifndef QPID_CLIENT_AMQP0_10_INCOMINGMESSAGES_H
+#define QPID_CLIENT_AMQP0_10_INCOMINGMESSAGES_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include "qpid/client/AsyncSession.h"
+#include "qpid/framing/SequenceSet.h"
+#include "qpid/sys/BlockingQueue.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+
+namespace framing{
+class FrameSet;
+}
+
+namespace messaging {
+class Message;
+}
+
+namespace client {
+namespace amqp0_10 {
+
+/**
+ *
+ */
+class IncomingMessages
+{
+ public:
+ typedef boost::shared_ptr<qpid::framing::FrameSet> FrameSetPtr;
+ class MessageTransfer
+ {
+ public:
+ const std::string& getDestination();
+ void retrieve(qpid::messaging::Message* message);
+ private:
+ FrameSetPtr content;
+ IncomingMessages& parent;
+
+ MessageTransfer(FrameSetPtr, IncomingMessages&);
+ friend class IncomingMessages;
+ };
+
+ struct Handler
+ {
+ virtual ~Handler() {}
+ virtual bool accept(MessageTransfer& transfer) = 0;
+ };
+
+ void setSession(qpid::client::AsyncSession session);
+ bool get(Handler& handler, qpid::sys::Duration timeout);
+ //bool get(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ //bool get(const std::string& destination, qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ void accept();
+ void releaseAll();
+ void releasePending(const std::string& destination);
+ private:
+ typedef std::deque<FrameSetPtr> FrameSetQueue;
+
+ qpid::client::AsyncSession session;
+ qpid::framing::SequenceSet unaccepted;
+ boost::shared_ptr< sys::BlockingQueue<FrameSetPtr> > incoming;
+ FrameSetQueue received;
+
+ bool process(Handler*, qpid::sys::Duration);
+ void retrieve(FrameSetPtr, qpid::messaging::Message*);
+
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_INCOMINGMESSAGES_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/MessageSink.h b/qpid/cpp/src/qpid/client/amqp0_10/MessageSink.h
new file mode 100644
index 0000000000..d66d2ecb3c
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/MessageSink.h
@@ -0,0 +1,52 @@
+#ifndef QPID_CLIENT_AMQP0_10_MESSAGESINK_H
+#define QPID_CLIENT_AMQP0_10_MESSAGESINK_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/AsyncSession.h"
+
+namespace qpid {
+
+namespace messaging {
+class Message;
+}
+
+namespace client {
+namespace amqp0_10 {
+
+class OutgoingMessage;
+
+/**
+ *
+ */
+class MessageSink
+{
+ public:
+ virtual ~MessageSink() {}
+ virtual void declare(qpid::client::AsyncSession& session, const std::string& name) = 0;
+ virtual void send(qpid::client::AsyncSession& session, const std::string& name, OutgoingMessage& message) = 0;
+ virtual void cancel(qpid::client::AsyncSession& session, const std::string& name) = 0;
+ private:
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_MESSAGESINK_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/MessageSource.h b/qpid/cpp/src/qpid/client/amqp0_10/MessageSource.h
new file mode 100644
index 0000000000..74f2732f59
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/MessageSource.h
@@ -0,0 +1,47 @@
+#ifndef QPID_CLIENT_AMQP0_10_MESSAGESOURCE_H
+#define QPID_CLIENT_AMQP0_10_MESSAGESOURCE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/client/AsyncSession.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+/**
+ * Abstraction behind which the AMQP 0-10 commands required to
+ * establish (and tear down) an incoming stream of messages from a
+ * given address are hidden.
+ */
+class MessageSource
+{
+ public:
+ virtual ~MessageSource() {}
+ virtual void subscribe(qpid::client::AsyncSession& session, const std::string& destination) = 0;
+ virtual void cancel(qpid::client::AsyncSession& session, const std::string& destination) = 0;
+
+ private:
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_MESSAGESOURCE_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
new file mode 100644
index 0000000000..716f955f98
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * 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 "qpid/client/amqp0_10/OutgoingMessage.h"
+#include "qpid/client/amqp0_10/AddressResolution.h"
+#include "qpid/client/amqp0_10/Codecs.h"
+#include "qpid/client/amqp0_10/CodecsInternal.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::messaging::Address;
+using qpid::messaging::MessageImplAccess;
+
+template <class T> void encode(const qpid::messaging::Message& from, qpid::client::Message& to)
+{
+ T codec;
+ MessageImplAccess::get(from).getEncodedContent(codec, to.getData());
+ to.getMessageProperties().setContentType(T::contentType);
+}
+
+void OutgoingMessage::convert(const qpid::messaging::Message& from)
+{
+ //TODO: need to avoid copying as much as possible
+ if (from.getContent().isList()) {
+ encode<ListCodec>(from, message);
+ } else if (from.getContent().isMap()) {
+ encode<MapCodec>(from, message);
+ } else {
+ message.setData(from.getBytes());
+ message.getMessageProperties().setContentType(from.getContentType());
+ }
+ const Address& address = from.getReplyTo();
+ if (!address.value.empty()) {
+ message.getMessageProperties().setReplyTo(AddressResolution::convert(address));
+ }
+ translate(from.getHeaders(), message.getMessageProperties().getApplicationHeaders());
+ //TODO: set other message properties
+ message.getDeliveryProperties().setRoutingKey(from.getSubject());
+ //TODO: set other delivery properties
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h
new file mode 100644
index 0000000000..8801e4e769
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.h
@@ -0,0 +1,46 @@
+#ifndef QPID_CLIENT_AMQP0_10_OUTGOINGMESSAGE_H
+#define QPID_CLIENT_AMQP0_10_OUTGOINGMESSAGE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/client/Completion.h"
+#include "qpid/client/Message.h"
+
+namespace qpid {
+namespace messaging {
+class Message;
+}
+namespace client {
+namespace amqp0_10 {
+
+struct OutgoingMessage
+{
+ qpid::client::Message message;
+ qpid::client::Completion status;
+
+ void convert(const qpid::messaging::Message&);
+};
+
+
+
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_OUTGOINGMESSAGE_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
new file mode 100644
index 0000000000..31efff38a6
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp
@@ -0,0 +1,190 @@
+/*
+ *
+ * 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 "ReceiverImpl.h"
+#include "AddressResolution.h"
+#include "MessageSource.h"
+#include "SessionImpl.h"
+#include "qpid/messaging/MessageListener.h"
+#include "qpid/messaging/Receiver.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+using qpid::messaging::Receiver;
+
+void ReceiverImpl::received(qpid::messaging::Message&)
+{
+ //TODO: should this be configurable
+ if (capacity && --window <= capacity/2) {
+ session.sendCompletion();
+ window = capacity;
+ }
+}
+
+qpid::messaging::Message ReceiverImpl::get(qpid::sys::Duration timeout)
+{
+ qpid::messaging::Message result;
+ if (!get(result, timeout)) throw Receiver::NoMessageAvailable();
+ return result;
+}
+
+qpid::messaging::Message ReceiverImpl::fetch(qpid::sys::Duration timeout)
+{
+ qpid::messaging::Message result;
+ if (!fetch(result, timeout)) throw Receiver::NoMessageAvailable();
+ return result;
+}
+
+bool ReceiverImpl::get(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ Get f(*this, message, timeout);
+ while (!parent.execute(f)) {}
+ return f.result;
+}
+
+bool ReceiverImpl::fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ Fetch f(*this, message, timeout);
+ while (!parent.execute(f)) {}
+ return f.result;
+}
+
+void ReceiverImpl::cancel()
+{
+ execute<Cancel>();
+}
+
+void ReceiverImpl::start()
+{
+ execute<Start>();
+}
+
+void ReceiverImpl::stop()
+{
+ execute<Stop>();
+}
+
+void ReceiverImpl::setCapacity(uint32_t c)
+{
+ execute1<SetCapacity>(c);
+}
+
+void ReceiverImpl::startFlow()
+{
+ if (capacity > 0) {
+ session.messageSetFlowMode(destination, FLOW_MODE_WINDOW);
+ session.messageFlow(destination, CREDIT_UNIT_MESSAGE, capacity);
+ session.messageFlow(destination, CREDIT_UNIT_BYTE, byteCredit);
+ window = capacity;
+ }
+}
+
+void ReceiverImpl::init(qpid::client::AsyncSession s, AddressResolution& resolver)
+{
+
+ session = s;
+ if (state == UNRESOLVED) {
+ source = resolver.resolveSource(session, address, filter, options);
+ state = STOPPED;//TODO: if session is started, go straight to started
+ }
+ if (state == CANCELLED) {
+ source->cancel(session, destination);
+ parent.receiverCancelled(destination);
+ } else {
+ source->subscribe(session, destination);
+ if (state == STARTED) start();
+ }
+}
+
+void ReceiverImpl::setListener(qpid::messaging::MessageListener* l) { listener = l; }
+qpid::messaging::MessageListener* ReceiverImpl::getListener() { return listener; }
+
+const std::string& ReceiverImpl::getName() const { return destination; }
+
+ReceiverImpl::ReceiverImpl(SessionImpl& p, const std::string& name,
+ const qpid::messaging::Address& a,
+ const qpid::messaging::Filter* f,
+ const qpid::messaging::Variant::Map& o) :
+
+ parent(p), destination(name), address(a), filter(f), options(o), byteCredit(0xFFFFFFFF),
+ state(UNRESOLVED), capacity(0), listener(0), window(0) {}
+
+bool ReceiverImpl::getImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ return parent.get(*this, message, timeout);
+}
+
+bool ReceiverImpl::fetchImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ if (state == CANCELLED) return false;//TODO: or should this be an error?
+
+ if (capacity == 0 || state != STARTED) {
+ session.messageSetFlowMode(destination, FLOW_MODE_CREDIT);
+ session.messageFlow(destination, CREDIT_UNIT_MESSAGE, 1);
+ session.messageFlow(destination, CREDIT_UNIT_BYTE, 0xFFFFFFFF);
+ }
+
+ if (getImpl(message, timeout)) {
+ return true;
+ } else {
+ sync(session).messageFlush(destination);
+ startFlow();//reallocate credit
+ return getImpl(message, 0);
+ }
+}
+
+void ReceiverImpl::cancelImpl()
+{
+ if (state != CANCELLED) {
+ state = CANCELLED;
+ source->cancel(session, destination);
+ parent.receiverCancelled(destination);
+ }
+}
+
+void ReceiverImpl::startImpl()
+{
+ if (state == STOPPED) {
+ state = STARTED;
+ startFlow();
+ }
+}
+
+void ReceiverImpl::stopImpl()
+{
+ state = STOPPED;
+ session.messageStop(destination);
+}
+
+void ReceiverImpl::setCapacityImpl(uint32_t c)
+{
+ if (c != capacity) {
+ capacity = c;
+ if (state == STARTED) {
+ session.messageStop(destination);
+ startFlow();
+ }
+ }
+}
+
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
new file mode 100644
index 0000000000..509c784513
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h
@@ -0,0 +1,165 @@
+#ifndef QPID_CLIENT_AMQP0_10_RECEIVERIMPL_H
+#define QPID_CLIENT_AMQP0_10_RECEIVERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Filter.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/ReceiverImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/amqp0_10/SessionImpl.h"
+#include "qpid/sys/Time.h"
+#include <memory>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+class AddressResolution;
+class MessageSource;
+
+/**
+ * A receiver implementation based on an AMQP 0-10 subscription.
+ */
+class ReceiverImpl : public qpid::messaging::ReceiverImpl
+{
+ public:
+
+ enum State {UNRESOLVED, STOPPED, STARTED, CANCELLED};
+
+ ReceiverImpl(SessionImpl& parent, const std::string& name,
+ const qpid::messaging::Address& address,
+ const qpid::messaging::Filter* filter,
+ const qpid::messaging::Variant::Map& options);
+
+ void init(qpid::client::AsyncSession session, AddressResolution& resolver);
+ bool get(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ qpid::messaging::Message get(qpid::sys::Duration timeout);
+ bool fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ qpid::messaging::Message fetch(qpid::sys::Duration timeout);
+ void cancel();
+ void start();
+ void stop();
+ const std::string& getName() const;
+ void setCapacity(uint32_t);
+ void setListener(qpid::messaging::MessageListener* listener);
+ qpid::messaging::MessageListener* getListener();
+ void received(qpid::messaging::Message& message);
+ private:
+ SessionImpl& parent;
+ const std::string destination;
+ const qpid::messaging::Address address;
+ const qpid::messaging::Filter* filter;
+ const qpid::messaging::Variant::Map options;
+ const uint32_t byteCredit;
+ State state;
+
+ std::auto_ptr<MessageSource> source;
+ uint32_t capacity;
+ qpid::client::AsyncSession session;
+ qpid::messaging::MessageListener* listener;
+ uint32_t window;
+
+ void startFlow();
+ //implementation of public facing methods
+ bool fetchImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ bool getImpl(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ void startImpl();
+ void stopImpl();
+ void cancelImpl();
+ void setCapacityImpl(uint32_t);
+
+ //functors for public facing methods (allows locking and retry
+ //logic to be centralised)
+ struct Command
+ {
+ ReceiverImpl& impl;
+
+ Command(ReceiverImpl& i) : impl(i) {}
+ };
+
+ struct Get : Command
+ {
+ qpid::messaging::Message& message;
+ qpid::sys::Duration timeout;
+ bool result;
+
+ Get(ReceiverImpl& i, qpid::messaging::Message& m, qpid::sys::Duration t) :
+ Command(i), message(m), timeout(t), result(false) {}
+ void operator()() { result = impl.getImpl(message, timeout); }
+ };
+
+ struct Fetch : Command
+ {
+ qpid::messaging::Message& message;
+ qpid::sys::Duration timeout;
+ bool result;
+
+ Fetch(ReceiverImpl& i, qpid::messaging::Message& m, qpid::sys::Duration t) :
+ Command(i), message(m), timeout(t), result(false) {}
+ void operator()() { result = impl.fetchImpl(message, timeout); }
+ };
+
+ struct Stop : Command
+ {
+ Stop(ReceiverImpl& i) : Command(i) {}
+ void operator()() { impl.stopImpl(); }
+ };
+
+ struct Start : Command
+ {
+ Start(ReceiverImpl& i) : Command(i) {}
+ void operator()() { impl.startImpl(); }
+ };
+
+ struct Cancel : Command
+ {
+ Cancel(ReceiverImpl& i) : Command(i) {}
+ void operator()() { impl.cancelImpl(); }
+ };
+
+ struct SetCapacity : Command
+ {
+ uint32_t capacity;
+
+ SetCapacity(ReceiverImpl& i, uint32_t c) : Command(i), capacity(c) {}
+ void operator()() { impl.setCapacityImpl(capacity); }
+ };
+
+ //helper templates for some common patterns
+ template <class F> void execute()
+ {
+ F f(*this);
+ parent.execute(f);
+ }
+
+ template <class F, class P> void execute1(P p)
+ {
+ F f(*this, p);
+ parent.execute(f);
+ }
+};
+
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_RECEIVERIMPL_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
new file mode 100644
index 0000000000..c619d1226a
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * 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 "SenderImpl.h"
+#include "MessageSink.h"
+#include "SessionImpl.h"
+#include "AddressResolution.h"
+#include "OutgoingMessage.h"
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+SenderImpl::SenderImpl(SessionImpl& _parent, const std::string& _name,
+ const qpid::messaging::Address& _address,
+ const qpid::messaging::Variant::Map& _options) :
+ parent(_parent), name(_name), address(_address), options(_options), state(UNRESOLVED),
+ capacity(50), window(0) {}
+
+void SenderImpl::send(const qpid::messaging::Message& m)
+{
+ execute1<Send>(&m);
+}
+
+void SenderImpl::cancel()
+{
+ execute<Cancel>();
+}
+
+void SenderImpl::init(qpid::client::AsyncSession s, AddressResolution& resolver)
+{
+ session = s;
+ if (state == UNRESOLVED) {
+ sink = resolver.resolveSink(session, address, options);
+ state = ACTIVE;
+ }
+ if (state == CANCELLED) {
+ sink->cancel(session, name);
+ parent.senderCancelled(name);
+ } else {
+ sink->declare(session, name);
+ replay();
+ }
+}
+
+void SenderImpl::sendImpl(const qpid::messaging::Message& m)
+{
+ //TODO: make recoding for replay optional
+ std::auto_ptr<OutgoingMessage> msg(new OutgoingMessage());
+ msg->convert(m);
+ outgoing.push_back(msg.release());
+ sink->send(session, name, outgoing.back());
+ if (++window > (capacity / 2)) {//TODO: make this configurable?
+ session.flush();
+ checkPendingSends();
+ window = 0;
+ }
+}
+
+void SenderImpl::replay()
+{
+ for (OutgoingMessages::iterator i = outgoing.begin(); i != outgoing.end(); ++i) {
+ sink->send(session, name, *i);
+ }
+}
+
+void SenderImpl::checkPendingSends()
+{
+ while (!outgoing.empty() && outgoing.front().status.isComplete()) {
+ outgoing.pop_front();
+ }
+}
+
+void SenderImpl::cancelImpl()
+{
+ state = CANCELLED;
+ sink->cancel(session, name);
+ parent.senderCancelled(name);
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
new file mode 100644
index 0000000000..4ba793d71c
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SenderImpl.h
@@ -0,0 +1,118 @@
+#ifndef QPID_CLIENT_AMQP0_10_SENDERIMPL_H
+#define QPID_CLIENT_AMQP0_10_SENDERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/SenderImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/amqp0_10/SessionImpl.h"
+#include <memory>
+#include <boost/ptr_container/ptr_deque.hpp>
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+class AddressResolution;
+class MessageSink;
+class OutgoingMessage;
+
+/**
+ *
+ */
+class SenderImpl : public qpid::messaging::SenderImpl
+{
+ public:
+ enum State {UNRESOLVED, ACTIVE, CANCELLED};
+
+ SenderImpl(SessionImpl& parent, const std::string& name,
+ const qpid::messaging::Address& address,
+ const qpid::messaging::Variant::Map& options);
+ void send(const qpid::messaging::Message&);
+ void cancel();
+ void init(qpid::client::AsyncSession, AddressResolution&);
+
+ private:
+ SessionImpl& parent;
+ const std::string name;
+ const qpid::messaging::Address address;
+ const qpid::messaging::Variant::Map options;
+ State state;
+ std::auto_ptr<MessageSink> sink;
+
+ qpid::client::AsyncSession session;
+ std::string destination;
+ std::string routingKey;
+
+ typedef boost::ptr_deque<OutgoingMessage> OutgoingMessages;
+ OutgoingMessages outgoing;
+ uint32_t capacity;
+ uint32_t window;
+
+ void checkPendingSends();
+ void replay();
+
+ //logic for application visible methods:
+ void sendImpl(const qpid::messaging::Message&);
+ void cancelImpl();
+
+ //functors for application visible methods (allowing locking and
+ //retry to be centralised):
+ struct Command
+ {
+ SenderImpl& impl;
+
+ Command(SenderImpl& i) : impl(i) {}
+ };
+
+ struct Send : Command
+ {
+ const qpid::messaging::Message* message;
+
+ Send(SenderImpl& i, const qpid::messaging::Message* m) : Command(i), message(m) {}
+ void operator()() { impl.sendImpl(*message); }
+ };
+
+ struct Cancel : Command
+ {
+ Cancel(SenderImpl& i) : Command(i) {}
+ void operator()() { impl.cancelImpl(); }
+ };
+
+ //helper templates for some common patterns
+ template <class F> void execute()
+ {
+ F f(*this);
+ parent.execute(f);
+ }
+
+ template <class F, class P> void execute1(P p)
+ {
+ F f(*this, p);
+ parent.execute(f);
+ }
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_SENDERIMPL_H*/
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp
new file mode 100644
index 0000000000..0e6c430d89
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp
@@ -0,0 +1,375 @@
+/*
+ *
+ * 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 "qpid/client/amqp0_10/SessionImpl.h"
+#include "qpid/client/amqp0_10/ConnectionImpl.h"
+#include "qpid/client/amqp0_10/ReceiverImpl.h"
+#include "qpid/client/amqp0_10/SenderImpl.h"
+#include "qpid/client/amqp0_10/MessageSource.h"
+#include "qpid/client/amqp0_10/MessageSink.h"
+#include "qpid/client/PrivateImplRef.h"
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Filter.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
+#include "qpid/messaging/MessageListener.h"
+#include "qpid/messaging/Sender.h"
+#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/framing/reply_exceptions.h"
+#include <boost/format.hpp>
+#include <boost/function.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+using qpid::messaging::Filter;
+using qpid::messaging::MessageImplAccess;
+using qpid::messaging::Sender;
+using qpid::messaging::Receiver;
+using qpid::messaging::VariantMap;
+
+namespace qpid {
+namespace client {
+namespace amqp0_10 {
+
+SessionImpl::SessionImpl(ConnectionImpl& c) : connection(c) {}
+
+
+void SessionImpl::sync()
+{
+ retry<Sync>();
+}
+
+void SessionImpl::flush()
+{
+ retry<Flush>();
+}
+
+void SessionImpl::commit()
+{
+ if (!execute<Commit>()) {
+ throw Exception();//TODO: what type?
+ }
+}
+
+void SessionImpl::rollback()
+{
+ //If the session fails during this operation, the transaction will
+ //be rolled back anyway.
+ execute<Rollback>();
+}
+
+void SessionImpl::acknowledge()
+{
+ //Should probably throw an exception on failure here, or indicate
+ //it through a return type at least. Failure means that the
+ //message may be redelivered; i.e. the application cannot delete
+ //any state necessary for preventing reprocessing of the message
+ execute<Acknowledge>();
+}
+
+void SessionImpl::reject(qpid::messaging::Message& m)
+{
+ //Possibly want to somehow indicate failure here as well. Less
+ //clear need as compared to acknowledge however.
+ execute1<Reject>(m);
+}
+
+void SessionImpl::close()
+{
+ connection.closed(*this);
+ session.close();
+}
+
+template <class T, class S> boost::intrusive_ptr<S> getImplPtr(T& t)
+{
+ return boost::dynamic_pointer_cast<S>(qpid::client::PrivateImplRef<T>::get(t));
+}
+
+template <class T> void getFreeKey(std::string& key, T& map)
+{
+ std::string name = key;
+ int count = 1;
+ for (typename T::const_iterator i = map.find(name); i != map.end(); i = map.find(name)) {
+ name = (boost::format("%1%_%2%") % key % ++count).str();
+ }
+ key = name;
+}
+
+
+void SessionImpl::setSession(qpid::client::Session s)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ session = s;
+ incoming.setSession(session);
+ for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) {
+ getImplPtr<Receiver, ReceiverImpl>(i->second)->init(session, resolver);
+ }
+ for (Senders::iterator i = senders.begin(); i != senders.end(); ++i) {
+ getImplPtr<Sender, SenderImpl>(i->second)->init(session, resolver);
+ }
+}
+
+struct SessionImpl::CreateReceiver : Command
+{
+ qpid::messaging::Receiver result;
+ const qpid::messaging::Address& address;
+ const Filter* filter;
+ const qpid::messaging::Variant::Map& options;
+
+ CreateReceiver(SessionImpl& i, const qpid::messaging::Address& a, const Filter* f,
+ const qpid::messaging::Variant::Map& o) :
+ Command(i), address(a), filter(f), options(o) {}
+ void operator()() { result = impl.createReceiverImpl(address, filter, options); }
+};
+
+Receiver SessionImpl::createReceiver(const qpid::messaging::Address& address, const VariantMap& options)
+{
+ CreateReceiver f(*this, address, 0, options);
+ while (!execute(f)) {}
+ return f.result;
+}
+
+Receiver SessionImpl::createReceiver(const qpid::messaging::Address& address,
+ const Filter& filter, const VariantMap& options)
+{
+ CreateReceiver f(*this, address, &filter, options);
+ while (!execute(f)) {}
+ return f.result;
+}
+
+Receiver SessionImpl::createReceiverImpl(const qpid::messaging::Address& address,
+ const Filter* filter, const VariantMap& options)
+{
+ std::string name = address;
+ getFreeKey(name, receivers);
+ Receiver receiver(new ReceiverImpl(*this, name, address, filter, options));
+ getImplPtr<Receiver, ReceiverImpl>(receiver)->init(session, resolver);
+ receivers[name] = receiver;
+ return receiver;
+}
+
+struct SessionImpl::CreateSender : Command
+{
+ qpid::messaging::Sender result;
+ const qpid::messaging::Address& address;
+ const qpid::messaging::Variant::Map& options;
+
+ CreateSender(SessionImpl& i, const qpid::messaging::Address& a,
+ const qpid::messaging::Variant::Map& o) :
+ Command(i), address(a), options(o) {}
+ void operator()() { result = impl.createSenderImpl(address, options); }
+};
+
+Sender SessionImpl::createSender(const qpid::messaging::Address& address, const VariantMap& options)
+{
+ CreateSender f(*this, address, options);
+ while (!execute(f)) {}
+ return f.result;
+}
+
+Sender SessionImpl::createSenderImpl(const qpid::messaging::Address& address, const VariantMap& options)
+{
+ std::string name = address;
+ getFreeKey(name, senders);
+ Sender sender(new SenderImpl(*this, name, address, options));
+ getImplPtr<Sender, SenderImpl>(sender)->init(session, resolver);
+ senders[name] = sender;
+ return sender;
+}
+
+qpid::messaging::Address SessionImpl::createTempQueue(const std::string& baseName)
+{
+ std::string name = baseName + std::string("_") + session.getId().getName();
+ session.queueDeclare(arg::queue=name, arg::exclusive=true, arg::autoDelete=true);
+ return qpid::messaging::Address(name);
+}
+
+SessionImpl& SessionImpl::convert(qpid::messaging::Session& s)
+{
+ boost::intrusive_ptr<SessionImpl> impl = getImplPtr<qpid::messaging::Session, SessionImpl>(s);
+ if (!impl) {
+ throw qpid::Exception(QPID_MSG("Configuration error; require qpid::client::amqp0_10::SessionImpl"));
+ }
+ return *impl;
+}
+
+namespace {
+
+struct IncomingMessageHandler : IncomingMessages::Handler
+{
+ typedef boost::function1<bool, IncomingMessages::MessageTransfer&> Callback;
+ Callback callback;
+
+ IncomingMessageHandler(Callback c) : callback(c) {}
+
+ bool accept(IncomingMessages::MessageTransfer& transfer)
+ {
+ return callback(transfer);
+ }
+};
+
+}
+
+bool SessionImpl::accept(ReceiverImpl* receiver,
+ qpid::messaging::Message* message,
+ bool isDispatch,
+ IncomingMessages::MessageTransfer& transfer)
+{
+ if (receiver->getName() == transfer.getDestination()) {
+ transfer.retrieve(message);
+ if (isDispatch) {
+ qpid::sys::Mutex::ScopedUnlock u(lock);
+ qpid::messaging::MessageListener* listener = receiver->getListener();
+ if (listener) listener->received(*message);
+ }
+ receiver->received(*message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool SessionImpl::acceptAny(qpid::messaging::Message* message, bool isDispatch, IncomingMessages::MessageTransfer& transfer)
+{
+ Receivers::iterator i = receivers.find(transfer.getDestination());
+ if (i == receivers.end()) {
+ QPID_LOG(error, "Received message for unknown destination " << transfer.getDestination());
+ return false;
+ } else {
+ boost::intrusive_ptr<ReceiverImpl> receiver = getImplPtr<Receiver, ReceiverImpl>(i->second);
+ return receiver && (!isDispatch || receiver->getListener()) && accept(receiver.get(), message, isDispatch, transfer);
+ }
+}
+
+bool SessionImpl::getIncoming(IncomingMessages::Handler& handler, qpid::sys::Duration timeout)
+{
+ return incoming.get(handler, timeout);
+}
+
+bool SessionImpl::get(ReceiverImpl& receiver, qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ IncomingMessageHandler handler(boost::bind(&SessionImpl::accept, this, &receiver, &message, false, _1));
+ return getIncoming(handler, timeout);
+}
+
+bool SessionImpl::dispatch(qpid::sys::Duration timeout)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ while (true) {
+ try {
+ qpid::messaging::Message message;
+ IncomingMessageHandler handler(boost::bind(&SessionImpl::acceptAny, this, &message, true, _1));
+ return getIncoming(handler, timeout);
+ } catch (TransportFailure&) {
+ reconnect();
+ }
+ }
+}
+
+bool SessionImpl::fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout)
+{
+ qpid::sys::Mutex::ScopedLock l(lock);
+ while (true) {
+ try {
+ IncomingMessageHandler handler(boost::bind(&SessionImpl::acceptAny, this, &message, false, _1));
+ return getIncoming(handler, timeout);
+ } catch (TransportFailure&) {
+ reconnect();
+ }
+ }
+}
+
+void SessionImpl::syncImpl()
+{
+ session.sync();
+}
+
+void SessionImpl::flushImpl()
+{
+ session.flush();
+}
+
+
+void SessionImpl::commitImpl()
+{
+ incoming.accept();
+ session.txCommit();
+}
+
+void SessionImpl::rollbackImpl()
+{
+ for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) i->second.stop();
+ //ensure that stop has been processed and all previously sent
+ //messages are available for release:
+ session.sync();
+ incoming.releaseAll();
+ session.txRollback();
+ for (Receivers::iterator i = receivers.begin(); i != receivers.end(); ++i) i->second.start();
+}
+
+void SessionImpl::acknowledgeImpl()
+{
+ incoming.accept();
+}
+
+void SessionImpl::rejectImpl(qpid::messaging::Message& m)
+{
+ SequenceSet set;
+ set.add(MessageImplAccess::get(m).getInternalId());
+ session.messageReject(set);
+}
+
+qpid::messaging::Message SessionImpl::fetch(qpid::sys::Duration timeout)
+{
+ qpid::messaging::Message result;
+ if (!fetch(result, timeout)) throw Receiver::NoMessageAvailable();
+ return result;
+}
+
+void SessionImpl::receiverCancelled(const std::string& name)
+{
+ receivers.erase(name);
+ session.sync();
+ incoming.releasePending(name);
+}
+
+void SessionImpl::senderCancelled(const std::string& name)
+{
+ senders.erase(name);
+}
+
+void SessionImpl::reconnect()
+{
+ connection.reconnect();
+}
+
+void* SessionImpl::getLastConfirmedSent()
+{
+ return 0;
+}
+
+void* SessionImpl::getLastConfirmedAcknowledged()
+{
+ return 0;
+}
+
+}}} // namespace qpid::client::amqp0_10
diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h
new file mode 100644
index 0000000000..1c7db17bbb
--- /dev/null
+++ b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.h
@@ -0,0 +1,202 @@
+#ifndef QPID_CLIENT_AMQP0_10_SESSIONIMPL_H
+#define QPID_CLIENT_AMQP0_10_SESSIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/SessionImpl.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/amqp0_10/AddressResolution.h"
+#include "qpid/client/amqp0_10/IncomingMessages.h"
+#include "qpid/sys/Mutex.h"
+
+namespace qpid {
+
+namespace messaging {
+struct Address;
+struct Filter;
+class Message;
+class Receiver;
+class Sender;
+class Session;
+}
+
+namespace client {
+namespace amqp0_10 {
+
+class ConnectionImpl;
+class ReceiverImpl;
+class SenderImpl;
+
+/**
+ * Implementation of the protocol independent Session interface using
+ * AMQP 0-10.
+ */
+class SessionImpl : public qpid::messaging::SessionImpl
+{
+ public:
+ SessionImpl(ConnectionImpl&);
+ void commit();
+ void rollback();
+ void acknowledge();
+ void reject(qpid::messaging::Message&);
+ void close();
+ void sync();
+ void flush();
+ qpid::messaging::Address createTempQueue(const std::string& baseName);
+ qpid::messaging::Sender createSender(const qpid::messaging::Address& address,
+ const qpid::messaging::VariantMap& options);
+ qpid::messaging::Receiver createReceiver(const qpid::messaging::Address& address,
+ const qpid::messaging::VariantMap& options);
+ qpid::messaging::Receiver createReceiver(const qpid::messaging::Address& address,
+ const qpid::messaging::Filter& filter,
+ const qpid::messaging::VariantMap& options);
+
+ void* getLastConfirmedSent();
+ void* getLastConfirmedAcknowledged();
+
+ bool fetch(qpid::messaging::Message& message, qpid::sys::Duration timeout);
+ qpid::messaging::Message fetch(qpid::sys::Duration timeout);
+ bool dispatch(qpid::sys::Duration timeout);
+
+ bool get(ReceiverImpl& receiver, qpid::messaging::Message& message, qpid::sys::Duration timeout);
+
+ void receiverCancelled(const std::string& name);
+ void senderCancelled(const std::string& name);
+
+ void setSession(qpid::client::Session);
+
+ template <class T> bool execute(T& f)
+ {
+ try {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ f();
+ return true;
+ } catch (TransportFailure&) {
+ reconnect();
+ return false;
+ }
+ }
+
+ static SessionImpl& convert(qpid::messaging::Session&);
+
+ private:
+ typedef std::map<std::string, qpid::messaging::Receiver> Receivers;
+ typedef std::map<std::string, qpid::messaging::Sender> Senders;
+
+ qpid::sys::Mutex lock;
+ ConnectionImpl& connection;
+ qpid::client::Session session;
+ AddressResolution resolver;
+ IncomingMessages incoming;
+ Receivers receivers;
+ Senders senders;
+
+ bool acceptAny(qpid::messaging::Message*, bool, IncomingMessages::MessageTransfer&);
+ bool accept(ReceiverImpl*, qpid::messaging::Message*, bool, IncomingMessages::MessageTransfer&);
+ bool getIncoming(IncomingMessages::Handler& handler, qpid::sys::Duration timeout);
+ void reconnect();
+
+ void commitImpl();
+ void rollbackImpl();
+ void acknowledgeImpl();
+ void rejectImpl(qpid::messaging::Message&);
+ void closeImpl();
+ void syncImpl();
+ void flushImpl();
+ qpid::messaging::Sender createSenderImpl(const qpid::messaging::Address& address,
+ const qpid::messaging::VariantMap& options);
+ qpid::messaging::Receiver createReceiverImpl(const qpid::messaging::Address& address,
+ const qpid::messaging::Filter* filter,
+ const qpid::messaging::VariantMap& options);
+
+ //functors for public facing methods (allows locking and retry
+ //logic to be centralised)
+ struct Command
+ {
+ SessionImpl& impl;
+
+ Command(SessionImpl& i) : impl(i) {}
+ };
+
+ struct Commit : Command
+ {
+ Commit(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.commitImpl(); }
+ };
+
+ struct Rollback : Command
+ {
+ Rollback(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.rollbackImpl(); }
+ };
+
+ struct Acknowledge : Command
+ {
+ Acknowledge(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.acknowledgeImpl(); }
+ };
+
+ struct Sync : Command
+ {
+ Sync(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.syncImpl(); }
+ };
+
+ struct Flush : Command
+ {
+ Flush(SessionImpl& i) : Command(i) {}
+ void operator()() { impl.flushImpl(); }
+ };
+
+ struct Reject : Command
+ {
+ qpid::messaging::Message& message;
+
+ Reject(SessionImpl& i, qpid::messaging::Message& m) : Command(i), message(m) {}
+ void operator()() { impl.rejectImpl(message); }
+ };
+
+ struct CreateSender;
+ struct CreateReceiver;
+
+ //helper templates for some common patterns
+ template <class F> bool execute()
+ {
+ F f(*this);
+ return execute(f);
+ }
+
+ template <class F> void retry()
+ {
+ while (!execute<F>()) {}
+ }
+
+ template <class F, class P> bool execute1(P p)
+ {
+ F f(*this, p);
+ return execute(f);
+ }
+};
+}}} // namespace qpid::client::amqp0_10
+
+#endif /*!QPID_CLIENT_AMQP0_10_SESSIONIMPL_H*/
diff --git a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
index ac418ffbb6..2e557f2ab6 100644
--- a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
+++ b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp
@@ -213,7 +213,7 @@ class MessageUpdater {
framing::MessageTransferBody transfer(
framing::ProtocolVersion(), UpdateClient::UPDATE, message::ACCEPT_MODE_NONE, message::ACQUIRE_MODE_PRE_ACQUIRED);
- sb.get()->send(transfer, message.payload->getFrames());
+ sb.get()->send(transfer, message.payload->getFrames(), !message.payload->isContentReleased());
if (message.payload->isContentReleased()){
uint16_t maxFrameSize = sb.get()->getConnection()->getNegotiatedSettings().maxFrameSize;
uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead();
diff --git a/qpid/cpp/src/qpid/framing/FieldTable.cpp b/qpid/cpp/src/qpid/framing/FieldTable.cpp
index bc832e9db4..255a3b74a4 100644
--- a/qpid/cpp/src/qpid/framing/FieldTable.cpp
+++ b/qpid/cpp/src/qpid/framing/FieldTable.cpp
@@ -185,13 +185,8 @@ template <class T, int width, uint8_t typecode>
bool getRawFixedWidthValue(FieldTable::ValuePtr vptr, T& value)
{
if (vptr && vptr->getType() == typecode) {
- FixedWidthValue<width>* fwv = dynamic_cast< FixedWidthValue<width>* >(&vptr->getData());
- if (fwv) {
- uint8_t* const octets = Endian::convertIfRequired(fwv->rawOctets(), width);
- uint8_t* const target = reinterpret_cast<uint8_t*>(&value);
- for (uint i = 0; i < width; ++i) target[i] = octets[i];
- return true;
- }
+ value = vptr->get<T>();
+ return true;
}
return false;
}
@@ -370,5 +365,16 @@ void FieldTable::erase(const std::string& name)
values.erase(name);
}
+std::pair<FieldTable::ValueMap::iterator, bool> FieldTable::insert(const ValueMap::value_type& value)
+{
+ return values.insert(value);
+}
+
+FieldTable::ValueMap::iterator FieldTable::insert(ValueMap::iterator position, const ValueMap::value_type& value)
+{
+ return values.insert(position, value);
+}
+
+
}
}
diff --git a/qpid/cpp/src/qpid/framing/FieldValue.cpp b/qpid/cpp/src/qpid/framing/FieldValue.cpp
index 5f7248a751..5bac931b83 100644
--- a/qpid/cpp/src/qpid/framing/FieldValue.cpp
+++ b/qpid/cpp/src/qpid/framing/FieldValue.cpp
@@ -22,6 +22,7 @@
#include "qpid/framing/Array.h"
#include "qpid/framing/Buffer.h"
#include "qpid/framing/Endian.h"
+#include "qpid/framing/List.h"
#include "qpid/framing/reply_exceptions.h"
namespace qpid {
@@ -37,6 +38,8 @@ void FieldValue::setType(uint8_t type)
typeOctet = type;
if (typeOctet == 0xA8) {
data.reset(new EncodedValue<FieldTable>());
+ } else if (typeOctet == 0xA9) {
+ data.reset(new EncodedValue<List>());
} else if (typeOctet == 0xAA) {
data.reset(new EncodedValue<Array>());
} else {
@@ -164,10 +167,37 @@ FieldTableValue::FieldTableValue(const FieldTable& f) : FieldValue(0xa8, new Enc
{
}
+ListValue::ListValue(const List& l) : FieldValue(0xa9, new EncodedValue<List>(l))
+{
+}
+
ArrayValue::ArrayValue(const Array& a) : FieldValue(0xaa, new EncodedValue<Array>(a))
{
}
+VoidValue::VoidValue() : FieldValue(0xf0, new FixedWidthValue<0>()) {}
+
+BoolValue::BoolValue(bool b) :
+ FieldValue(0x08, new FixedWidthValue<1>(b))
+{}
+
+Unsigned8Value::Unsigned8Value(uint8_t v) :
+ FieldValue(0x02, new FixedWidthValue<1>(v))
+{}
+Unsigned16Value::Unsigned16Value(uint16_t v) :
+ FieldValue(0x12, new FixedWidthValue<2>(v))
+{}
+Unsigned32Value::Unsigned32Value(uint32_t v) :
+ FieldValue(0x22, new FixedWidthValue<4>(v))
+{}
+
+Integer8Value::Integer8Value(int8_t v) :
+ FieldValue(0x01, new FixedWidthValue<1>(v))
+{}
+Integer16Value::Integer16Value(int16_t v) :
+ FieldValue(0x11, new FixedWidthValue<2>(v))
+{}
+
void FieldValue::print(std::ostream& out) const {
data->print(out);
out << TypeCode(typeOctet) << '(';
@@ -177,4 +207,9 @@ void FieldValue::print(std::ostream& out) const {
out << ')';
}
+uint8_t* FieldValue::convertIfRequired(uint8_t* const octets, int width)
+{
+ return Endian::convertIfRequired(octets, width);
+}
+
}}
diff --git a/qpid/cpp/src/qpid/framing/List.cpp b/qpid/cpp/src/qpid/framing/List.cpp
new file mode 100644
index 0000000000..bde7dabbac
--- /dev/null
+++ b/qpid/cpp/src/qpid/framing/List.cpp
@@ -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.
+ *
+ */
+#include "qpid/framing/List.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/reply_exceptions.h"
+
+namespace qpid {
+namespace framing {
+
+uint32_t List::encodedSize() const
+{
+ uint32_t len(4/*size*/ + 4/*count*/);
+ for(Values::const_iterator i = values.begin(); i != values.end(); ++i) {
+ len += (*i)->encodedSize();
+ }
+ return len;
+}
+
+void List::encode(Buffer& buffer) const
+{
+ buffer.putLong(encodedSize() - 4);
+ buffer.putLong(size());
+ for (Values::const_iterator i = values.begin(); i!=values.end(); ++i) {
+ (*i)->encode(buffer);
+ }
+}
+
+void List::decode(Buffer& buffer)
+{
+ values.clear();
+ uint32_t size = buffer.getLong();
+ uint32_t available = buffer.available();
+ if (available < size) {
+ throw IllegalArgumentException(QPID_MSG("Not enough data for list, expected "
+ << size << " bytes but only " << available << " available"));
+ }
+ if (size) {
+ uint32_t count = buffer.getLong();
+ for (uint32_t i = 0; i < count; i++) {
+ ValuePtr value(new FieldValue);
+ value->decode(buffer);
+ values.push_back(value);
+ }
+ }
+}
+
+
+bool List::operator==(const List& other) const {
+ return values.size() == other.values.size() &&
+ std::equal(values.begin(), values.end(), other.values.begin());
+}
+
+std::ostream& operator<<(std::ostream& out, const List& l)
+{
+ out << "{";
+ for(List::Values::const_iterator i = l.values.begin(); i != l.values.end(); ++i) {
+ if (i != l.values.begin()) out << ", ";
+ (*i)->print(out);
+ }
+ return out << "}";
+}
+
+}} // namespace qpid::framing
diff --git a/qpid/cpp/src/qpid/framing/Uuid.cpp b/qpid/cpp/src/qpid/framing/Uuid.cpp
index c0b41c6906..71fa6a7329 100644
--- a/qpid/cpp/src/qpid/framing/Uuid.cpp
+++ b/qpid/cpp/src/qpid/framing/Uuid.cpp
@@ -17,6 +17,8 @@
*/
#include "qpid/framing/Uuid.h"
+
+#include "qpid/sys/uuid.h"
#include "qpid/Exception.h"
#include "qpid/framing/Buffer.h"
#include "qpid/framing/reply_exceptions.h"
@@ -28,6 +30,35 @@ using namespace std;
static const size_t UNPARSED_SIZE=36;
+Uuid::Uuid(bool unique) {
+ if (unique) {
+ generate();
+ } else {
+ clear();
+ }
+}
+
+Uuid::Uuid(const uint8_t* data) {
+ assign(data);
+}
+
+void Uuid::assign(const uint8_t* data) {
+ uuid_copy(c_array(), data);
+}
+
+void Uuid::generate() {
+ uuid_generate(c_array());
+}
+
+void Uuid::clear() {
+ uuid_clear(c_array());
+}
+
+// Force int 0/!0 to false/true; avoids compile warnings.
+bool Uuid::isNull() {
+ return !!uuid_is_null(data());
+}
+
void Uuid::encode(Buffer& buf) const {
buf.putRawData(data(), size());
}
diff --git a/qpid/cpp/src/qpid/management/Manageable.cpp b/qpid/cpp/src/qpid/management/Manageable.cpp
index e487dfc455..a3593e73e3 100644
--- a/qpid/cpp/src/qpid/management/Manageable.cpp
+++ b/qpid/cpp/src/qpid/management/Manageable.cpp
@@ -33,7 +33,7 @@ string Manageable::StatusText (status_t status, string text)
case STATUS_UNKNOWN_OBJECT : return "UnknownObject";
case STATUS_UNKNOWN_METHOD : return "UnknownMethod";
case STATUS_NOT_IMPLEMENTED : return "NotImplemented";
- case STATUS_INVALID_PARAMETER : return "InvalidParameter";
+ case STATUS_PARAMETER_INVALID : return "InvalidParameter";
case STATUS_FEATURE_NOT_IMPLEMENTED : return "FeatureNotImplemented";
case STATUS_FORBIDDEN : return "Forbidden";
}
diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.cpp b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
index 2df10b1e95..0e462342d4 100644
--- a/qpid/cpp/src/qpid/management/ManagementAgent.cpp
+++ b/qpid/cpp/src/qpid/management/ManagementAgent.cpp
@@ -535,8 +535,8 @@ void ManagementAgent::handleMethodRequestLH (Buffer& inBuffer, string replyToKey
} else {
if ((iter->second->getPackageName() != packageName) ||
(iter->second->getClassName() != className)) {
- outBuffer.putLong (Manageable::STATUS_INVALID_PARAMETER);
- outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_INVALID_PARAMETER));
+ outBuffer.putLong (Manageable::STATUS_PARAMETER_INVALID);
+ outBuffer.putMediumString(Manageable::StatusText (Manageable::STATUS_PARAMETER_INVALID));
}
else
try {
diff --git a/qpid/cpp/src/qpid/messaging/Address.cpp b/qpid/cpp/src/qpid/messaging/Address.cpp
new file mode 100644
index 0000000000..ed35054a00
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/Address.cpp
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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 "qpid/messaging/Address.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+Address::Address() {}
+Address::Address(const std::string& address) : value(address) {}
+Address::Address(const std::string& address, const std::string& t) : value(address), type(t) {}
+Address::operator const std::string&() const { return value; }
+const std::string& Address::toStr() const { return value; }
+Address::operator bool() const { return !value.empty(); }
+bool Address::operator !() const { return value.empty(); }
+
+const std::string TYPE_SEPARATOR(":");
+
+std::ostream& operator<<(std::ostream& out, const Address& address)
+{
+ if (!address.type.empty()) {
+ out << address.type;
+ out << TYPE_SEPARATOR;
+ }
+ out << address.value;
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/Connection.cpp b/qpid/cpp/src/qpid/messaging/Connection.cpp
new file mode 100644
index 0000000000..feb6566008
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/Connection.cpp
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Connection.h"
+#include "qpid/messaging/ConnectionImpl.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/messaging/SessionImpl.h"
+#include "qpid/client/PrivateImplRef.h"
+#include "qpid/client/amqp0_10/ConnectionImpl.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<qpid::messaging::Connection> PI;
+
+}
+
+namespace messaging {
+
+using qpid::client::PI;
+
+Connection Connection::open(const std::string& url, const Variant::Map& options)
+{
+ //only support amqp 0-10 at present
+ Connection connection(new qpid::client::amqp0_10::ConnectionImpl(url, options));
+ return connection;
+}
+
+Connection::Connection(ConnectionImpl* impl) { PI::ctor(*this, impl); }
+Connection::Connection(const Connection& c) : qpid::client::Handle<ConnectionImpl>() { PI::copy(*this, c); }
+Connection& Connection::operator=(const Connection& c) { return PI::assign(*this, c); }
+Connection::~Connection() { PI::dtor(*this); }
+
+void Connection::close() { impl->close(); }
+Session Connection::newSession() { return impl->newSession(); }
+
+InvalidOptionString::InvalidOptionString(const std::string& msg) : Exception(msg) {}
+
+void parseKeyValuePair(const std::string& in, Variant::Map& out)
+{
+ std::string::size_type i = in.find('=');
+ if (i == std::string::npos || i == in.size() || in.find('=', i+1) != std::string::npos) {
+ throw InvalidOptionString(QPID_MSG("Cannot parse name-value pair from " << in));
+ } else {
+ out[in.substr(0, i)] = in.substr(i+1);
+ }
+}
+
+void parseOptionString(const std::string& in, Variant::Map& out)
+{
+ std::string::size_type start = 0;
+ std::string::size_type i = in.find('&');
+ while (i != std::string::npos) {
+ parseKeyValuePair(in.substr(start, i-start), out);
+ if (i < in.size()) {
+ start = i+1;
+ i = in.find('&', start);
+ } else {
+ i = std::string::npos;
+ }
+ }
+ parseKeyValuePair(in.substr(start), out);
+}
+
+Variant::Map parseOptionString(const std::string& in)
+{
+ Variant::Map map;
+ parseOptionString(in, map);
+ return map;
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/ConnectionImpl.h b/qpid/cpp/src/qpid/messaging/ConnectionImpl.h
new file mode 100644
index 0000000000..aa9e5b5fbe
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/ConnectionImpl.h
@@ -0,0 +1,45 @@
+#ifndef QPID_MESSAGING_CONNECTIONIMPL_H
+#define QPID_MESSAGING_CONNECTIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include <string>
+#include "qpid/RefCounted.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+class Session;
+
+class ConnectionImpl : public virtual qpid::RefCounted
+{
+ public:
+ virtual ~ConnectionImpl() {}
+ virtual void close() = 0;
+ virtual Session newSession() = 0;
+ private:
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_CONNECTIONIMPL_H*/
diff --git a/qpid/cpp/src/qpid/messaging/Filter.cpp b/qpid/cpp/src/qpid/messaging/Filter.cpp
new file mode 100644
index 0000000000..b06cbdb373
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/Filter.cpp
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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 "qpid/messaging/Filter.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+Filter::Filter(std::string t, std::string pattern) : type(t) { patterns.push_back(pattern); }
+Filter::Filter(std::string t, std::string pattern1, std::string pattern2) : type(t)
+{
+ patterns.push_back(pattern1);
+ patterns.push_back(pattern2);
+}
+
+const std::string Filter::WILDCARD("WILDCARD");
+const std::string Filter::EXACT_MATCH("EXACT_MATCH");
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/Message.cpp b/qpid/cpp/src/qpid/messaging/Message.cpp
new file mode 100644
index 0000000000..1d844b3027
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/Message.cpp
@@ -0,0 +1,70 @@
+/*
+ *
+ * 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 "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageImpl.h"
+
+namespace qpid {
+namespace messaging {
+
+Message::Message(const std::string& bytes) : impl(new MessageImpl(bytes)) {}
+Message::Message(const char* bytes, size_t count) : impl(new MessageImpl(bytes, count)) {}
+
+Message::Message(const Message& m) : impl(new MessageImpl(m.getBytes())) {}
+Message::~Message() { delete impl; }
+
+Message& Message::operator=(const Message& m) { *impl = *m.impl; return *this; }
+
+void Message::setReplyTo(const Address& d) { impl->setReplyTo(d); }
+const Address& Message::getReplyTo() const { return impl->getReplyTo(); }
+
+void Message::setSubject(const std::string& s) { impl->setSubject(s); }
+const std::string& Message::getSubject() const { return impl->getSubject(); }
+
+void Message::setContentType(const std::string& s) { impl->setContentType(s); }
+const std::string& Message::getContentType() const { return impl->getContentType(); }
+
+const VariantMap& Message::getHeaders() const { return impl->getHeaders(); }
+VariantMap& Message::getHeaders() { return impl->getHeaders(); }
+
+void Message::setBytes(const std::string& c) { impl->setBytes(c); }
+void Message::setBytes(const char* chars, size_t count) { impl->setBytes(chars, count); }
+const std::string& Message::getBytes() const { return impl->getBytes(); }
+std::string& Message::getBytes() { return impl->getBytes(); }
+
+const char* Message::getRawContent() const { return impl->getBytes().data(); }
+size_t Message::getContentSize() const { return impl->getBytes().size(); }
+
+MessageContent& Message::getContent() { return *impl; }
+const MessageContent& Message::getContent() const { return *impl; }
+void Message::setContent(const std::string& s) { *impl = s; }
+void Message::setContent(const Variant::Map& m) { *impl = m; }
+void Message::setContent(const Variant::List& l) { *impl = l; }
+
+void Message::encode(Codec& codec) { impl->encode(codec); }
+
+void Message::decode(Codec& codec) { impl->decode(codec); }
+
+std::ostream& operator<<(std::ostream& out, const MessageContent& content)
+{
+ return content.print(out);
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.cpp b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp
new file mode 100644
index 0000000000..5df9218e03
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp
@@ -0,0 +1,205 @@
+/*
+ *
+ * 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 "MessageImpl.h"
+#include "qpid/messaging/Message.h"
+
+namespace qpid {
+namespace messaging {
+
+namespace {
+const std::string EMPTY_STRING = "";
+}
+
+MessageImpl::MessageImpl(const std::string& c) : bytes(c), type(VAR_VOID), internalId(0) {}
+MessageImpl::MessageImpl(const char* chars, size_t count) : bytes(chars, count), type(VAR_VOID), internalId(0) {}
+
+void MessageImpl::setReplyTo(const Address& d) { replyTo = d; }
+const Address& MessageImpl::getReplyTo() const { return replyTo; }
+
+void MessageImpl::setSubject(const std::string& s) { subject = s; }
+const std::string& MessageImpl::getSubject() const { return subject; }
+
+void MessageImpl::setContentType(const std::string& s) { contentType = s; }
+const std::string& MessageImpl::getContentType() const { return contentType; }
+
+const VariantMap& MessageImpl::getHeaders() const { return headers; }
+VariantMap& MessageImpl::getHeaders() { return headers; }
+
+//should these methods be on MessageContent?
+void MessageImpl::setBytes(const std::string& c) { clear(); bytes = c; }
+void MessageImpl::setBytes(const char* chars, size_t count) { clear(); bytes.assign(chars, count); }
+const std::string& MessageImpl::getBytes() const { return bytes; }
+std::string& MessageImpl::getBytes() { return bytes; }
+
+
+Variant& MessageImpl::operator[](const std::string& key) { return asMap()[key]; }
+
+std::ostream& MessageImpl::print(std::ostream& out) const
+{
+ if (type == VAR_MAP) {
+ return out << content.asMap();
+ } else if (type == VAR_LIST) {
+ return out << content.asList();
+ } else {
+ return out << bytes;
+ }
+}
+
+template <class T> MessageContent& MessageImpl::append(T& t)
+{
+ if (type == VAR_VOID) {
+ //TODO: this is inefficient, probably want to hold on to the stream object
+ std::stringstream s;
+ s << bytes;
+ s << t;
+ bytes = s.str();
+ } else if (type == VAR_LIST) {
+ content.asList().push_back(Variant(t));
+ } else {
+ throw InvalidConversion("<< operator only valid on strings and lists");
+ }
+ return *this;
+}
+
+MessageContent& MessageImpl::operator<<(const std::string& v) { return append(v); }
+MessageContent& MessageImpl::operator<<(const char* v) { return append(v); }
+MessageContent& MessageImpl::operator<<(bool v) { return append(v); }
+MessageContent& MessageImpl::operator<<(int8_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(int16_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(int32_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(int64_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(uint8_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(uint16_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(uint32_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(uint64_t v) { return append(v); }
+MessageContent& MessageImpl::operator<<(double v) { return append(v); }
+MessageContent& MessageImpl::operator<<(float v) { return append(v); }
+MessageContent& MessageImpl::operator=(const std::string& s)
+{
+ type = VAR_VOID;
+ bytes = s;
+ return *this;
+}
+MessageContent& MessageImpl::operator=(const char* c)
+{
+ type = VAR_VOID;
+ bytes = c;
+ return *this;
+}
+MessageContent& MessageImpl::operator=(const Variant::Map& m)
+{
+ type = VAR_MAP;
+ content = m;
+ return *this;
+}
+
+MessageContent& MessageImpl::operator=(const Variant::List& l)
+{
+ type = VAR_LIST;
+ content = l;
+ return *this;
+}
+
+void MessageImpl::encode(Codec& codec)
+{
+ if (content.getType() != VAR_VOID) {
+ bytes = EMPTY_STRING;
+ codec.encode(content, bytes);
+ }
+}
+
+void MessageImpl::getEncodedContent(Codec& codec, std::string& out) const
+{
+ if (content.getType() != VAR_VOID) {
+ codec.encode(content, out);
+ } else {
+ out = bytes;
+ }
+}
+
+void MessageImpl::decode(Codec& codec)
+{
+ codec.decode(bytes, content);
+ if (content.getType() == VAR_MAP) type = VAR_MAP;
+ else if (content.getType() == VAR_LIST) type = VAR_LIST;
+ else type = VAR_VOID;//TODO: what if codec set some type other than map or list??
+}
+
+void MessageImpl::setInternalId(qpid::framing::SequenceNumber i) { internalId = i; }
+qpid::framing::SequenceNumber MessageImpl::getInternalId() { return internalId; }
+
+bool MessageImpl::isVoid() const { return type == VAR_VOID; }
+
+const std::string& MessageImpl::asString() const
+{
+ if (isVoid()) return getBytes();
+ else return content.getString();//will throw an error
+}
+std::string& MessageImpl::asString()
+{
+ if (isVoid()) return getBytes();
+ else return content.getString();//will throw an error
+}
+
+const char* MessageImpl::asChars() const
+{
+ if (!isVoid()) throw InvalidConversion("Content is of structured type.");
+ return bytes.data();
+}
+size_t MessageImpl::size() const
+{
+ return bytes.size();
+}
+
+const Variant::Map& MessageImpl::asMap() const { return content.asMap(); }
+Variant::Map& MessageImpl::asMap()
+{
+ if (isVoid()) {
+ content = Variant::Map();
+ type = VAR_MAP;
+ }
+ return content.asMap();
+}
+bool MessageImpl::isMap() const { return type == VAR_MAP; }
+
+const Variant::List& MessageImpl::asList() const { return content.asList(); }
+Variant::List& MessageImpl::asList()
+{
+ if (isVoid()) {
+ content = Variant::List();
+ type = VAR_LIST;
+ }
+ return content.asList();
+}
+bool MessageImpl::isList() const { return type == VAR_LIST; }
+
+void MessageImpl::clear() { bytes = EMPTY_STRING; content.reset(); type = VAR_VOID; }
+
+MessageImpl& MessageImplAccess::get(Message& msg)
+{
+ return *msg.impl;
+}
+const MessageImpl& MessageImplAccess::get(const Message& msg)
+{
+ return *msg.impl;
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.h b/qpid/cpp/src/qpid/messaging/MessageImpl.h
new file mode 100644
index 0000000000..1173e7570a
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/MessageImpl.h
@@ -0,0 +1,134 @@
+#ifndef QPID_MESSAGING_MESSAGEIMPL_H
+#define QPID_MESSAGING_MESSAGEIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Codec.h"
+#include "qpid/messaging/MessageContent.h"
+#include "qpid/messaging/Variant.h"
+#include "qpid/framing/SequenceNumber.h"
+
+namespace qpid {
+namespace messaging {
+
+struct MessageImpl : MessageContent
+{
+ Address replyTo;
+ std::string subject;
+ std::string contentType;
+ Variant::Map headers;
+
+ std::string bytes;
+ Variant content;//used only for LIST and MAP
+ VariantType type;//if LIST, MAP content holds the value; if VOID bytes holds the value
+
+ qpid::framing::SequenceNumber internalId;
+
+ MessageImpl(const std::string& c);
+ MessageImpl(const char* chars, size_t count);
+
+ void setReplyTo(const Address& d);
+ const Address& getReplyTo() const;
+
+ void setSubject(const std::string& s);
+ const std::string& getSubject() const;
+
+ void setContentType(const std::string& s);
+ const std::string& getContentType() const;
+
+ const Variant::Map& getHeaders() const;
+ Variant::Map& getHeaders();
+
+ void setBytes(const std::string& bytes);
+ void setBytes(const char* chars, size_t count);
+ const std::string& getBytes() const;
+ std::string& getBytes();
+
+ void setInternalId(qpid::framing::SequenceNumber id);
+ qpid::framing::SequenceNumber getInternalId();
+
+ bool isVoid() const;
+
+ const std::string& asString() const;
+ std::string& asString();
+
+ const char* asChars() const;
+ size_t size() const;
+
+ const Variant::Map& asMap() const;
+ Variant::Map& asMap();
+ bool isMap() const;
+
+ const Variant::List& asList() const;
+ Variant::List& asList();
+ bool isList() const;
+
+ void clear();
+
+ void getEncodedContent(Codec& codec, std::string&) const;
+ void encode(Codec& codec);
+ void decode(Codec& codec);
+
+ Variant& operator[](const std::string&);
+
+ std::ostream& print(std::ostream& out) const;
+
+ //operator<< for variety of types...
+ MessageContent& operator<<(const std::string&);
+ MessageContent& operator<<(const char*);
+ MessageContent& operator<<(bool);
+ MessageContent& operator<<(int8_t);
+ MessageContent& operator<<(int16_t);
+ MessageContent& operator<<(int32_t);
+ MessageContent& operator<<(int64_t);
+ MessageContent& operator<<(uint8_t);
+ MessageContent& operator<<(uint16_t);
+ MessageContent& operator<<(uint32_t);
+ MessageContent& operator<<(uint64_t);
+ MessageContent& operator<<(double);
+ MessageContent& operator<<(float);
+
+ //assignment from string, map and list
+ MessageContent& operator=(const std::string&);
+ MessageContent& operator=(const char*);
+ MessageContent& operator=(const Variant::Map&);
+ MessageContent& operator=(const Variant::List&);
+
+ template <class T> MessageContent& append(T& t);
+};
+
+class Message;
+
+/**
+ * Provides access to the internal MessageImpl for a message which is
+ * useful when accessing any message state not exposed directly
+ * through the public API.
+ */
+struct MessageImplAccess
+{
+ static MessageImpl& get(Message&);
+ static const MessageImpl& get(const Message&);
+};
+
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_MESSAGEIMPL_H*/
diff --git a/qpid/cpp/src/qpid/messaging/Receiver.cpp b/qpid/cpp/src/qpid/messaging/Receiver.cpp
new file mode 100644
index 0000000000..2e8b89d27f
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/Receiver.cpp
@@ -0,0 +1,51 @@
+/*
+ *
+ * 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 "qpid/messaging/Receiver.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/ReceiverImpl.h"
+#include "qpid/client/PrivateImplRef.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<qpid::messaging::Receiver> PI;
+
+}
+
+namespace messaging {
+
+using qpid::client::PI;
+
+Receiver::Receiver(ReceiverImpl* impl) { PI::ctor(*this, impl); }
+Receiver::Receiver(const Receiver& s) : qpid::client::Handle<ReceiverImpl>() { PI::copy(*this, s); }
+Receiver::~Receiver() { PI::dtor(*this); }
+Receiver& Receiver::operator=(const Receiver& s) { return PI::assign(*this, s); }
+bool Receiver::get(Message& message, qpid::sys::Duration timeout) { return impl->get(message, timeout); }
+Message Receiver::get(qpid::sys::Duration timeout) { return impl->get(timeout); }
+bool Receiver::fetch(Message& message, qpid::sys::Duration timeout) { return impl->fetch(message, timeout); }
+Message Receiver::fetch(qpid::sys::Duration timeout) { return impl->fetch(timeout); }
+void Receiver::start() { impl->start(); }
+void Receiver::stop() { impl->stop(); }
+void Receiver::setCapacity(uint32_t c) { impl->setCapacity(c); }
+void Receiver::cancel() { impl->cancel(); }
+void Receiver::setListener(MessageListener* listener) { impl->setListener(listener); }
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/ReceiverImpl.h b/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
new file mode 100644
index 0000000000..77697b730c
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/ReceiverImpl.h
@@ -0,0 +1,52 @@
+#ifndef QPID_MESSAGING_RECEIVERIMPL_H
+#define QPID_MESSAGING_RECEIVERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/RefCounted.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+class Message;
+class MessageListener;
+
+class ReceiverImpl : public virtual qpid::RefCounted
+{
+ public:
+ virtual ~ReceiverImpl() {}
+ virtual bool get(Message& message, qpid::sys::Duration timeout) = 0;
+ virtual Message get(qpid::sys::Duration timeout) = 0;
+ virtual bool fetch(Message& message, qpid::sys::Duration timeout) = 0;
+ virtual Message fetch(qpid::sys::Duration timeout) = 0;
+ virtual void start() = 0;
+ virtual void stop() = 0;
+ virtual void setCapacity(uint32_t) = 0;
+ virtual void cancel() = 0;
+ virtual void setListener(MessageListener*) = 0;
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_RECEIVERIMPL_H*/
diff --git a/qpid/cpp/src/qpid/messaging/Sender.cpp b/qpid/cpp/src/qpid/messaging/Sender.cpp
new file mode 100644
index 0000000000..8db700b060
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/Sender.cpp
@@ -0,0 +1,44 @@
+/*
+ *
+ * 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 "qpid/messaging/Sender.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/SenderImpl.h"
+#include "qpid/client/PrivateImplRef.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<qpid::messaging::Sender> PI;
+
+}
+
+namespace messaging {
+
+using qpid::client::PI;
+
+Sender::Sender(SenderImpl* impl) { PI::ctor(*this, impl); }
+Sender::Sender(const Sender& s) : qpid::client::Handle<SenderImpl>() { PI::copy(*this, s); }
+Sender::~Sender() { PI::dtor(*this); }
+Sender& Sender::operator=(const Sender& s) { return PI::assign(*this, s); }
+void Sender::send(const Message& message) { impl->send(message); }
+void Sender::cancel() { impl->cancel(); }
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/SenderImpl.h b/qpid/cpp/src/qpid/messaging/SenderImpl.h
new file mode 100644
index 0000000000..77d2cfaeaf
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/SenderImpl.h
@@ -0,0 +1,44 @@
+#ifndef QPID_MESSAGING_SENDERIMPL_H
+#define QPID_MESSAGING_SENDERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/RefCounted.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+class Message;
+
+class SenderImpl : public virtual qpid::RefCounted
+{
+ public:
+ virtual ~SenderImpl() {}
+ virtual void send(const Message& message) = 0;
+ virtual void cancel() = 0;
+ private:
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_SENDERIMPL_H*/
diff --git a/qpid/cpp/src/qpid/messaging/Session.cpp b/qpid/cpp/src/qpid/messaging/Session.cpp
new file mode 100644
index 0000000000..284b20dacc
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/Session.cpp
@@ -0,0 +1,117 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/messaging/Session.h"
+#include "qpid/messaging/Address.h"
+#include "qpid/messaging/Filter.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/Sender.h"
+#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/SessionImpl.h"
+#include "qpid/client/PrivateImplRef.h"
+
+namespace qpid {
+namespace client {
+
+typedef PrivateImplRef<qpid::messaging::Session> PI;
+
+}
+
+namespace messaging {
+
+using qpid::client::PI;
+
+Session::Session(SessionImpl* impl) { PI::ctor(*this, impl); }
+Session::Session(const Session& s) : qpid::client::Handle<SessionImpl>() { PI::copy(*this, s); }
+Session::~Session() { PI::dtor(*this); }
+Session& Session::operator=(const Session& s) { return PI::assign(*this, s); }
+void Session::commit() { impl->commit(); }
+void Session::rollback() { impl->rollback(); }
+void Session::acknowledge() { impl->acknowledge(); }
+void Session::reject(Message& m) { impl->reject(m); }
+void Session::close() { impl->close(); }
+
+Sender Session::createSender(const Address& address, const VariantMap& options)
+{
+ return impl->createSender(address, options);
+}
+Receiver Session::createReceiver(const Address& address, const VariantMap& options)
+{
+ return impl->createReceiver(address, options);
+}
+Receiver Session::createReceiver(const Address& address, const Filter& filter, const VariantMap& options)
+{
+ return impl->createReceiver(address, filter, options);
+}
+
+Sender Session::createSender(const std::string& address, const VariantMap& options)
+{
+ return impl->createSender(Address(address), options);
+}
+Receiver Session::createReceiver(const std::string& address, const VariantMap& options)
+{
+ return impl->createReceiver(Address(address), options);
+}
+Receiver Session::createReceiver(const std::string& address, const Filter& filter, const VariantMap& options)
+{
+ return impl->createReceiver(Address(address), filter, options);
+}
+
+Address Session::createTempQueue(const std::string& baseName)
+{
+ return impl->createTempQueue(baseName);
+}
+
+void Session::sync()
+{
+ impl->sync();
+}
+
+void Session::flush()
+{
+ impl->flush();
+}
+
+bool Session::fetch(Message& message, qpid::sys::Duration timeout)
+{
+ return impl->fetch(message, timeout);
+}
+
+Message Session::fetch(qpid::sys::Duration timeout)
+{
+ return impl->fetch(timeout);
+}
+
+bool Session::dispatch(qpid::sys::Duration timeout)
+{
+ return impl->dispatch(timeout);
+}
+
+void* Session::getLastConfirmedSent()
+{
+ return impl->getLastConfirmedSent();
+}
+
+void* Session::getLastConfirmedAcknowledged()
+{
+ return impl->getLastConfirmedAcknowledged();
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/messaging/SessionImpl.h b/qpid/cpp/src/qpid/messaging/SessionImpl.h
new file mode 100644
index 0000000000..9b122a24bc
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/SessionImpl.h
@@ -0,0 +1,65 @@
+#ifndef QPID_MESSAGING_SESSIONIMPL_H
+#define QPID_MESSAGING_SESSIONIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/RefCounted.h"
+#include <string>
+#include "qpid/messaging/Variant.h"
+#include "qpid/sys/Time.h"
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+struct Address;
+struct Filter;
+class Message;
+class Sender;
+class Receiver;
+
+class SessionImpl : public virtual qpid::RefCounted
+{
+ public:
+ virtual ~SessionImpl() {}
+ virtual void commit() = 0;
+ virtual void rollback() = 0;
+ virtual void acknowledge() = 0;
+ virtual void reject(Message&) = 0;
+ virtual void close() = 0;
+ virtual void sync() = 0;
+ virtual void flush() = 0;
+ virtual bool fetch(Message& message, qpid::sys::Duration timeout) = 0;
+ virtual Message fetch(qpid::sys::Duration timeout) = 0;
+ virtual bool dispatch(qpid::sys::Duration timeout) = 0;
+ virtual Address createTempQueue(const std::string& baseName) = 0;
+ virtual Sender createSender(const Address& address, const VariantMap& options) = 0;
+ virtual Receiver createReceiver(const Address& address, const VariantMap& options) = 0;
+ virtual Receiver createReceiver(const Address& address, const Filter& filter, const VariantMap& options) = 0;
+ virtual void* getLastConfirmedSent() = 0;
+ virtual void* getLastConfirmedAcknowledged() = 0;
+ private:
+};
+}} // namespace qpid::messaging
+
+#endif /*!QPID_MESSAGING_SESSIONIMPL_H*/
diff --git a/qpid/cpp/src/qpid/messaging/Variant.cpp b/qpid/cpp/src/qpid/messaging/Variant.cpp
new file mode 100644
index 0000000000..4e37134b39
--- /dev/null
+++ b/qpid/cpp/src/qpid/messaging/Variant.cpp
@@ -0,0 +1,603 @@
+/*
+ *
+ * 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 "qpid/messaging/Variant.h"
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace qpid {
+namespace client {
+}
+
+namespace messaging {
+
+InvalidConversion::InvalidConversion(const std::string& msg) : Exception(msg) {}
+
+
+namespace {
+std::string EMPTY;
+}
+
+class VariantImpl
+{
+ public:
+ VariantImpl();
+ VariantImpl(bool);
+ VariantImpl(uint8_t);
+ VariantImpl(uint16_t);
+ VariantImpl(uint32_t);
+ VariantImpl(uint64_t);
+ VariantImpl(int8_t);
+ VariantImpl(int16_t);
+ VariantImpl(int32_t);
+ VariantImpl(int64_t);
+ VariantImpl(float);
+ VariantImpl(double);
+ VariantImpl(const std::string&);
+ VariantImpl(const Variant::Map&);
+ VariantImpl(const Variant::List&);
+ ~VariantImpl();
+
+ VariantType getType() const;
+
+ bool asBool() const;
+ uint8_t asUint8() const;
+ uint16_t asUint16() const;
+ uint32_t asUint32() const;
+ uint64_t asUint64() const;
+ int8_t asInt8() const;
+ int16_t asInt16() const;
+ int32_t asInt32() const;
+ int64_t asInt64() const;
+ float asFloat() const;
+ double asDouble() const;
+ std::string asString() const;
+
+ const Variant::Map& asMap() const;
+ Variant::Map& asMap();
+ const Variant::List& asList() const;
+ Variant::List& asList();
+
+ const std::string& getString() const;
+ std::string& getString();
+
+ void setEncoding(const std::string&);
+ const std::string& getEncoding() const;
+
+ static VariantImpl* create(const Variant&);
+ private:
+ const VariantType type;
+ union {
+ bool b;
+ uint8_t ui8;
+ uint16_t ui16;
+ uint32_t ui32;
+ uint64_t ui64;
+ int8_t i8;
+ int16_t i16;
+ int32_t i32;
+ int64_t i64;
+ float f;
+ double d;
+ void* v;//variable width data
+ } value;
+ std::string encoding;//optional encoding for variable length data
+
+ std::string getTypeName(VariantType type) const;
+ template<class T> T convertFromString() const
+ {
+ std::string* s = reinterpret_cast<std::string*>(value.v);
+ try {
+ return boost::lexical_cast<T>(*s);
+ } catch(const boost::bad_lexical_cast&) {
+ throw InvalidConversion(QPID_MSG("Cannot convert " << *s));
+ }
+ }
+};
+
+
+VariantImpl::VariantImpl() : type(VAR_VOID) { value.i64 = 0; }
+VariantImpl::VariantImpl(bool b) : type(VAR_BOOL) { value.b = b; }
+VariantImpl::VariantImpl(uint8_t i) : type(VAR_UINT8) { value.ui8 = i; }
+VariantImpl::VariantImpl(uint16_t i) : type(VAR_UINT16) { value.ui16 = i; }
+VariantImpl::VariantImpl(uint32_t i) : type(VAR_UINT32) { value.ui32 = i; }
+VariantImpl::VariantImpl(uint64_t i) : type(VAR_UINT64) { value.ui64 = i; }
+VariantImpl::VariantImpl(int8_t i) : type(VAR_INT8) { value.i8 = i; }
+VariantImpl::VariantImpl(int16_t i) : type(VAR_INT16) { value.i16 = i; }
+VariantImpl::VariantImpl(int32_t i) : type(VAR_INT32) { value.i32 = i; }
+VariantImpl::VariantImpl(int64_t i) : type(VAR_INT64) { value.i64 = i; }
+VariantImpl::VariantImpl(float f) : type(VAR_FLOAT) { value.f = f; }
+VariantImpl::VariantImpl(double d) : type(VAR_DOUBLE) { value.d = d; }
+VariantImpl::VariantImpl(const std::string& s) : type(VAR_STRING) { value.v = new std::string(s); }
+VariantImpl::VariantImpl(const Variant::Map& m) : type(VAR_MAP) { value.v = new Variant::Map(m); }
+VariantImpl::VariantImpl(const Variant::List& l) : type(VAR_LIST) { value.v = new Variant::List(l); }
+
+VariantImpl::~VariantImpl() {
+ switch (type) {
+ case VAR_STRING:
+ delete reinterpret_cast<std::string*>(value.v);
+ break;
+ case VAR_MAP:
+ delete reinterpret_cast<Variant::Map*>(value.v);
+ break;
+ case VAR_LIST:
+ delete reinterpret_cast<Variant::List*>(value.v);
+ break;
+ default:
+ break;
+ }
+}
+
+VariantType VariantImpl::getType() const { return type; }
+
+namespace {
+
+bool same_char(char a, char b)
+{
+ return toupper(a) == toupper(b);
+}
+
+bool caseInsensitiveMatch(const std::string& a, const std::string& b)
+{
+ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin(), &same_char);
+}
+
+const std::string TRUE("True");
+const std::string FALSE("False");
+
+bool toBool(const std::string& s)
+{
+ if (caseInsensitiveMatch(s, TRUE)) return true;
+ if (caseInsensitiveMatch(s, FALSE)) return false;
+ try { return boost::lexical_cast<int>(s); } catch(const boost::bad_lexical_cast&) {}
+ throw InvalidConversion(QPID_MSG("Cannot convert " << s << " to bool"));
+}
+
+}
+
+bool VariantImpl::asBool() const
+{
+ switch(type) {
+ case VAR_VOID: return false;
+ case VAR_BOOL: return value.b;
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_UINT32: return value.ui32;
+ case VAR_UINT64: return value.ui64;
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_INT32: return value.i32;
+ case VAR_INT64: return value.i64;
+ case VAR_STRING: return toBool(*reinterpret_cast<std::string*>(value.v));
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_BOOL)));
+ }
+}
+uint8_t VariantImpl::asUint8() const
+{
+ switch(type) {
+ case VAR_UINT8: return value.ui8;
+ case VAR_STRING: return convertFromString<uint8_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT8)));
+ }
+}
+uint16_t VariantImpl::asUint16() const
+{
+ switch(type) {
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_STRING: return convertFromString<uint16_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT16)));
+ }
+}
+uint32_t VariantImpl::asUint32() const
+{
+ switch(type) {
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_UINT32: return value.ui32;
+ case VAR_STRING: return convertFromString<uint32_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT32)));
+ }
+}
+uint64_t VariantImpl::asUint64() const
+{
+ switch(type) {
+ case VAR_UINT8: return value.ui8;
+ case VAR_UINT16: return value.ui16;
+ case VAR_UINT32: return value.ui32;
+ case VAR_UINT64: return value.ui64;
+ case VAR_STRING: return convertFromString<uint64_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_UINT64)));
+ }
+}
+int8_t VariantImpl::asInt8() const
+{
+ switch(type) {
+ case VAR_INT8: return value.i8;
+ case VAR_STRING: return convertFromString<int8_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT8)));
+ }
+}
+int16_t VariantImpl::asInt16() const
+{
+ switch(type) {
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_STRING: return convertFromString<int16_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT16)));
+ }
+}
+int32_t VariantImpl::asInt32() const
+{
+ switch(type) {
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_INT32: return value.i32;
+ case VAR_STRING: return convertFromString<int32_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT32)));
+ }
+}
+int64_t VariantImpl::asInt64() const
+{
+ switch(type) {
+ case VAR_INT8: return value.i8;
+ case VAR_INT16: return value.i16;
+ case VAR_INT32: return value.i32;
+ case VAR_INT64: return value.i64;
+ case VAR_STRING: return convertFromString<int64_t>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_INT64)));
+ }
+}
+float VariantImpl::asFloat() const
+{
+ switch(type) {
+ case VAR_FLOAT: return value.f;
+ case VAR_STRING: return convertFromString<float>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_FLOAT)));
+ }
+}
+double VariantImpl::asDouble() const
+{
+ switch(type) {
+ case VAR_FLOAT: return value.f;
+ case VAR_DOUBLE: return value.d;
+ case VAR_STRING: return convertFromString<double>();
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_DOUBLE)));
+ }
+}
+std::string VariantImpl::asString() const
+{
+ switch(type) {
+ case VAR_VOID: return EMPTY;
+ case VAR_BOOL: return value.b ? TRUE : FALSE;
+ case VAR_UINT8: return boost::lexical_cast<std::string>((int) value.ui8);
+ case VAR_UINT16: return boost::lexical_cast<std::string>(value.ui16);
+ case VAR_UINT32: return boost::lexical_cast<std::string>(value.ui32);
+ case VAR_UINT64: return boost::lexical_cast<std::string>(value.ui64);
+ case VAR_INT8: return boost::lexical_cast<std::string>((int) value.i8);
+ case VAR_INT16: return boost::lexical_cast<std::string>(value.i16);
+ case VAR_INT32: return boost::lexical_cast<std::string>(value.i32);
+ case VAR_INT64: return boost::lexical_cast<std::string>(value.i64);
+ case VAR_DOUBLE: return boost::lexical_cast<std::string>(value.d);
+ case VAR_FLOAT: return boost::lexical_cast<std::string>(value.f);
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_STRING)));
+ }
+}
+
+const Variant::Map& VariantImpl::asMap() const
+{
+ switch(type) {
+ case VAR_MAP: return *reinterpret_cast<Variant::Map*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_MAP)));
+ }
+}
+
+Variant::Map& VariantImpl::asMap()
+{
+ switch(type) {
+ case VAR_MAP: return *reinterpret_cast<Variant::Map*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_MAP)));
+ }
+}
+
+const Variant::List& VariantImpl::asList() const
+{
+ switch(type) {
+ case VAR_LIST: return *reinterpret_cast<Variant::List*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_LIST)));
+ }
+}
+
+Variant::List& VariantImpl::asList()
+{
+ switch(type) {
+ case VAR_LIST: return *reinterpret_cast<Variant::List*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Cannot convert from " << getTypeName(type) << " to " << getTypeName(VAR_LIST)));
+ }
+}
+
+std::string& VariantImpl::getString()
+{
+ switch(type) {
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Variant is not a string; use asString() if conversion is required."));
+ }
+}
+
+const std::string& VariantImpl::getString() const
+{
+ switch(type) {
+ case VAR_STRING: return *reinterpret_cast<std::string*>(value.v);
+ default: throw InvalidConversion(QPID_MSG("Variant is not a string; use asString() if conversion is required."));
+ }
+}
+
+void VariantImpl::setEncoding(const std::string& s) { encoding = s; }
+const std::string& VariantImpl::getEncoding() const { return encoding; }
+
+std::string VariantImpl::getTypeName(VariantType type) const
+{
+ switch (type) {
+ case VAR_VOID: return "void";
+ case VAR_BOOL: return "bool";
+ case VAR_UINT8: return "uint8";
+ case VAR_UINT16: return "uint16";
+ case VAR_UINT32: return "uint32";
+ case VAR_UINT64: return "uint64";
+ case VAR_INT8: return "int8";
+ case VAR_INT16: return "int16";
+ case VAR_INT32: return "int32";
+ case VAR_INT64: return "int64";
+ case VAR_FLOAT: return "float";
+ case VAR_DOUBLE: return "double";
+ case VAR_STRING: return "string";
+ case VAR_MAP: return "map";
+ case VAR_LIST: return "list";
+ }
+ return "<unknown>";//should never happen
+}
+
+VariantImpl* VariantImpl::create(const Variant& v)
+{
+ switch (v.getType()) {
+ case VAR_BOOL: return new VariantImpl(v.asBool());
+ case VAR_UINT8: return new VariantImpl(v.asUint8());
+ case VAR_UINT16: return new VariantImpl(v.asUint16());
+ case VAR_UINT32: return new VariantImpl(v.asUint32());
+ case VAR_UINT64: return new VariantImpl(v.asUint64());
+ case VAR_INT8: return new VariantImpl(v.asInt8());
+ case VAR_INT16: return new VariantImpl(v.asInt16());
+ case VAR_INT32: return new VariantImpl(v.asInt32());
+ case VAR_INT64: return new VariantImpl(v.asInt64());
+ case VAR_FLOAT: return new VariantImpl(v.asFloat());
+ case VAR_DOUBLE: return new VariantImpl(v.asDouble());
+ case VAR_STRING: return new VariantImpl(v.asString());
+ case VAR_MAP: return new VariantImpl(v.asMap());
+ case VAR_LIST: return new VariantImpl(v.asList());
+ default: return new VariantImpl();
+ }
+}
+
+Variant::Variant() : impl(new VariantImpl()) {}
+Variant::Variant(bool b) : impl(new VariantImpl(b)) {}
+Variant::Variant(uint8_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(uint16_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(uint32_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(uint64_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(int8_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(int16_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(int32_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(int64_t i) : impl(new VariantImpl(i)) {}
+Variant::Variant(float f) : impl(new VariantImpl(f)) {}
+Variant::Variant(double d) : impl(new VariantImpl(d)) {}
+Variant::Variant(const std::string& s) : impl(new VariantImpl(s)) {}
+Variant::Variant(const char* s) : impl(new VariantImpl(std::string(s))) {}
+Variant::Variant(const Map& m) : impl(new VariantImpl(m)) {}
+Variant::Variant(const List& l) : impl(new VariantImpl(l)) {}
+Variant::Variant(const Variant& v) : impl(VariantImpl::create(v)) {}
+
+Variant::~Variant() { if (impl) delete impl; }
+
+void Variant::reset()
+{
+ if (impl) delete impl;
+ impl = new VariantImpl();
+}
+
+
+Variant& Variant::operator=(bool b)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(b);
+ return *this;
+}
+
+Variant& Variant::operator=(uint8_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(uint16_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(uint32_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(uint64_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+
+Variant& Variant::operator=(int8_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(int16_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(int32_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+Variant& Variant::operator=(int64_t i)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(i);
+ return *this;
+}
+
+Variant& Variant::operator=(float f)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(f);
+ return *this;
+}
+Variant& Variant::operator=(double d)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(d);
+ return *this;
+}
+
+Variant& Variant::operator=(const std::string& s)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(s);
+ return *this;
+}
+
+Variant& Variant::operator=(const char* s)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(std::string(s));
+ return *this;
+}
+
+Variant& Variant::operator=(const Map& m)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(m);
+ return *this;
+}
+
+Variant& Variant::operator=(const List& l)
+{
+ if (impl) delete impl;
+ impl = new VariantImpl(l);
+ return *this;
+}
+
+Variant& Variant::operator=(const Variant& v)
+{
+ if (impl) delete impl;
+ impl = VariantImpl::create(v);
+ return *this;
+}
+
+VariantType Variant::getType() const { return impl->getType(); }
+bool Variant::asBool() const { return impl->asBool(); }
+uint8_t Variant::asUint8() const { return impl->asUint8(); }
+uint16_t Variant::asUint16() const { return impl->asUint16(); }
+uint32_t Variant::asUint32() const { return impl->asUint32(); }
+uint64_t Variant::asUint64() const { return impl->asUint64(); }
+int8_t Variant::asInt8() const { return impl->asInt8(); }
+int16_t Variant::asInt16() const { return impl->asInt16(); }
+int32_t Variant::asInt32() const { return impl->asInt32(); }
+int64_t Variant::asInt64() const { return impl->asInt64(); }
+float Variant::asFloat() const { return impl->asFloat(); }
+double Variant::asDouble() const { return impl->asDouble(); }
+std::string Variant::asString() const { return impl->asString(); }
+const Variant::Map& Variant::asMap() const { return impl->asMap(); }
+Variant::Map& Variant::asMap() { return impl->asMap(); }
+const Variant::List& Variant::asList() const { return impl->asList(); }
+Variant::List& Variant::asList() { return impl->asList(); }
+const std::string& Variant::getString() const { return impl->getString(); }
+std::string& Variant::getString() { return impl->getString(); }
+void Variant::setEncoding(const std::string& s) { impl->setEncoding(s); }
+const std::string& Variant::getEncoding() const { return impl->getEncoding(); }
+
+Variant::operator bool() const { return asBool(); }
+Variant::operator uint8_t() const { return asUint8(); }
+Variant::operator uint16_t() const { return asUint16(); }
+Variant::operator uint32_t() const { return asUint32(); }
+Variant::operator uint64_t() const { return asUint64(); }
+Variant::operator int8_t() const { return asInt8(); }
+Variant::operator int16_t() const { return asInt16(); }
+Variant::operator int32_t() const { return asInt32(); }
+Variant::operator int64_t() const { return asInt64(); }
+Variant::operator float() const { return asFloat(); }
+Variant::operator double() const { return asDouble(); }
+Variant::operator const char*() const { return asString().c_str(); }
+
+std::ostream& operator<<(std::ostream& out, const Variant::Map& map)
+{
+ for (Variant::Map::const_iterator i = map.begin(); i != map.end(); ++i) {
+ if (i != map.begin()) out << ", ";
+ out << i->first << ":" << i->second;
+ }
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const Variant::List& list)
+{
+ for (Variant::List::const_iterator i = list.begin(); i != list.end(); ++i) {
+ if (i != list.begin()) out << ", ";
+ out << *i;
+ }
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const Variant& value)
+{
+ switch (value.getType()) {
+ case VAR_MAP:
+ out << "{" << value.asMap() << "}";
+ break;
+ case VAR_LIST:
+ out << "[" << value.asList() << "]";
+ break;
+ case VAR_VOID:
+ out << "<void>";
+ break;
+ default:
+ out << value.asString();
+ break;
+ }
+ return out;
+}
+
+}} // namespace qpid::messaging
diff --git a/qpid/cpp/src/qpid/sys/Timer.cpp b/qpid/cpp/src/qpid/sys/Timer.cpp
index d569fb3bb7..3d2a900455 100644
--- a/qpid/cpp/src/qpid/sys/Timer.cpp
+++ b/qpid/cpp/src/qpid/sys/Timer.cpp
@@ -84,6 +84,7 @@ Timer::~Timer()
stop();
}
+// TODO AStitcher 21/08/09 The threshholds for emitting warnings are a little arbitrary
void Timer::run()
{
Monitor::ScopedLock l(monitor);
@@ -111,8 +112,8 @@ void Timer::run()
// Warn on callback overrun
AbsTime end(AbsTime::now());
Duration overrun(tasks.top()->nextFireTime, end);
- bool late = delay > 1 * TIME_MSEC;
- bool overran = overrun > 1 * TIME_MSEC;
+ bool late = delay > 10 * TIME_MSEC;
+ bool overran = overrun > 2 * TIME_MSEC;
if (late)
if (overran) {
QPID_LOG(warning,
diff --git a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
index 5d1ac6d034..8545ebd9cb 100644
--- a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
+++ b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp
@@ -305,6 +305,13 @@ private:
* thread processing this handle.
*/
volatile bool writePending;
+ /**
+ * This records whether we've been reading is flow controlled:
+ * it's safe as a simple boolean as the only way to be stopped
+ * is in calls only allowed in the callback context, the only calls
+ * checking it are also in calls only allowed in callback context.
+ */
+ volatile bool readingStopped;
};
AsynchIO::AsynchIO(const Socket& s,
@@ -323,7 +330,8 @@ AsynchIO::AsynchIO(const Socket& s,
idleCallback(iCb),
socket(s),
queuedClose(false),
- writePending(false) {
+ writePending(false),
+ readingStopped(false) {
s.setNonblocking();
}
@@ -351,8 +359,11 @@ void AsynchIO::queueReadBuffer(BufferBase* buff) {
assert(buff);
buff->dataStart = 0;
buff->dataCount = 0;
+
+ bool queueWasEmpty = bufferQueue.empty();
bufferQueue.push_back(buff);
- DispatchHandle::rewatchRead();
+ if (queueWasEmpty && !readingStopped)
+ DispatchHandle::rewatchRead();
}
void AsynchIO::unread(BufferBase* buff) {
@@ -361,15 +372,18 @@ void AsynchIO::unread(BufferBase* buff) {
memmove(buff->bytes, buff->bytes+buff->dataStart, buff->dataCount);
buff->dataStart = 0;
}
+
+ bool queueWasEmpty = bufferQueue.empty();
bufferQueue.push_front(buff);
- DispatchHandle::rewatchRead();
+ if (queueWasEmpty && !readingStopped)
+ DispatchHandle::rewatchRead();
}
void AsynchIO::queueWrite(BufferBase* buff) {
assert(buff);
// If we've already closed the socket then throw the write away
if (queuedClose) {
- bufferQueue.push_front(buff);
+ queueReadBuffer(buff);
return;
} else {
writeQueue.push_front(buff);
@@ -378,6 +392,7 @@ void AsynchIO::queueWrite(BufferBase* buff) {
DispatchHandle::rewatchWrite();
}
+// This can happen outside the callback context
void AsynchIO::notifyPendingWrite() {
writePending = true;
DispatchHandle::rewatchWrite();
@@ -392,11 +407,14 @@ bool AsynchIO::writeQueueEmpty() {
return writeQueue.empty();
}
+// This can happen outside the callback context
void AsynchIO::startReading() {
+ readingStopped = false;
DispatchHandle::rewatchRead();
}
void AsynchIO::stopReading() {
+ readingStopped = true;
DispatchHandle::unwatchRead();
}
diff --git a/qpid/cpp/include/qpid/sys/uuid.h b/qpid/cpp/src/qpid/sys/uuid.h
index 804ab34463..804ab34463 100644
--- a/qpid/cpp/include/qpid/sys/uuid.h
+++ b/qpid/cpp/src/qpid/sys/uuid.h
diff --git a/qpid/cpp/include/qpid/sys/windows/uuid.h b/qpid/cpp/src/qpid/sys/windows/uuid.h
index c79abe95c6..c79abe95c6 100644
--- a/qpid/cpp/include/qpid/sys/windows/uuid.h
+++ b/qpid/cpp/src/qpid/sys/windows/uuid.h
diff --git a/qpid/cpp/src/qpidd.cpp b/qpid/cpp/src/qpidd.cpp
index 9c3c6b0c4b..1839a62205 100644
--- a/qpid/cpp/src/qpidd.cpp
+++ b/qpid/cpp/src/qpidd.cpp
@@ -77,7 +77,7 @@ int main(int argc, char* argv[])
return broker.execute(options.get());
}
catch(const exception& e) {
- QPID_LOG(critical, "Broker start-up failed: " << e.what());
+ QPID_LOG(critical, "Unexpected error: " << e.what());
}
return 1;
}
diff --git a/qpid/cpp/src/tests/CMakeLists.txt b/qpid/cpp/src/tests/CMakeLists.txt
index 34f5d35a9a..b1219aad74 100644
--- a/qpid/cpp/src/tests/CMakeLists.txt
+++ b/qpid/cpp/src/tests/CMakeLists.txt
@@ -95,6 +95,7 @@ set(unit_tests_to_build
InlineAllocator
InlineVector
ClientSessionTest
+ MessagingSessionTests
SequenceSet
StringUtils
IncompleteMessageList
@@ -128,6 +129,7 @@ set(unit_tests_to_build
ReplicationTest
ClientMessageTest
PollableCondition
+ Variant
${xml_tests}
CACHE STRING "Which unit tests to build"
)
diff --git a/qpid/cpp/src/tests/FieldTable.cpp b/qpid/cpp/src/tests/FieldTable.cpp
index a02bbd5194..5b43871f6d 100644
--- a/qpid/cpp/src/tests/FieldTable.cpp
+++ b/qpid/cpp/src/tests/FieldTable.cpp
@@ -22,6 +22,7 @@
#include "qpid/framing/Array.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/List.h"
#include "qpid/sys/alloca.h"
#include "unit_test.h"
@@ -86,7 +87,9 @@ QPID_AUTO_TEST_CASE(testAssignment)
QPID_AUTO_TEST_CASE(testNestedValues)
{
- char buff[100];
+ double d = 1.2345;
+ uint32_t u = 101;
+ char buff[1000];
{
FieldTable a;
FieldTable b;
@@ -94,11 +97,17 @@ QPID_AUTO_TEST_CASE(testNestedValues)
items.push_back("one");
items.push_back("two");
Array c(items);
+ List list;
+ list.push_back(List::ValuePtr(new Str16Value("red")));
+ list.push_back(List::ValuePtr(new Unsigned32Value(u)));
+ list.push_back(List::ValuePtr(new Str8Value("yellow")));
+ list.push_back(List::ValuePtr(new DoubleValue(d)));
a.setString("id", "A");
b.setString("id", "B");
a.setTable("B", b);
a.setArray("C", c);
+ a.set("my-list", FieldTable::ValuePtr(new ListValue(list)));
Buffer wbuffer(buff, 100);
@@ -119,6 +128,27 @@ QPID_AUTO_TEST_CASE(testNestedValues)
BOOST_CHECK((uint) 2 == items.size());
BOOST_CHECK(string("one") == items[0]);
BOOST_CHECK(string("two") == items[1]);
+
+ List list;
+ BOOST_CHECK(a.get("my-list")->get<List>(list));
+ List::const_iterator i = list.begin();
+ BOOST_CHECK(i != list.end());
+ BOOST_CHECK_EQUAL(std::string("red"), (*i)->get<std::string>());
+
+ i++;
+ BOOST_CHECK(i != list.end());
+ BOOST_CHECK_EQUAL(u, (uint32_t) (*i)->get<int>());
+
+ i++;
+ BOOST_CHECK(i != list.end());
+ BOOST_CHECK_EQUAL(std::string("yellow"), (*i)->get<std::string>());
+
+ i++;
+ BOOST_CHECK(i != list.end());
+ BOOST_CHECK_EQUAL(d, (*i)->get<double>());
+
+ i++;
+ BOOST_CHECK(i == list.end());
}
}
diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am
index db4c8ba914..a15ba3578c 100644
--- a/qpid/cpp/src/tests/Makefile.am
+++ b/qpid/cpp/src/tests/Makefile.am
@@ -65,6 +65,7 @@ unit_test_LDADD=-lboost_unit_test_framework -lboost_regex \
$(lib_client) $(lib_broker) $(lib_console)
unit_test_SOURCES= unit_test.cpp unit_test.h \
+ MessagingSessionTests.cpp \
ClientSessionTest.cpp \
BrokerFixture.h SocketProxy.h \
exception_test.cpp \
@@ -111,7 +112,8 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \
FrameDecoder.cpp \
ReplicationTest.cpp \
ClientMessageTest.cpp \
- PollableCondition.cpp
+ PollableCondition.cpp \
+ Variant.cpp
if HAVE_XML
unit_test_SOURCES+= XmlClientSessionTest.cpp
@@ -268,6 +270,11 @@ check_PROGRAMS+=qrsh
qrsh_SOURCES=qrsh.cpp
qrsh_LDADD=$(lib_client)
+check_PROGRAMS+=qpid_stream
+qpid_stream_INCLUDES=$(PUBLIC_INCLUDES)
+qpid_stream_SOURCES=qpid_stream.cpp
+qpid_stream_LDADD=$(lib_client)
+
TESTS_ENVIRONMENT = \
VALGRIND=$(VALGRIND) \
diff --git a/qpid/cpp/src/tests/MessagingSessionTests.cpp b/qpid/cpp/src/tests/MessagingSessionTests.cpp
new file mode 100644
index 0000000000..4ee27f0764
--- /dev/null
+++ b/qpid/cpp/src/tests/MessagingSessionTests.cpp
@@ -0,0 +1,360 @@
+/*
+ *
+ * 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 "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/messaging/Connection.h"
+#include "qpid/messaging/Message.h"
+#include "qpid/messaging/MessageListener.h"
+#include "qpid/messaging/Receiver.h"
+#include "qpid/messaging/Sender.h"
+#include "qpid/messaging/Session.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Session.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/sys/Time.h"
+#include <boost/assign.hpp>
+#include <boost/format.hpp>
+#include <string>
+#include <vector>
+
+QPID_AUTO_TEST_SUITE(MessagingSessionTests)
+
+using namespace qpid::messaging;
+using namespace qpid;
+using qpid::broker::Broker;
+
+struct BrokerAdmin
+{
+ qpid::client::Connection connection;
+ qpid::client::Session session;
+
+ BrokerAdmin(uint16_t port)
+ {
+ connection.open("localhost", port);
+ session = connection.newSession();
+ }
+
+ void createQueue(const std::string& name)
+ {
+ session.queueDeclare(qpid::client::arg::queue=name);
+ }
+
+ void deleteQueue(const std::string& name)
+ {
+ session.queueDelete(qpid::client::arg::queue=name);
+ }
+
+ void createExchange(const std::string& name, const std::string& type)
+ {
+ session.exchangeDeclare(qpid::client::arg::exchange=name, qpid::client::arg::type=type);
+ }
+
+ void deleteExchange(const std::string& name)
+ {
+ session.exchangeDelete(qpid::client::arg::exchange=name);
+ }
+
+ ~BrokerAdmin()
+ {
+ session.close();
+ connection.close();
+ }
+};
+
+struct MessagingFixture : public BrokerFixture
+{
+ Connection connection;
+ Session session;
+ BrokerAdmin admin;
+
+ MessagingFixture(Broker::Options opts = Broker::Options()) :
+ BrokerFixture(opts),
+ connection(Connection::open((boost::format("amqp:tcp:localhost:%1%") % (broker->getPort(Broker::TCP_TRANSPORT))).str())),
+ session(connection.newSession()),
+ admin(broker->getPort(Broker::TCP_TRANSPORT)) {}
+
+ ~MessagingFixture()
+ {
+ session.close();
+ connection.close();
+ }
+};
+
+struct QueueFixture : MessagingFixture
+{
+ std::string queue;
+
+ QueueFixture(const std::string& name = "test-queue") : queue(name)
+ {
+ admin.createQueue(queue);
+ }
+
+ ~QueueFixture()
+ {
+ admin.deleteQueue(queue);
+ }
+
+};
+
+struct TopicFixture : MessagingFixture
+{
+ std::string topic;
+
+ TopicFixture(const std::string& name = "test-topic", const std::string& type="fanout") : topic(name)
+ {
+ admin.createExchange(topic, type);
+ }
+
+ ~TopicFixture()
+ {
+ admin.deleteExchange(topic);
+ }
+
+};
+
+struct MultiQueueFixture : MessagingFixture
+{
+ typedef std::vector<std::string>::const_iterator const_iterator;
+ std::vector<std::string> queues;
+
+ MultiQueueFixture(const std::vector<std::string>& names = boost::assign::list_of<std::string>("q1")("q2")("q3")) : queues(names)
+ {
+ for (const_iterator i = queues.begin(); i != queues.end(); ++i) {
+ admin.createQueue(*i);
+ }
+ }
+
+ ~MultiQueueFixture()
+ {
+ for (const_iterator i = queues.begin(); i != queues.end(); ++i) {
+ admin.deleteQueue(*i);
+ }
+ }
+
+};
+
+struct MessageDataCollector : MessageListener
+{
+ std::vector<std::string> messageData;
+
+ void received(Message& message) {
+ messageData.push_back(message.getBytes());
+ }
+};
+
+std::vector<std::string> fetch(Receiver& receiver, int count, qpid::sys::Duration timeout=qpid::sys::TIME_SEC*5)
+{
+ std::vector<std::string> data;
+ Message message;
+ for (int i = 0; i < count && receiver.fetch(message, timeout); i++) {
+ data.push_back(message.getBytes());
+ }
+ return data;
+}
+
+QPID_AUTO_TEST_CASE(testSimpleSendReceive)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message out("test-message");
+ sender.send(out);
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ fix.session.acknowledge();
+ BOOST_CHECK_EQUAL(in.getBytes(), out.getBytes());
+}
+
+QPID_AUTO_TEST_CASE(testSendReceiveHeaders)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message out("test-message");
+ for (uint i = 0; i < 10; ++i) {
+ out.getHeaders()["a"] = i;
+ sender.send(out);
+ }
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in;
+ for (uint i = 0; i < 10; ++i) {
+ //Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ BOOST_CHECK(receiver.fetch(in, 5 * qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(in.getBytes(), out.getBytes());
+ BOOST_CHECK_EQUAL(in.getHeaders()["a"].asUint32(), i);
+ fix.session.acknowledge();
+ }
+}
+
+QPID_AUTO_TEST_CASE(testSenderError)
+{
+ MessagingFixture fix;
+ //TODO: this is the wrong type for the exception; define explicit set in messaging namespace
+ BOOST_CHECK_THROW(fix.session.createSender("NonExistentAddress"), qpid::framing::NotFoundException);
+}
+
+QPID_AUTO_TEST_CASE(testReceiverError)
+{
+ MessagingFixture fix;
+ //TODO: this is the wrong type for the exception; define explicit set in messaging namespace
+ BOOST_CHECK_THROW(fix.session.createReceiver("NonExistentAddress"), qpid::framing::NotFoundException);
+}
+
+QPID_AUTO_TEST_CASE(testSimpleTopic)
+{
+ TopicFixture fix;
+
+ Sender sender = fix.session.createSender(fix.topic);
+ Message msg("one");
+ sender.send(msg);
+ Receiver sub1 = fix.session.createReceiver(fix.topic);
+ sub1.setCapacity(10u);
+ sub1.start();
+ msg.setBytes("two");
+ sender.send(msg);
+ Receiver sub2 = fix.session.createReceiver(fix.topic);
+ sub2.setCapacity(10u);
+ sub2.start();
+ msg.setBytes("three");
+ sender.send(msg);
+ Receiver sub3 = fix.session.createReceiver(fix.topic);
+ sub3.setCapacity(10u);
+ sub3.start();
+ msg.setBytes("four");
+ sender.send(msg);
+ BOOST_CHECK_EQUAL(fetch(sub2, 2), boost::assign::list_of<std::string>("three")("four"));
+ sub2.cancel();
+
+ msg.setBytes("five");
+ sender.send(msg);
+ BOOST_CHECK_EQUAL(fetch(sub1, 4), boost::assign::list_of<std::string>("two")("three")("four")("five"));
+ BOOST_CHECK_EQUAL(fetch(sub3, 2), boost::assign::list_of<std::string>("four")("five"));
+ Message in;
+ BOOST_CHECK(!sub2.fetch(in, 0));//TODO: or should this raise an error?
+
+
+ //TODO: check pending messages...
+}
+
+QPID_AUTO_TEST_CASE(testSessionFetch)
+{
+ MultiQueueFixture fix;
+
+ for (uint i = 0; i < fix.queues.size(); i++) {
+ Receiver r = fix.session.createReceiver(fix.queues[i]);
+ r.setCapacity(10u);
+ r.start();//TODO: add Session::start
+ }
+
+ for (uint i = 0; i < fix.queues.size(); i++) {
+ Sender s = fix.session.createSender(fix.queues[i]);
+ Message msg((boost::format("Message_%1%") % (i+1)).str());
+ s.send(msg);
+ }
+
+ for (uint i = 0; i < fix.queues.size(); i++) {
+ Message msg;
+ BOOST_CHECK(fix.session.fetch(msg, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(msg.getBytes(), (boost::format("Message_%1%") % (i+1)).str());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testSessionDispatch)
+{
+ MultiQueueFixture fix;
+
+ MessageDataCollector collector;
+ for (uint i = 0; i < fix.queues.size(); i++) {
+ Receiver r = fix.session.createReceiver(fix.queues[i]);
+ r.setListener(&collector);
+ r.setCapacity(10u);
+ r.start();//TODO: add Session::start
+ }
+
+ for (uint i = 0; i < fix.queues.size(); i++) {
+ Sender s = fix.session.createSender(fix.queues[i]);
+ Message msg((boost::format("Message_%1%") % (i+1)).str());
+ s.send(msg);
+ }
+
+ while (fix.session.dispatch(qpid::sys::TIME_SEC)) ;
+
+ BOOST_CHECK_EQUAL(collector.messageData, boost::assign::list_of<std::string>("Message_1")("Message_2")("Message_3"));
+}
+
+
+QPID_AUTO_TEST_CASE(testMapMessage)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message out;
+ out.getContent().asMap()["abc"] = "def";
+ out.getContent().asMap()["pi"] = 3.14f;
+ sender.send(out);
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ BOOST_CHECK_EQUAL(in.getContent().asMap()["abc"].asString(), "def");
+ BOOST_CHECK_EQUAL(in.getContent().asMap()["pi"].asFloat(), 3.14f);
+ fix.session.acknowledge();
+}
+
+QPID_AUTO_TEST_CASE(testListMessage)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message out;
+ out.getContent() = Variant::List();
+ out.getContent() << "abc";
+ out.getContent() << 1234;
+ out.getContent() << "def";
+ out.getContent() << 56.789;
+ sender.send(out);
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ Variant::List& list = in.getContent().asList();
+ BOOST_CHECK_EQUAL(list.size(), out.getContent().asList().size());
+ BOOST_CHECK_EQUAL(list.front().asString(), "abc");
+ list.pop_front();
+ BOOST_CHECK_EQUAL(list.front().asInt64(), 1234);
+ list.pop_front();
+ BOOST_CHECK_EQUAL(list.front().asString(), "def");
+ list.pop_front();
+ BOOST_CHECK_EQUAL(list.front().asDouble(), 56.789);
+ fix.session.acknowledge();
+}
+
+QPID_AUTO_TEST_CASE(testReject)
+{
+ QueueFixture fix;
+ Sender sender = fix.session.createSender(fix.queue);
+ Message m1("reject-me");
+ sender.send(m1);
+ Message m2("accept-me");
+ sender.send(m2);
+ Receiver receiver = fix.session.createReceiver(fix.queue);
+ Message in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ BOOST_CHECK_EQUAL(in.getBytes(), m1.getBytes());
+ fix.session.reject(in);
+ in = receiver.fetch(5 * qpid::sys::TIME_SEC);
+ BOOST_CHECK_EQUAL(in.getBytes(), m2.getBytes());
+ fix.session.acknowledge();
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/Variant.cpp b/qpid/cpp/src/tests/Variant.cpp
new file mode 100644
index 0000000000..b7ce776827
--- /dev/null
+++ b/qpid/cpp/src/tests/Variant.cpp
@@ -0,0 +1,157 @@
+/*
+ *
+ * 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 <iostream>
+#include "qpid/messaging/Variant.h"
+
+#include "unit_test.h"
+
+using namespace qpid::messaging;
+
+QPID_AUTO_TEST_SUITE(VariantSuite)
+
+QPID_AUTO_TEST_CASE(testConversions)
+{
+ Variant value;
+
+ //string to float/double
+ value = "1.5";
+ BOOST_CHECK_EQUAL((float) 1.5, value.asFloat());
+ BOOST_CHECK_EQUAL((double) 1.5, value.asDouble());
+
+ //float to string or double
+ value = 1.5f;
+ BOOST_CHECK_EQUAL((float) 1.5, value.asFloat());
+ BOOST_CHECK_EQUAL((double) 1.5, value.asDouble());
+ BOOST_CHECK_EQUAL(std::string("1.5"), value.asString());
+
+ //double to string (conversion to float not valid)
+ value = 1.5;
+ BOOST_CHECK_THROW(value.asFloat(), InvalidConversion);
+ BOOST_CHECK_EQUAL((double) 1.5, value.asDouble());
+ BOOST_CHECK_EQUAL(std::string("1.5"), value.asString());
+
+ //uint8 to larger unsigned ints and string
+ value = (uint8_t) 7;
+ BOOST_CHECK_EQUAL((uint8_t) 7, value.asUint8());
+ BOOST_CHECK_EQUAL((uint16_t) 7, value.asUint16());
+ BOOST_CHECK_EQUAL((uint32_t) 7, value.asUint32());
+ BOOST_CHECK_EQUAL((uint64_t) 7, value.asUint64());
+ BOOST_CHECK_EQUAL(std::string("7"), value.asString());
+ BOOST_CHECK_THROW(value.asInt8(), InvalidConversion);
+
+ value = (uint16_t) 8;
+ BOOST_CHECK_EQUAL(std::string("8"), value.asString());
+ value = (uint32_t) 9;
+ BOOST_CHECK_EQUAL(std::string("9"), value.asString());
+
+ //uint32 to larger unsigned ints and string
+ value = (uint32_t) 9999999;
+ BOOST_CHECK_EQUAL((uint32_t) 9999999, value.asUint32());
+ BOOST_CHECK_EQUAL((uint64_t) 9999999, value.asUint64());
+ BOOST_CHECK_EQUAL(std::string("9999999"), value.asString());
+ BOOST_CHECK_THROW(value.asUint8(), InvalidConversion);
+ BOOST_CHECK_THROW(value.asUint16(), InvalidConversion);
+ BOOST_CHECK_THROW(value.asInt32(), InvalidConversion);
+
+ value = "true";
+ BOOST_CHECK(value.asBool());
+ value = "false";
+ BOOST_CHECK(!value.asBool());
+ value = "1";
+ BOOST_CHECK(value.asBool());
+ value = "0";
+ BOOST_CHECK(!value.asBool());
+ value = "other";
+ BOOST_CHECK_THROW(value.asBool(), InvalidConversion);
+}
+
+QPID_AUTO_TEST_CASE(testAssignment)
+{
+ Variant value("abc");
+ Variant other = value;
+ BOOST_CHECK_EQUAL(VAR_STRING, value.getType());
+ BOOST_CHECK_EQUAL(other.getType(), value.getType());
+ BOOST_CHECK_EQUAL(other.asString(), value.asString());
+
+ const uint32_t i(1000);
+ value = i;
+ BOOST_CHECK_EQUAL(VAR_UINT32, value.getType());
+ BOOST_CHECK_EQUAL(VAR_STRING, other.getType());
+}
+
+QPID_AUTO_TEST_CASE(testList)
+{
+ const std::string s("abc");
+ const float f(9.876f);
+ const int16_t x(1000);
+
+ Variant value = Variant::List();
+ value.asList().push_back(Variant(s));
+ value.asList().push_back(Variant(f));
+ value.asList().push_back(Variant(x));
+ BOOST_CHECK_EQUAL(3u, value.asList().size());
+ Variant::List::const_iterator i = value.asList().begin();
+
+ BOOST_CHECK(i != value.asList().end());
+ BOOST_CHECK_EQUAL(VAR_STRING, i->getType());
+ BOOST_CHECK_EQUAL(s, i->asString());
+ i++;
+
+ BOOST_CHECK(i != value.asList().end());
+ BOOST_CHECK_EQUAL(VAR_FLOAT, i->getType());
+ BOOST_CHECK_EQUAL(f, i->asFloat());
+ i++;
+
+ BOOST_CHECK(i != value.asList().end());
+ BOOST_CHECK_EQUAL(VAR_INT16, i->getType());
+ BOOST_CHECK_EQUAL(x, i->asInt16());
+ i++;
+
+ BOOST_CHECK(i == value.asList().end());
+}
+
+QPID_AUTO_TEST_CASE(testMap)
+{
+ const std::string red("red");
+ const float pi(3.14f);
+ const int16_t x(1000);
+
+ Variant value = Variant::Map();
+ value.asMap()["colour"] = red;
+ value.asMap()["pi"] = pi;
+ value.asMap()["my-key"] = x;
+ BOOST_CHECK_EQUAL(3u, value.asMap().size());
+
+ BOOST_CHECK_EQUAL(VAR_STRING, value.asMap()["colour"].getType());
+ BOOST_CHECK_EQUAL(red, value.asMap()["colour"].asString());
+
+ BOOST_CHECK_EQUAL(VAR_FLOAT, value.asMap()["pi"].getType());
+ BOOST_CHECK_EQUAL(pi, value.asMap()["pi"].asFloat());
+
+ BOOST_CHECK_EQUAL(VAR_INT16, value.asMap()["my-key"].getType());
+ BOOST_CHECK_EQUAL(x, value.asMap()["my-key"].asInt16());
+
+ value.asMap()["my-key"] = "now it's a string";
+ BOOST_CHECK_EQUAL(VAR_STRING, value.asMap()["my-key"].getType());
+ BOOST_CHECK_EQUAL(std::string("now it's a string"), value.asMap()["my-key"].asString());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/qpid/cpp/src/tests/cli_tests.py b/qpid/cpp/src/tests/cli_tests.py
index 2af1a20a87..4309b66271 100755
--- a/qpid/cpp/src/tests/cli_tests.py
+++ b/qpid/cpp/src/tests/cli_tests.py
@@ -123,6 +123,28 @@ class CliTests(TestBase010):
found = True
self.assertEqual(found, False)
+ def test_qpid_config_altex(self):
+ self.startQmf();
+ qmf = self.qmf
+ exName = "testalt"
+ altName = "amq.direct"
+
+ ret = os.system(self.command(" add exchange topic %s --alternate-exchange=%s" % (exName, altName)))
+ self.assertEqual(ret, 0)
+
+ exchanges = qmf.getObjects(_class="exchange")
+ found = False
+ for exchange in exchanges:
+ if exchange.name == altName:
+ self.assertEqual(exchange.altExchange, None)
+
+ if exchange.name == exName:
+ found = True
+ if not exchange.altExchange:
+ self.fail("Alternate exchange not set")
+ self.assertEqual(exchange._altExchange_.name, altName)
+ self.assertEqual(found, True)
+
def test_qpid_route(self):
self.startQmf();
qmf = self.qmf
diff --git a/qpid/cpp/src/tests/cluster_python_tests_failing.txt b/qpid/cpp/src/tests/cluster_python_tests_failing.txt
index 337fb4a0f2..53b609942d 100644
--- a/qpid/cpp/src/tests/cluster_python_tests_failing.txt
+++ b/qpid/cpp/src/tests/cluster_python_tests_failing.txt
@@ -1,4 +1,5 @@
tests_0-10.management.ManagementTest.test_purge_queue
+tests_0-10.management.ManagementTest.test_connection_close
tests_0-10.dtx.DtxTests.test_bad_resume
tests_0-10.dtx.DtxTests.test_commit_unknown
tests_0-10.dtx.DtxTests.test_end
diff --git a/qpid/cpp/src/tests/federation.py b/qpid/cpp/src/tests/federation.py
index daf831f3ed..aa68e8198b 100755
--- a/qpid/cpp/src/tests/federation.py
+++ b/qpid/cpp/src/tests/federation.py
@@ -32,6 +32,17 @@ class FederationTests(TestBase010):
def remote_port(self):
return int(self.defines["remote-port"])
+ def verify_cleanup(self):
+ attempts = 0
+ total = len(self.qmf.getObjects(_class="bridge")) + len(self.qmf.getObjects(_class="link"))
+ while total > 0:
+ attempts += 1
+ if attempts >= 10:
+ self.fail("Bridges and links didn't clean up")
+ return
+ sleep(1)
+ total = len(self.qmf.getObjects(_class="bridge")) + len(self.qmf.getObjects(_class="link"))
+
def test_bridge_create_and_close(self):
self.startQmf();
qmf = self.qmf
@@ -51,9 +62,7 @@ class FederationTests(TestBase010):
result = link.close()
self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+ self.verify_cleanup()
def test_pull_from_exchange(self):
session = self.session
@@ -98,9 +107,7 @@ class FederationTests(TestBase010):
result = link.close()
self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+ self.verify_cleanup()
def test_push_to_exchange(self):
session = self.session
@@ -144,9 +151,7 @@ class FederationTests(TestBase010):
result = link.close()
self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+ self.verify_cleanup()
def test_pull_from_queue(self):
session = self.session
@@ -199,9 +204,7 @@ class FederationTests(TestBase010):
result = link.close()
self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+ self.verify_cleanup()
def test_tracing_automatic(self):
remoteUrl = "%s:%d" % (self.remote_host(), self.remote_port())
@@ -312,9 +315,7 @@ class FederationTests(TestBase010):
result = link.close()
self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+ self.verify_cleanup()
def test_dynamic_fanout(self):
session = self.session
@@ -358,9 +359,7 @@ class FederationTests(TestBase010):
result = link.close()
self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+ self.verify_cleanup()
def test_dynamic_direct(self):
@@ -405,10 +404,7 @@ class FederationTests(TestBase010):
result = link.close()
self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
-
+ self.verify_cleanup()
def test_dynamic_topic(self):
session = self.session
@@ -452,9 +448,7 @@ class FederationTests(TestBase010):
result = link.close()
self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+ self.verify_cleanup()
def test_dynamic_topic_reorigin(self):
session = self.session
@@ -509,14 +503,24 @@ class FederationTests(TestBase010):
self.assertEqual(result.status, 0)
result = bridge2.close()
self.assertEqual(result.status, 0)
- result = link.close()
- self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+ # extra check: verify we don't leak bridge objects - keep the link
+ # around and verify the bridge count has gone to zero
+
+ attempts = 0
+ bridgeCount = len(qmf.getObjects(_class="bridge"))
+ while bridgeCount > 0:
+ attempts += 1
+ if attempts >= 5:
+ self.fail("Bridges didn't clean up")
+ return
+ sleep(1)
+ bridgeCount = len(qmf.getObjects(_class="bridge"))
+ result = link.close()
+ self.assertEqual(result.status, 0)
+ self.verify_cleanup()
def test_dynamic_direct_reorigin(self):
session = self.session
@@ -569,16 +573,17 @@ class FederationTests(TestBase010):
result = bridge.close()
self.assertEqual(result.status, 0)
- result = bridge2.close()
- self.assertEqual(result.status, 0)
+
+ # Extra test: don't explicitly close() bridge2. When the link is closed,
+ # it should clean up bridge2 automagically. verify_cleanup() will detect
+ # if bridge2 isn't cleaned up and will fail the test.
+ #
+ #result = bridge2.close()
+ #self.assertEqual(result.status, 0)
result = link.close()
self.assertEqual(result.status, 0)
- sleep(3)
- self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
- self.assertEqual(len(qmf.getObjects(_class="link")), 0)
-
-
+ self.verify_cleanup()
def getProperty(self, msg, name):
for h in msg.headers:
diff --git a/qpid/cpp/src/tests/qpid_stream.cpp b/qpid/cpp/src/tests/qpid_stream.cpp
new file mode 100644
index 0000000000..8e02baa8a0
--- /dev/null
+++ b/qpid/cpp/src/tests/qpid_stream.cpp
@@ -0,0 +1,163 @@
+/*
+ *
+ * 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 <qpid/messaging/Connection.h>
+#include <qpid/messaging/Message.h>
+#include <qpid/messaging/Receiver.h>
+#include <qpid/messaging/Sender.h>
+#include <qpid/messaging/Session.h>
+#include <qpid/sys/Runnable.h>
+#include <qpid/sys/Thread.h>
+#include <qpid/sys/Time.h>
+#include <qpid/Options.h>
+#include <iostream>
+#include <string>
+
+using namespace qpid::messaging;
+using namespace qpid::sys;
+
+struct Args : public qpid::Options
+{
+ std::string url;
+ std::string address;
+ uint rate;
+ bool durable;
+
+ Args() : url("amqp:tcp:127.0.0.1:5672"), address("test-queue"), rate(1000), durable(false)
+ {
+ addOptions()
+ ("url", qpid::optValue(url, "URL"), "Url to connect to.")
+ ("address", qpid::optValue(address, "ADDRESS"), "Address to stream messages through.")
+ ("rate", qpid::optValue(rate, "msgs/sec"), "Rate at which to stream messages.")
+ ("durable", qpid::optValue(durable, "true|false"), "Mark messages as durable.");
+ }
+};
+
+Args opts;
+
+const std::string TIMESTAMP = "ts";
+
+uint64_t timestamp(const AbsTime& time)
+{
+ Duration t(time);
+ return t;
+}
+
+struct Client : Runnable
+{
+ virtual ~Client() {}
+ virtual void doWork(Session&) = 0;
+
+ void run()
+ {
+ try {
+ Connection connection = Connection::open(opts.url);
+ Session session = connection.newSession();
+ doWork(session);
+ session.close();
+ connection.close();
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ }
+
+ Thread thread;
+
+ void start() { thread = Thread(this); }
+ void join() { thread.join(); }
+};
+
+struct Publish : Client
+{
+ void doWork(Session& session)
+ {
+ Sender sender = session.createSender(opts.address);
+ Message msg;
+ uint64_t interval = TIME_SEC / opts.rate;
+ uint64_t sent = 0, missedRate = 0;
+ AbsTime start = now();
+ while (true) {
+ AbsTime sentAt = now();
+ msg.getHeaders()[TIMESTAMP] = timestamp(sentAt);
+ sender.send(msg);
+ ++sent;
+ AbsTime waitTill(start, sent*interval);
+ Duration delay(sentAt, waitTill);
+ if (delay < 0) {
+ ++missedRate;
+ } else {
+ qpid::sys::usleep(delay / TIME_USEC);
+ }
+ }
+ }
+};
+
+struct Consume : Client
+{
+ void doWork(Session& session)
+ {
+ Message msg;
+ uint64_t received = 0;
+ double minLatency = std::numeric_limits<double>::max();
+ double maxLatency = 0;
+ double totalLatency = 0;
+ Receiver receiver = session.createReceiver(opts.address);
+ while (receiver.fetch(msg)) {
+ session.acknowledge();//TODO: add batching option
+ ++received;
+ //calculate latency
+ uint64_t receivedAt = timestamp(now());
+ uint64_t sentAt = msg.getHeaders()[TIMESTAMP].asUint64();
+ double latency = ((double) (receivedAt - sentAt)) / TIME_MSEC;
+
+ //update avg, min & max
+ minLatency = std::min(minLatency, latency);
+ maxLatency = std::max(maxLatency, latency);
+ totalLatency += latency;
+
+ if (received % opts.rate == 0) {
+ std::cout << "count=" << received
+ << ", avg=" << (totalLatency/received)
+ << ", min=" << minLatency
+ << ", max=" << maxLatency << std::endl;
+ }
+ }
+ }
+};
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ Publish publish;
+ Consume consume;
+ publish.start();
+ consume.start();
+ consume.join();
+ publish.join();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/qpid/cpp/src/tests/txtest.cpp b/qpid/cpp/src/tests/txtest.cpp
index c1ee246e2c..f604df7e21 100644
--- a/qpid/cpp/src/tests/txtest.cpp
+++ b/qpid/cpp/src/tests/txtest.cpp
@@ -33,7 +33,7 @@
#include "qpid/client/SubscriptionManager.h"
#include "qpid/framing/Array.h"
#include "qpid/framing/Buffer.h"
-#include "qpid/sys/uuid.h"
+#include "qpid/framing/Uuid.h"
#include "qpid/sys/Thread.h"
using namespace qpid;
@@ -130,8 +130,6 @@ struct Transfer : public Client, public Runnable
std::string src;
std::string dest;
Thread thread;
- uuid_t uuid;
- char uuidStr[37]; // Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + trailing \0
framing::Xid xid;
Transfer(const std::string& to, const std::string& from) : src(to), dest(from), xid(0x4c414e47, "", from) {}
@@ -184,9 +182,8 @@ struct Transfer : public Client, public Runnable
}
void setNewXid(framing::Xid& xid) {
- ::uuid_generate(uuid);
- ::uuid_unparse(uuid, uuidStr);
- xid.setGlobalId(uuidStr);
+ framing::Uuid uuid(true);
+ xid.setGlobalId(uuid.str());
}
};