diff options
Diffstat (limited to 'qpid/cpp')
214 files changed, 6720 insertions, 4029 deletions
diff --git a/qpid/cpp/CMakeLists.txt b/qpid/cpp/CMakeLists.txt index de1353bd11..18a7616d99 100644 --- a/qpid/cpp/CMakeLists.txt +++ b/qpid/cpp/CMakeLists.txt @@ -23,26 +23,150 @@ if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) +set (QPID_VERSION_MAJOR 0) +set (QPID_VERSION_MINOR 6) +set (qpidc_version ${QPID_VERSION_MAJOR}.${QPID_VERSION_MINOR}) + enable_testing() include (CTest) -set (qpidc_version 0.5) +# When doing installs, there are a number of components that the item can +# be associated with. Since there may be different sets of components desired +# for the various platforms, the component names are defined here. When +# setting the COMPONENT in an install directive, use these to ensure that +# the item is installed correctly. +# +# This section also has all the setup for various packaging-specific options. +if (WIN32) + set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") + set (CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/NSIS\\\\qpid-icon.ico") + set (CPACK_NSIS_MUI_UNIICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/NSIS\\\\qpid-icon.ico") + set (CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/packaging/NSIS\\\\qpid-install-banner.bmp") -# set(CMAKE_INCLUDE_CURRENT_DIR ON) + # Install types; these defines the component sets that are installed. + # Each component (below) indicates which of these install type(s) it is + # included in. The user can refine the components at install time. + set (CPACK_ALL_INSTALL_TYPES Broker Development Full) -add_subdirectory(managementgen) -# add_subdirectory(etc) -add_subdirectory(src) -# add_subdirectory(docs/api) -# add_subdirectory(docs/man) + set (QPID_COMPONENT_COMMON Common) + set (CPACK_COMPONENT_COMMON_INSTALL_TYPES Broker Development Full) + set (CPACK_COMPONENT_COMMON_DISPLAY_NAME "Required common runtime items") + set (CPACK_COMPONENT_COMMON_DESCRIPTION + "Run-time library common to all runtime components in Qpid.\n + This item is required by both broker and client components.") + + set (QPID_COMPONENT_BROKER Broker) + set (CPACK_COMPONENT_BROKER_DEPENDS Common) + set (CPACK_COMPONENT_BROKER_INSTALL_TYPES Broker Full) + set (CPACK_COMPONENT_BROKER_DISPLAY_NAME "Broker") + set (CPACK_COMPONENT_BROKER_DESCRIPTION + "Messaging broker; controls message flow within the system.\n + At least one broker is required to run any messaging application.") + + set (QPID_COMPONENT_CLIENT Client) + set (CPACK_COMPONENT_CLIENT_DEPENDS Common) + set (CPACK_COMPONENT_CLIENT_INSTALL_TYPES Development Full) + set (CPACK_COMPONENT_CLIENT_DISPLAY_NAME "Client runtime libraries") + set (CPACK_COMPONENT_CLIENT_DESCRIPTION + "Runtime library components required to build and execute a client application.") + + set (QPID_COMPONENT_CLIENT_INCLUDE ClientInclude) + set (CPACK_COMPONENT_CLIENTINCLUDE_INSTALL_TYPES Development Full) + set (CPACK_COMPONENT_CLIENTINCLUDE_DISPLAY_NAME + "Client programming header files") + set (CPACK_COMPONENT_CLIENTINCLUDE_DESCRIPTION + "C++ header files required to build any Qpid messaging application.") + + set (QPID_COMPONENT_QMF QMF) + set (CPACK_COMPONENT_QMF_INSTALL_TYPES Development Full) + set (CPACK_COMPONENT_QMF_DISPLAY_NAME + "Qpid Management Framework (QMF)") + set (CPACK_COMPONENT_QMF_DESCRIPTION + "QMF Agent allows you to embed QMF management in your program.\n + QMF Console allows you to build management programs using QMF.") + + set (QPID_INSTALL_BINDIR bin CACHE STRING + "Directory to install user executables") + set (QPID_INSTALL_CONFDIR conf CACHE STRING + "Directory to install configuration files") + set (QPID_INSTALL_DATADIR conf CACHE STRING + "Directory to install read-only arch.-independent data root") + set (QPID_INSTALL_INCLUDEDIR include CACHE STRING + "Directory to install programming header files") + set (QPID_INSTALL_LIBDIR bin CACHE STRING + "Directory to install library files") + set (QPID_INSTALL_SBINDIR bin CACHE STRING + "Directory to install system admin executables") + set (QPIDC_MODULE_DIR plugins/client CACHE STRING + "Directory to load client plug-in modules from") + set (QPIDD_MODULE_DIR plugins/broker CACHE STRING + "Directory to load broker plug-in modules from") +endif (WIN32) +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + # Set up install locations. Since the Linux install puts some files in + # /etc and most in the install location, we need to use a DESTDIR build + # rather than the usual simple use of CPACK_INSTALL_PREFIX. + set (CPACK_SET_DESTDIR ON) -# if (WIN32) -# do something Microsoft specific -# endif (WIN32) + set (QPID_COMPONENT_BROKER runtime) + set (QPID_COMPONENT_CLIENT runtime) + set (QPID_COMPONENT_COMMON runtime) + set (CPACK_COMPONENT_RUNTIME_DISPLAY_NAME + "Items required to run broker and/or client programs") + set (QPID_COMPONENT_CLIENT_INCLUDE development) + set (QPID_COMPONENT_QMF development) + set (CPACK_COMPONENT_DEVELOPMENT_DISPLAY_NAME + "Items required to build new C++ Qpid client programs") + + + set (QPID_INSTALL_BINDIR bin CACHE STRING + "Directory to install user executables") + set (QPID_INSTALL_CONFDIR /etc/qpid CACHE STRING + "Directory to install configuration files") + set (QPID_INSTALL_DATADIR share/qpid CACHE STRING + "Directory to install read-only arch.-independent data root") + set (QPID_INSTALL_INCLUDEDIR include CACHE STRING + "Directory to install programming header files") + set (QPID_INSTALL_LIBDIR lib CACHE STRING + "Directory to install library files") + set (QPID_INSTALL_SBINDIR sbin CACHE STRING + "Directory to install system admin executables") + set (QPIDC_MODULE_DIR ${QPID_INSTALL_LIBDIR}/qpid/client CACHE STRING + "Directory to load client plug-in modules from") + set (QPIDD_MODULE_DIR ${QPID_INSTALL_LIBDIR}/qpid/daemon CACHE STRING + "Directory to load broker plug-in modules from") +endif (CMAKE_SYSTEM_NAME STREQUAL Linux) + +set (QPIDC_CONF_FILE ${QPID_INSTALL_CONFDIR}/qpidc.conf CACHE STRING + "Name of the Qpid client configuration file") +set (QPIDD_CONF_FILE ${QPID_INSTALL_CONFDIR}/qpidd.conf CACHE STRING + "Name of the Qpid broker configuration file") install(FILES LICENSE NOTICE README SSL RELEASE_NOTES DESIGN xml/cluster.xml INSTALL-WINDOWS - DESTINATION .) + DESTINATION ${QPID_INSTALL_DATADIR}) + +if (WIN32) + set (CMAKE_DEBUG_POSTFIX "d") +endif (WIN32) + +# set(CMAKE_INCLUDE_CURRENT_DIR ON) +add_subdirectory(managementgen) +add_subdirectory(etc) +add_subdirectory(src) +# add_subdirectory(docs/api) +# add_subdirectory(docs/man) add_subdirectory(examples) + +set(CPACK_PACKAGE_NAME "qpid-cpp") +set(CPACK_PACKAGE_VENDOR "Apache Software Foundation") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache Qpid C++") +set(CPACK_PACKAGE_VERSION "${qpidc_version}") +set(CPACK_PACKAGE_VERSION_MAJOR "${QPID_VERSION_MAJOR}") +set(CPACK_PACKAGE_VERSION_MINOR "${QPID_VERSION_MINOR}") +set(CPACK_PACKAGE_VERSION_PATCH "0") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "qpidc-${qpidc_version}") + +include (CPack) diff --git a/qpid/cpp/bindings/qmf/python/Makefile.am b/qpid/cpp/bindings/qmf/python/Makefile.am index 55d9079fb7..53303c7be9 100644 --- a/qpid/cpp/bindings/qmf/python/Makefile.am +++ b/qpid/cpp/bindings/qmf/python/Makefile.am @@ -38,7 +38,7 @@ lib_LTLIBRARIES = _qmfengine.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_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmf.la _qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(srcdir)/qmf -I$(PYTHON_INC) nodist__qmfengine_la_SOURCES = qmfengine.cpp diff --git a/qpid/cpp/bindings/qmf/python/qmf.py b/qpid/cpp/bindings/qmf/python/qmf.py index 4800b327f1..383baad0e3 100644 --- a/qpid/cpp/bindings/qmf/python/qmf.py +++ b/qpid/cpp/bindings/qmf/python/qmf.py @@ -566,7 +566,7 @@ class Console: # attr_reader :impl def initialize(handler=None, kwargs={}): self._handler = handler - self.impl = qmfengine.ConsoleEngine() + self.impl = qmfengine.Console() self._event = qmfengine.ConsoleEvent() self._broker_list = [] @@ -741,7 +741,7 @@ class Agent(ConnectionHandler): self._agentLabel = label self._conn = None self._handler = handler - self.impl = qmfengine.AgentEngine(self._agentLabel) + self.impl = qmfengine.Agent(self._agentLabel) self._event = qmfengine.AgentEvent() self._xmtMessage = qmfengine.Message() diff --git a/qpid/cpp/bindings/qmf/qmfengine.i b/qpid/cpp/bindings/qmf/qmfengine.i index d3500c9b8f..3477215254 100644 --- a/qpid/cpp/bindings/qmf/qmfengine.i +++ b/qpid/cpp/bindings/qmf/qmfengine.i @@ -19,34 +19,35 @@ %{ -#include "qmf/AgentEngine.h" -#include "qmf/ConsoleEngine.h" -#include "qmf/ResilientConnection.h" +#include "qmf/engine/Agent.h" +#include "qmf/engine/Console.h" +#include "qmf/engine/ResilientConnection.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> +%include <qmf/engine/QmfEngineImportExport.h> +%include <qmf/engine/Query.h> +%include <qmf/engine/Message.h> +%include <qmf/engine/Agent.h> +%include <qmf/engine/Console.h> +%include <qmf/engine/ConnectionSettings.h> +%include <qmf/engine/ResilientConnection.h> +%include <qmf/engine/Typecode.h> +%include <qmf/engine/Schema.h> +%include <qmf/engine/Value.h> +%include <qmf/engine/ObjectId.h> +%include <qmf/engine/Object.h> %inline { using namespace std; -using namespace qmf; +using namespace qmf::engine; namespace qmf { +namespace engine { - +} } } diff --git a/qpid/cpp/bindings/qmf/ruby/Makefile.am b/qpid/cpp/bindings/qmf/ruby/Makefile.am index 0537dd1cd8..34096da9ee 100644 --- a/qpid/cpp/bindings/qmf/ruby/Makefile.am +++ b/qpid/cpp/bindings/qmf/ruby/Makefile.am @@ -23,23 +23,22 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src EXTRA_DIST = ruby.i BUILT_SOURCES = qmfengine.cpp -generated_file_list = qmfengine.cpp rubylibdir = $(RUBY_LIB) dist_rubylib_DATA = qmf.rb -$(generated_file_list): $(srcdir)/ruby.i $(srcdir)/../qmfengine.i +qmfengine.cpp: $(srcdir)/ruby.i $(srcdir)/../qmfengine.i $(SWIG) -ruby -c++ -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -o qmfengine.cpp $(srcdir)/ruby.i 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/libqmfagent.la +qmfengine_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfengine.la qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) nodist_qmfengine_la_SOURCES = qmfengine.cpp -CLEANFILES = $(generated_file_list) +CLEANFILES = qmfengine.cpp endif # HAVE_RUBY_DEVEL diff --git a/qpid/cpp/bindings/qmf/ruby/qmf.rb b/qpid/cpp/bindings/qmf/ruby/qmf.rb index 16f1058f4a..fbf95215fd 100644 --- a/qpid/cpp/bindings/qmf/ruby/qmf.rb +++ b/qpid/cpp/bindings/qmf/ruby/qmf.rb @@ -60,7 +60,19 @@ module Qmf raise ArgumentError, "Value for attribute '#{key}' has unsupported type: #{val.class}" end - @impl.setAttr(key, v) + good = @impl.setAttr(key, v) + raise "Invalid attribute '#{key}'" unless good + end + + def method_missing(name_in, *args) + name = name_in.to_s + if name[name.length - 1] == 61 + attr = name[0..name.length - 2] + set_attr(attr, args[0]) + return + end + + super.method_missing(name_in, args) end end @@ -85,12 +97,17 @@ module Qmf @new_conn_handlers = [] @conn_handlers_to_delete = [] @conn_handlers = [] + @connected = nil @thread = Thread.new do run end end + def connected? + @connected + end + def kick @sockEngine.write(".") @sockEngine.flush @@ -112,7 +129,6 @@ module Qmf def run() eventImpl = Qmfengine::ResilientConnectionEvent.new - connected = nil new_handlers = nil del_handlers = nil bt_count = 0 @@ -129,7 +145,7 @@ module Qmf new_handlers.each do |nh| @conn_handlers << nh - nh.conn_event_connected() if connected + nh.conn_event_connected() if @connected end new_handlers = nil @@ -143,10 +159,10 @@ module Qmf begin case eventImpl.kind when Qmfengine::ResilientConnectionEvent::CONNECTED - connected = :true + @connected = :true @conn_handlers.each { |h| h.conn_event_connected() } when Qmfengine::ResilientConnectionEvent::DISCONNECTED - connected = nil + @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) @@ -189,8 +205,16 @@ module Qmf ##============================================================================== class QmfObject + include MonitorMixin attr_reader :impl, :object_class def initialize(cls, kwargs={}) + super() + @cv = new_cond + @sync_count = 0 + @sync_result = nil + @allow_sets = :false + @broker = kwargs[:broker] if kwargs.include?(:broker) + if cls: @object_class = cls @impl = Qmfengine::Object.new(@object_class.impl) @@ -204,6 +228,22 @@ module Qmf return ObjectId.new(@impl.getObjectId) end + def properties + list = [] + @object_class.properties.each do |prop| + list << [prop, get_attr(prop.name)] + end + return list + end + + def statistics + list = [] + @object_class.statistics.each do |stat| + list << [stat, get_attr(stat.name)] + end + return list + end + def get_attr(name) val = value(name) case val.getType @@ -212,7 +252,7 @@ module Qmf 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_REF then ObjectId.new(val.asObjectId) when TYPE_BOOL then val.asBool when TYPE_FLOAT then val.asFloat when TYPE_DOUBLE then val.asDouble @@ -264,6 +304,103 @@ module Qmf set_attr(name, get_attr(name) - by) end + def method_missing(name_in, *args) + # + # Convert the name to a string and determine if it represents an + # attribute assignment (i.e. "attr=") + # + name = name_in.to_s + attr_set = (name[name.length - 1] == 61) + name = name[0..name.length - 2] if attr_set + raise "Sets not permitted on this object" if attr_set && !@allow_sets + + # + # If the name matches a property name, set or return the value of the property. + # + @object_class.properties.each do |prop| + if prop.name == name + if attr_set + return set_attr(name, args[0]) + else + return get_attr(name) + end + end + end + + # + # Do the same for statistics + # + @object_class.statistics.each do |stat| + if stat.name == name + if attr_set + return set_attr(name, args[0]) + else + return get_attr(name) + end + end + end + + # + # If we still haven't found a match for the name, check to see if + # it matches a method name. If so, marshall the arguments and invoke + # the method. + # + @object_class.methods.each do |method| + if method.name == name + raise "Sets not permitted on methods" if attr_set + timeout = 30 + synchronize do + @sync_count = 1 + @impl.invokeMethod(name, _marshall(method, args), self) + @broker.conn.kick if @broker + unless @cv.wait(timeout) { @sync_count == 0 } + raise "Timed out waiting for response" + end + end + + return @sync_result + end + end + + # + # This name means nothing to us, pass it up the line to the parent + # class's handler. + # + super.method_missing(name_in, args) + end + + def _method_result(result) + synchronize do + @sync_result = result + @sync_count -= 1 + @cv.signal + end + end + + # + # Convert a Ruby array of arguments (positional) into a Value object of type "map". + # + private + def _marshall(schema, args) + map = Qmfengine::Value.new(TYPE_MAP) + schema.arguments.each do |arg| + if arg.direction == DIR_IN || arg.direction == DIR_IN_OUT + map.insert(arg.name, Qmfengine::Value.new(arg.typecode)) + end + end + + marshalled = Arguments.new(map) + idx = 0 + schema.arguments.each do |arg| + if arg.direction == DIR_IN || arg.direction == DIR_IN_OUT + marshalled[arg.name] = args[idx] unless args[idx] == nil + idx += 1 + end + end + + return marshalled.map + end + private def value(name) val = @impl.getValue(name.to_s) @@ -277,6 +414,7 @@ module Qmf class AgentObject < QmfObject def initialize(cls, kwargs={}) super(cls, kwargs) + @allow_sets = :true end def destroy @@ -296,20 +434,22 @@ module Qmf end def update() + raise "No linkage to broker" unless @broker + newer = @broker.console.objects(Query.new(:object_id => object_id)) + raise "Expected exactly one update for this object" unless newer.size == 1 + merge_update(newer[0]) end - def mergeUpdate(newObject) + def merge_update(new_object) + @impl.merge(new_object.impl) end def deleted?() - @delete_time > 0 + @impl.isDeleted end def index() end - - def method_missing(name, *args) - end end class ObjectId @@ -323,17 +463,29 @@ module Qmf end def object_num_high - return @impl.getObjectNumHi + @impl.getObjectNumHi end def object_num_low - return @impl.getObjectNumLo + @impl.getObjectNumLo + end + + def broker_bank + @impl.getBrokerBank + end + + def agent_bank + @impl.getAgentBank end def ==(other) return (@impl.getObjectNumHi == other.impl.getObjectNumHi) && (@impl.getObjectNumLo == other.impl.getObjectNumLo) end + + def to_s + @impl.str + end end class Arguments @@ -362,6 +514,14 @@ module Qmf @by_hash.each { |k, v| yield(k, v) } end + def method_missing(name, *args) + if @by_hash.include?(name.to_s) + return @by_hash[name.to_s] + end + + super.method_missing(name, args) + end + def by_key(key) val = @map.byKey(key) case val.getType @@ -370,7 +530,7 @@ module Qmf 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_REF then ObjectId.new(val.asObjectId) when TYPE_BOOL then val.asBool when TYPE_FLOAT then val.asFloat when TYPE_DOUBLE then val.asDouble @@ -407,6 +567,32 @@ module Qmf end end + class MethodResponse + def initialize(impl) + @impl = Qmfengine::MethodResponse.new(impl) + end + + def status + @impl.getStatus + end + + def exception + @impl.getException + end + + def text + exception.asString + end + + def args + Arguments.new(@impl.getArgs) + end + + def method_missing(name, *extra_args) + args.__send__(name, extra_args) + end + end + ##============================================================================== ## QUERY ##============================================================================== @@ -421,13 +607,13 @@ module Qmf if kwargs.include?(:key) @impl = Qmfengine::Query.new(kwargs[:key]) elsif kwargs.include?(:object_id) - @impl = Qmfengine::Query.new(kwargs[:object_id]) + @impl = Qmfengine::Query.new(kwargs[:object_id].impl) else package = kwargs[:package] if kwargs.include?(:package) if kwargs.include?(:class) @impl = Qmfengine::Query.new(kwargs[:class], package) else - raise ArgumentError, "Invalid arguments, use :key or :class[,:package]" + raise ArgumentError, "Invalid arguments, use :key, :object_id or :class[,:package]" end end end @@ -470,6 +656,18 @@ module Qmf def name @impl.getName end + + def direction + @impl.getDirection + end + + def typecode + @impl.getType + end + + def to_s + name + end end class SchemaMethod @@ -496,6 +694,10 @@ module Qmf def name @impl.getName end + + def to_s + name + end end class SchemaProperty @@ -516,6 +718,10 @@ module Qmf def name @impl.getName end + + def to_s + name + end end class SchemaStatistic @@ -533,6 +739,10 @@ module Qmf def name @impl.getName end + + def to_s + name + end end class SchemaClassKey @@ -541,12 +751,16 @@ module Qmf @impl = i end - def get_package() - @impl.getPackageName() + def package_name + @impl.getPackageName + end + + def class_name + @impl.getClassName end - def get_class() - @impl.getClassName() + def to_s + @impl.asString end end @@ -590,7 +804,15 @@ module Qmf @impl.addMethod(meth.impl) end - def name + def class_key + SchemaClassKey.new(@impl.getClassKey) + end + + def package_name + @impl.getClassKey.getPackageName + end + + def class_name @impl.getClassKey.getClassName end end @@ -643,7 +865,7 @@ module Qmf def initialize(handler = nil, kwargs={}) super() @handler = handler - @impl = Qmfengine::ConsoleEngine.new + @impl = Qmfengine::Console.new @event = Qmfengine::ConsoleEvent.new @broker_list = [] @cv = new_cond @@ -662,7 +884,7 @@ module Qmf @broker_list.delete(broker) end - def get_packages() + def packages() plist = [] count = @impl.packageCount for i in 0...count @@ -671,7 +893,7 @@ module Qmf return plist end - def get_classes(package, kind=CLASS_OBJECT) + def classes(package, kind=CLASS_OBJECT) clist = [] count = @impl.classCount(package) for i in 0...count @@ -708,7 +930,7 @@ module Qmf end end - def get_agents(broker = nil) + def agents(broker = nil) blist = [] if broker blist << broker @@ -727,11 +949,17 @@ module Qmf return agents end - def get_objects(query, kwargs = {}) + def objects(query, kwargs = {}) timeout = 30 + kwargs.merge!(query) if query.class == Hash + if kwargs.include?(:timeout) timeout = kwargs[:timeout] + kwargs.delete(:timeout) end + + query = Query.new(kwargs) if query.class == Hash + synchronize do @sync_count = 1 @sync_result = [] @@ -745,6 +973,18 @@ module Qmf end end + # Return one and only one object or nil. + def object(query, kwargs = {}) + objs = objects(query, kwargs) + return objs.length == 1 ? objs[0] : nil + end + + # Return the first of potentially many objects. + def first_object(query, kwargs = {}) + objs = objects(query, kwargs) + return objs.length > 0 ? objs[0] : nil + end + def _get_result(list, context) synchronize do list.each do |item| @@ -769,15 +1009,20 @@ module Qmf valid = @impl.getEvent(@event) while valid count += 1 - puts "Console Event: #{@event.kind}" case @event.kind when Qmfengine::ConsoleEvent::AGENT_ADDED + @handler.agent_added(AgentProxy.new(@event.agent, nil)) if @handler when Qmfengine::ConsoleEvent::AGENT_DELETED + @handler.agent_deleted(AgentProxy.new(@event.agent, nil)) if @handler when Qmfengine::ConsoleEvent::NEW_PACKAGE + @handler.new_package(@event.name) if @handler when Qmfengine::ConsoleEvent::NEW_CLASS + @handler.new_class(SchemaClassKey.new(@event.classKey)) if @handler when Qmfengine::ConsoleEvent::OBJECT_UPDATE + @handler.object_update(ConsoleObject.new(nil, :impl => @event.object), @event.hasProps, @event.hasStats) if @handler when Qmfengine::ConsoleEvent::EVENT_RECEIVED when Qmfengine::ConsoleEvent::AGENT_HEARTBEAT + @handler.agent_heartbeat(AgentProxy.new(@event.agent, nil), @event.timestamp) if @handler when Qmfengine::ConsoleEvent::METHOD_RESPONSE end @impl.popEvent @@ -798,14 +1043,23 @@ module Qmf def label @impl.getLabel end + + def broker_bank + @impl.getBrokerBank + end + + def agent_bank + @impl.getAgentBank + end end class Broker < ConnectionHandler include MonitorMixin - attr_reader :impl + attr_reader :impl, :conn, :console, :broker_bank def initialize(console, conn) super() + @broker_bank = 1 @console = console @conn = conn @session = nil @@ -825,7 +1079,7 @@ module Qmf @operational = :false end - def waitForStable(timeout = nil) + def wait_for_stable(timeout = nil) synchronize do return if @stable if timeout @@ -850,7 +1104,6 @@ module Qmf 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 @@ -871,9 +1124,12 @@ module Qmf when Qmfengine::BrokerEvent::QUERY_COMPLETE result = [] for idx in 0...@event.queryResponse.getObjectCount - result << ConsoleObject.new(nil, :impl => @event.queryResponse.getObject(idx)) + result << ConsoleObject.new(nil, :impl => @event.queryResponse.getObject(idx), :broker => self) end @console._get_result(result, @event.context) + when Qmfengine::BrokerEvent::METHOD_RESPONSE + obj = @event.context + obj._method_result(MethodResponse.new(@event.methodResponse)) end @impl.popEvent valid = @impl.getEvent(@event) @@ -946,7 +1202,7 @@ module Qmf end @conn = nil @handler = handler - @impl = Qmfengine::AgentEngine.new(@agentLabel) + @impl = Qmfengine::Agent.new(@agentLabel) @event = Qmfengine::AgentEvent.new @xmtMessage = Qmfengine::Message.new end @@ -1050,5 +1306,4 @@ module Qmf do_events end end - end diff --git a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb index 67591319ee..426a284e7d 100755 --- a/qpid/cpp/bindings/qmf/tests/agent_ruby.rb +++ b/qpid/cpp/bindings/qmf/tests/agent_ruby.rb @@ -40,6 +40,9 @@ class Model @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_property(Qmf::SchemaProperty.new("sstrval", Qmf::TYPE_SSTR)) + @parent_class.add_property(Qmf::SchemaProperty.new("lstrval", Qmf::TYPE_LSTR)) + @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") @@ -50,6 +53,14 @@ class Model method.add_argument(Qmf::SchemaArgument.new("test", Qmf::TYPE_SSTR, :dir => Qmf::DIR_IN)) @parent_class.add_method(method) + method = Qmf::SchemaMethod.new("set_short_string", :desc => "Set the short string value in the object") + method.add_argument(Qmf::SchemaArgument.new("value", Qmf::TYPE_SSTR, :dir => Qmf::DIR_IN_OUT)) + @parent_class.add_method(method) + + method = Qmf::SchemaMethod.new("set_long_string", :desc => "Set the long string value in the object") + method.add_argument(Qmf::SchemaArgument.new("value", Qmf::TYPE_LSTR, :dir => Qmf::DIR_IN_OUT)) + @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)) @@ -84,68 +95,74 @@ class App < Qmf::AgentHandler 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}" + retCode = 0 + retText = "OK" + 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.uint64val = 0x9494949449494949 + @parent.uint32val = 0xa5a55a5a + @parent.uint16val = 0xb66b + @parent.uint8val = 0xc7 - @parent.set_attr("int64val", 1000000000000000000) - @parent.set_attr("int32val", 1000000000) - @parent.set_attr("int16val", 10000) - @parent.set_attr("int8val", 100) + @parent.int64val = 1000000000000000000 + @parent.int32val = 1000000000 + @parent.int16val = 10000 + @parent.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.uint64val = 4 + @parent.uint32val = 5 + @parent.uint16val = 6 + @parent.uint8val = 7 - @parent.set_attr("int64val", 8) - @parent.set_attr("int32val", 9) - @parent.set_attr("int16val", 10) - @parent.set_attr("int8val", 11) + @parent.int64val = 8 + @parent.int32val = 9 + @parent.int16val = 10 + @parent.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.uint64val = 0 + @parent.uint32val = 0 + @parent.uint16val = 0 + @parent.uint8val = 0 - @parent.set_attr("int64val", -10000000000) - @parent.set_attr("int32val", -100000) - @parent.set_attr("int16val", -1000) - @parent.set_attr("int8val", -100) + @parent.int64val = -10000000000 + @parent.int32val = -100000 + @parent.int16val = -1000 + @parent.int8val = -100 else retCode = 1 retText = "Invalid argument value for test" end - @agent.method_response(context, retCode, retText, args) + elsif name == "set_short_string" + @parent.sstrval = args['value'] + + elsif name == "set_long_string" + @parent.lstrval = args['value'] elsif name == "create_child" oid = @agent.alloc_object_id(2) args['child_ref'] = oid @child = Qmf::AgentObject.new(@model.child_class) - @child.set_attr("name", args.by_key("child_name")) + @child.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) + retCode = 1 + retText = "Unimplemented Method: #{name}" end + + @agent.method_response(context, retCode, retText, args) end def main @@ -161,18 +178,18 @@ class App < Qmf::AgentHandler @agent.set_connection(@connection) @parent = Qmf::AgentObject.new(@model.parent_class) - @parent.set_attr("name", "Parent One") - @parent.set_attr("state", "OPERATIONAL") - - @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.name = "Parent One" + @parent.state = "OPERATIONAL" + + @parent.uint64val = 0 + @parent.uint32val = 0 + @parent.uint16val = 0 + @parent.uint8val = 0 + + @parent.int64val = 0 + @parent.int32val = 0 + @parent.int16val = 0 + @parent.int8val = 0 @parent_oid = @agent.alloc_object_id(1) @parent.set_object_id(@parent_oid) diff --git a/qpid/cpp/bindings/qmf/tests/ruby_console.rb b/qpid/cpp/bindings/qmf/tests/ruby_console.rb index c071829f09..0fa856c724 100755 --- a/qpid/cpp/bindings/qmf/tests/ruby_console.rb +++ b/qpid/cpp/bindings/qmf/tests/ruby_console.rb @@ -24,13 +24,46 @@ require 'socket' class App < Qmf::ConsoleHandler + def agent_added(agent) + puts "AgentAdded: #{agent.label} broker=#{agent.broker_bank} agent=#{agent.agent_bank}" + end + + def agent_deleted(agent) + puts "AgentDeleted: #{agent.label}" + end + + def new_package(package) + puts "NewPackage: #{package}" + end + + def new_class(class_key) + puts "NewClass: #{class_key}" + end + + def object_update(object, hasProps, hasStats) + puts "ObjectUpdate: #{object.object_class.class_name} props=#{hasProps} stats=#{hasStats}" + puts " broker-bank=#{object.object_id.broker_bank}" + puts " agent-bank=#{object.object_id.agent_bank}" + puts " package=#{object.object_class.package_name}" + end + + def event_received(event); end + + def agent_heartbeat(agent, timestamp) + puts "AgentHeartbeat: #{agent.label} time=#{timestamp/1000000000}" + end + + def method_response(resp); end + def broker_info(broker); end + + def dump_schema - packages = @qmfc.get_packages + packages = @qmfc.packages puts "----- Packages -----" packages.each do |p| puts p puts " ----- Object Classes -----" - classes = @qmfc.get_classes(p) + classes = @qmfc.classes(p) classes.each do |c| puts " #{c.name}" @@ -59,7 +92,7 @@ class App < Qmf::ConsoleHandler end puts " ----- Event Classes -----" - classes = @qmfc.get_classes(p, Qmf::CLASS_EVENT) + classes = @qmfc.classes(p, Qmf::CLASS_EVENT) classes.each do |c| puts " #{c.name}" puts " ---- Args ----" @@ -74,17 +107,17 @@ 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 + @settings.host = ARGV[0] if ARGV.size > 0 + @settings.port = ARGV[1].to_i if ARGV.size > 1 @connection = Qmf::Connection.new(@settings) - @qmfc = Qmf::Console.new + @qmfc = Qmf::Console.new(self) @broker = @qmfc.add_connection(@connection) - @broker.waitForStable + @broker.wait_for_stable - dump_schema + ##dump_schema - agents = @qmfc.get_agents() + agents = @qmfc.agents() puts "---- Agents ----" agents.each do |a| puts " => #{a.label}" @@ -92,13 +125,30 @@ class App < Qmf::ConsoleHandler puts "----" for idx in 0...20 - blist = @qmfc.get_objects(Qmf::Query.new(:class => "broker")) + blist = @qmfc.objects(Qmf::Query.new(:class => "broker")) puts "---- Brokers ----" blist.each do |b| puts " ---- Broker ----" - puts " systemRef: #{b.get_attr('systemRef')}" - puts " port : #{b.get_attr('port')}" - puts " uptime : #{b.get_attr('uptime') / 1000000000}" + puts " systemRef: #{b.systemRef}" + puts " port : #{b.port}" + puts " uptime : #{b.uptime / 1000000000}" + puts " properties : #{b.properties}" + puts " statistics : #{b.statistics}" + + for rep in 0...1 + puts " Pinging..." + ret = b.echo(45, 'text string') + puts " status=#{ret.status} text=#{ret.exception.asString} seq=#{ret.args.sequence} body=#{ret.args.body}" + end + end + puts "----" + + qlist = @qmfc.objects(Qmf::Query.new(:package => "org.apache.qpid.broker", + :class => "queue")) + puts "---- Queues ----" + qlist.each do |q| + puts " ---- Queue ----" + puts " name : #{q.name}" end puts "----" sleep(5) diff --git a/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb b/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb new file mode 100755 index 0000000000..b72c8e3806 --- /dev/null +++ b/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb @@ -0,0 +1,194 @@ +#!/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 'test_base' + +class ConsoleTest < ConsoleTestBase + + def test_A_agent_presence + assert(@connection.connected?, "Connection not connected") + + agents = [] + count = 0 + while agents.size == 0 + agents = @qmfc.objects(Qmf::Query.new(:class => "agent")) + sleep(1) + count += 1 + fail("Timed out waiting for remote agent") if count > 10 + end + + agentList = @qmfc.agents + assert_equal(agentList.size, 2, "Number of agents reported by Console") + end + + def test_A_connection_settings + begin + @settings.bogusAttribute = 25 + fail("Connection settings accepted bogus attribute") + rescue + end + end + + def test_B_basic_method_invocation + parent = @qmfc.object(:class => "parent") + assert(parent, "Number of 'parent' objects") + for seq in 0...10 + result = parent.echo(seq) + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + assert_equal(result.args.sequence, seq, "Echo Response Sequence") + end + + result = parent.set_numerics("bogus") + assert_equal(result.status, 1) + assert_equal(result.text, "Invalid argument value for test") + end + + def test_C_basic_types_numeric_big + parent = @qmfc.object(:class =>"parent") + assert(parent, "Number of parent objects") + + result = parent.set_numerics("big") + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + + parent.update + + assert_equal(parent.uint64val, 0x9494949449494949) + assert_equal(parent.uint32val, 0xA5A55A5A) + assert_equal(parent.uint16val, 0xB66B) + assert_equal(parent.uint8val, 0xC7) + + assert_equal(parent.int64val, 1000000000000000000) + assert_equal(parent.int32val, 1000000000) + assert_equal(parent.int16val, 10000) + assert_equal(parent.int8val, 100) + end + + def test_C_basic_types_numeric_small + parent = @qmfc.object(:class =>"parent") + assert(parent, "Number of parent objects") + + result = parent.set_numerics("small") + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + + parent.update + + assert_equal(parent.uint64val, 4) + assert_equal(parent.uint32val, 5) + assert_equal(parent.uint16val, 6) + assert_equal(parent.uint8val, 7) + + assert_equal(parent.int64val, 8) + assert_equal(parent.int32val, 9) + assert_equal(parent.int16val, 10) + assert_equal(parent.int8val, 11) + end + + def test_C_basic_types_numeric_negative + parent = @qmfc.object(:class =>"parent") + assert(parent, "Number of parent objects") + + result = parent.set_numerics("negative") + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + + parent.update + + assert_equal(parent.uint64val, 0) + assert_equal(parent.uint32val, 0) + assert_equal(parent.uint16val, 0) + assert_equal(parent.uint8val, 0) + + assert_equal(parent.int64val, -10000000000) + assert_equal(parent.int32val, -100000) + assert_equal(parent.int16val, -1000) + assert_equal(parent.int8val, -100) + end + + def test_C_basic_types_string_short + parent = @qmfc.object(:class =>"parent") + assert(parent, "Number of parent objects") + + strings = [] + strings << "" + strings << "A" + strings << "BC" + strings << "DEF" + strings << "GHIJKLMNOPQRSTUVWXYZ" + big = "a" + for i in 0...270 + big << "X" + end + strings << big + + strings.each do |str| + result = parent.set_short_string(str) + assert_equal(result.status, 0, "Method Response Status") + compare = str + compare = compare[0..254] if compare.size > 255 + assert_equal(result.args.value, compare, "Value returned by method") + parent.update + assert_equal(parent.sstrval, compare, "Value stored in the object") + end + end + + def test_C_basic_types_string_long + parent = @qmfc.object(:class =>"parent") + assert(parent, "Number of parent objects") + + strings = [] + strings << "" + strings << "A" + strings << "BC" + strings << "DEF" + strings << "GHIJKLMNOPQRSTUVWXYZ" + big = "a" + for i in 0...270 + big << "X" + end + strings << big + + strings.each do |str| + result = parent.set_long_string(str) + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.args.value, str, "Value returned by method") + parent.update + assert_equal(parent.lstrval, str, "Value stored in the object") + end + end + + def test_D_userid_for_method + parent = @qmfc.object(:class => "parent") + assert(parent, "Number of parent objects") + + result = parent.probe_userid + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.args.userid, "anonymous") + end + +end + +app = ConsoleTest.new + + + diff --git a/qpid/cpp/bindings/qmf/tests/run_interop_tests b/qpid/cpp/bindings/qmf/tests/run_interop_tests index 01d7221ac6..b5545d736d 100755 --- a/qpid/cpp/bindings/qmf/tests/run_interop_tests +++ b/qpid/cpp/bindings/qmf/tests/run_interop_tests @@ -88,11 +88,19 @@ if test -d ${PYTHON_DIR} ; then 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 + + echo " Ruby Agent (external storage) vs. Ruby Console" + ruby -I${MY_DIR} -I${MY_DIR}/../ruby -I${RUBY_LIB_DIR} ${MY_DIR}/ruby_console_test.rb localhost $BROKER_PORT $@ + RETCODE=$? + stop_ruby_agent + if test x$RETCODE != x0; then + echo "FAIL qmf interop tests (Ruby Console/Ruby Agent)"; + TESTS_FAILED=1 + fi fi # Also against the Pure-Python console: diff --git a/qpid/cpp/bindings/qmf/tests/test_base.rb b/qpid/cpp/bindings/qmf/tests/test_base.rb new file mode 100644 index 0000000000..cb7fd9d4f9 --- /dev/null +++ b/qpid/cpp/bindings/qmf/tests/test_base.rb @@ -0,0 +1,73 @@ +#!/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 ConsoleTestBase < Qmf::ConsoleHandler + def initialize + @settings = Qmf::ConnectionSettings.new + @settings.host = ARGV[0] if ARGV.size > 0 + @settings.port = ARGV[1].to_i if ARGV.size > 1 + @connection = Qmf::Connection.new(@settings) + @qmfc = Qmf::Console.new + + @broker = @qmfc.add_connection(@connection) + @broker.wait_for_stable + + tests = [] + methods.each do |m| + name = m.to_s + tests << name if name[0..4] == "test_" + end + + failures = 0 + + tests.sort.each do |t| + begin + print "#{t}..." + $stdout.flush + send(t) + puts " Pass" + rescue + puts " Fail: #{$!}" + failures += 1 + end + end + + @qmfc.del_connection(@broker) + exit(1) if failures > 0 + end + + def assert_equal(left, right, in_text=nil) + text = " (#{in_text})" if in_text + raise "Assertion failed: #{left} != #{right}#{text}" unless left == right + end + + def assert(condition, in_text=nil) + text = " (#{in_text})" if in_text + raise "Assertion failed: #{left} != #{right}#{text}" unless condition + end + + def fail(text) + raise text + end +end diff --git a/qpid/cpp/boost-1.32-support/supressions b/qpid/cpp/boost-1.32-support/supressions index 0747e32cc7..c2b4392566 100644 --- a/qpid/cpp/boost-1.32-support/supressions +++ b/qpid/cpp/boost-1.32-support/supressions @@ -789,3 +789,79 @@ fun:getaddrinfo fun:_ZNK4qpid3sys6Socket7connectERKSst } +{ + dl 0 + Memcheck:Leak + fun:*dl* +} + +{ + dl 1 + Memcheck:Leak + fun:* + fun:*dl* +} + +{ + dl 2 + fun:* + fun:* + Memcheck:Leak + fun:*dl* +} + +{ + Znwm + Memcheck:Leak + fun:_Znwm +} + +{ + Znwj + Memcheck:Leak + fun:_Znwj +} + +{ + Znaj + Memcheck:Leak + fun:_Znaj +} + +{ + libc res nsend + Memcheck:Leak + fun:malloc + fun:__libc_res_nsend +} + +{ + new exitfn + Memcheck:Leak + fun:malloc + fun:__new_exitfn +} + +{ + pthread mutex unlock + Memcheck:Param + futex(uaddr2) + fun:__lll_mutex_unlock_wake + fun:pthread_mutex_unlock +} + +{ + sasl 1 + Memcheck:Leak + fun:* + fun:sasl* +} + +{ + sasl 2 + Memcheck:Leak + fun:* + obj:* + fun:sasl* +} + diff --git a/qpid/cpp/etc/CMakeLists.txt b/qpid/cpp/etc/CMakeLists.txt new file mode 100644 index 0000000000..03121b364a --- /dev/null +++ b/qpid/cpp/etc/CMakeLists.txt @@ -0,0 +1,20 @@ +# +# 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. +# + +install(FILES qpidd.conf qpidc.conf DESTINATION ${QPID_INSTALL_CONFDIR}) diff --git a/qpid/cpp/examples/messaging/client.cpp b/qpid/cpp/examples/messaging/client.cpp index 45c065880b..de6d7768df 100644 --- a/qpid/cpp/examples/messaging/client.cpp +++ b/qpid/cpp/examples/messaging/client.cpp @@ -63,7 +63,7 @@ int main(int argc, char** argv) { request.setContent(s[i]); sender.send(request); Message response = receiver.fetch(); - std::cout << request.getContent().asString() << " -> " << response.getContent().asString() << std::endl; + std::cout << request.getContent() << " -> " << response.getContent() << std::endl; } connection.close(); return 0; diff --git a/qpid/cpp/examples/messaging/map_receiver.cpp b/qpid/cpp/examples/messaging/map_receiver.cpp index e6557b1560..f97c44eebd 100644 --- a/qpid/cpp/examples/messaging/map_receiver.cpp +++ b/qpid/cpp/examples/messaging/map_receiver.cpp @@ -20,6 +20,7 @@ */ #include <qpid/messaging/Connection.h> +#include <qpid/messaging/MapView.h> #include <qpid/messaging/Message.h> #include <qpid/messaging/Receiver.h> #include <qpid/messaging/Session.h> @@ -42,7 +43,8 @@ int main(int argc, char** argv) { Session session = connection.newSession(); Receiver receiver = session.createReceiver("message_queue"); Message message = receiver.fetch(); - std::cout << message.getContent().asMap() << std::endl; + MapView content(message); + std::cout << content << std::endl; session.acknowledge(); receiver.cancel(); connection.close(); diff --git a/qpid/cpp/examples/messaging/map_sender.cpp b/qpid/cpp/examples/messaging/map_sender.cpp index 9301c1fe1f..02c6433836 100644 --- a/qpid/cpp/examples/messaging/map_sender.cpp +++ b/qpid/cpp/examples/messaging/map_sender.cpp @@ -20,6 +20,7 @@ */ #include <qpid/messaging/Connection.h> +#include <qpid/messaging/MapContent.h> #include <qpid/messaging/Message.h> #include <qpid/messaging/Sender.h> #include <qpid/messaging/Session.h> @@ -43,14 +44,16 @@ int main(int argc, char** argv) { 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! + MapContent content(message); + content["id"] = 987654321; + content["name"] = "Widget"; + content["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; + content["colours"] = colours; + content.encode(); sender.send(message); session.sync(); diff --git a/qpid/cpp/examples/messaging/queue_listener.cpp b/qpid/cpp/examples/messaging/queue_listener.cpp index 099e8e145a..92a0eed5ed 100644 --- a/qpid/cpp/examples/messaging/queue_listener.cpp +++ b/qpid/cpp/examples/messaging/queue_listener.cpp @@ -47,8 +47,8 @@ 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 << "Message: " << message.getContent() << std::endl; + if (message.getContent() == "That's all, folks!") { std::cout << "Shutting down listener" << std::endl; receiver.cancel(); finished = true; diff --git a/qpid/cpp/examples/messaging/queue_receiver.cpp b/qpid/cpp/examples/messaging/queue_receiver.cpp index 83a44b2ca9..40f863eb30 100644 --- a/qpid/cpp/examples/messaging/queue_receiver.cpp +++ b/qpid/cpp/examples/messaging/queue_receiver.cpp @@ -24,16 +24,10 @@ #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"; @@ -47,7 +41,7 @@ int main(int argc, char** argv) { Message message = receiver.fetch(); std::cout << "Message: " << message.getContent() << std::endl; session.acknowledge(); - if (message.getContent().asString() == "That's all, folks!") { + if (message.getContent() == "That's all, folks!") { std::cout << "Cancelling receiver" << std::endl; receiver.cancel(); break; diff --git a/qpid/cpp/examples/messaging/queue_sender.cpp b/qpid/cpp/examples/messaging/queue_sender.cpp index 637e7eb8e4..1396e26d5c 100644 --- a/qpid/cpp/examples/messaging/queue_sender.cpp +++ b/qpid/cpp/examples/messaging/queue_sender.cpp @@ -26,14 +26,10 @@ #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; @@ -45,14 +41,13 @@ int main(int argc, char** argv) { // Now send some messages ... for (int i=0; i<count; i++) { - Message message; - message.getContent() << "Message " << i; - sender.send(message); + std::stringstream content; + content << "Message " << i; + sender.send(Message(content.str())); } - // And send a final message to indicate termination. - Message message("That's all, folks!"); - sender.send(message); + // And send a final message to indicate termination. + sender.send(Message("That's all, folks!")); session.sync(); connection.close(); return 0; diff --git a/qpid/cpp/examples/messaging/server.cpp b/qpid/cpp/examples/messaging/server.cpp index 38f4601ff6..024832f914 100644 --- a/qpid/cpp/examples/messaging/server.cpp +++ b/qpid/cpp/examples/messaging/server.cpp @@ -51,17 +51,17 @@ int main(int argc, char** argv) { const Address& address = request.getReplyTo(); if (address) { Sender sender = session.createSender(address); - std::string s = request.getContent().asString(); + std::string s = request.getContent(); std::transform(s.begin(), s.end(), s.begin(), toupper); Message response(s); sender.send(response); std::cout << "Processed request: " - << request.getContent().asString() + << request.getContent() << " -> " - << response.getContent().asString() << std::endl; + << response.getContent() << std::endl; session.acknowledge(); } else { - std::cerr << "Error: no reply address specified for request: " << request.getContent().asString() << std::endl; + std::cerr << "Error: no reply address specified for request: " << request.getContent() << std::endl; session.reject(request); } } diff --git a/qpid/cpp/examples/messaging/topic_listener.cpp b/qpid/cpp/examples/messaging/topic_listener.cpp index 700e03cdf9..ba999c03a7 100644 --- a/qpid/cpp/examples/messaging/topic_listener.cpp +++ b/qpid/cpp/examples/messaging/topic_listener.cpp @@ -48,8 +48,8 @@ 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 << "Message: " << message.getContent() << std::endl; + if (message.getContent() == "That's all, folks!") { std::cout << "Shutting down listener" << std::endl; receiver.cancel(); finished = true; diff --git a/qpid/cpp/examples/messaging/topic_receiver.cpp b/qpid/cpp/examples/messaging/topic_receiver.cpp index 063f0d9cb0..7352a91b30 100644 --- a/qpid/cpp/examples/messaging/topic_receiver.cpp +++ b/qpid/cpp/examples/messaging/topic_receiver.cpp @@ -47,8 +47,8 @@ int main(int argc, char** argv) { 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 << "Message: " << message.getContent() << std::endl; + if (message.getContent() == "That's all, folks!") { std::cout << "Cancelling receiver" << std::endl; receiver.cancel(); break; diff --git a/qpid/cpp/examples/qmf-agent/Makefile b/qpid/cpp/examples/qmf-agent/Makefile index e652edb1a2..5b1afc4b01 100644 --- a/qpid/cpp/examples/qmf-agent/Makefile +++ b/qpid/cpp/examples/qmf-agent/Makefile @@ -27,7 +27,7 @@ CC = gcc LIB_DIR = $(QPID_DIR)/cpp/src/.libs CC_INCLUDES = -I$(SRC_DIR) -I$(QPID_DIR)/cpp/include -I$(GEN_DIR) CC_FLAGS = -g -O3 -LD_FLAGS = -lqmfagent -lqmfcommon -L$(LIB_DIR) +LD_FLAGS = -lqmf -L$(LIB_DIR) SPEC_DIR = $(QPID_DIR)/specs MGEN_DIR = $(QPID_DIR)/cpp/managementgen MGEN = $(MGEN_DIR)/qmf-gen diff --git a/qpid/cpp/include/qmf/ConnectionSettings.h b/qpid/cpp/include/qmf/ConnectionSettings.h index 9bd6922a56..11af73d797 100644 --- a/qpid/cpp/include/qmf/ConnectionSettings.h +++ b/qpid/cpp/include/qmf/ConnectionSettings.h @@ -20,124 +20,13 @@ * under the License. */ -#include "qmf/QmfImportExport.h" -#include "qpid/sys/IntegerTypes.h" - namespace qmf { + namespace engine { + class ConnectionSettings; + } - 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; - }; - + typedef class engine::ConnectionSettings ConnectionSettings; } #endif + diff --git a/qpid/cpp/include/qmf/ConsoleObject.h b/qpid/cpp/include/qmf/ConsoleObject.h new file mode 100644 index 0000000000..acbc285e05 --- /dev/null +++ b/qpid/cpp/include/qmf/ConsoleObject.h @@ -0,0 +1,94 @@ +#ifndef _QmfConsoleObject_ +#define _QmfConsoleObject_ + +/* + * 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 ConsoleObjectImpl; + class SchemaObjectClass; + class ObjectId; + class Value; + + /** + * ConsoleObject is an extension of Object with console-specific methods added. + * + * \ingroup qmfapi + */ + class ConsoleObject : 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 ConsoleObject(const SchemaObjectClass* type); + + /** + * Destroy the object. + */ + QMF_EXTERN virtual ~ConsoleObject(); + + /** + * + */ + QMF_EXTERN const SchemaObjectClass* getSchema() const; + + /** + * + */ + QMF_EXTERN ObjectId* getObjectId() const; + + /** + * + */ + QMF_EXTERN uint64_t getCurrentTime() const; + QMF_EXTERN uint64_t getCreateTime() const; + QMF_EXTERN uint64_t getDeleteTime() const; + + /** + * + */ + QMF_EXTERN bool isDeleted() const; + + /** + * + */ + QMF_EXTERN void update(); + + /** + * + */ + QMF_EXTERN void invokeMethod(const char* name, const Value* arguments, MethodResult& result); + + /** + * + */ + QMF_EXTERN uint32_t invokeMethodAsync(const char* name, const Value* arguments = 0); + + private: + ConsoleObjectImpl* impl; + }; + +} + +#endif diff --git a/qpid/cpp/src/qmf/AgentEngine.h b/qpid/cpp/include/qmf/engine/Agent.h index c88ef33657..71abf82254 100644 --- a/qpid/cpp/src/qmf/AgentEngine.h +++ b/qpid/cpp/include/qmf/engine/Agent.h @@ -1,5 +1,5 @@ -#ifndef _QmfAgentEngine_ -#define _QmfAgentEngine_ +#ifndef _QmfEngineAgent_ +#define _QmfEngineAgent_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,15 +20,16 @@ * under the License. */ -#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> +#include <qmf/engine/Schema.h> +#include <qmf/engine/ObjectId.h> +#include <qmf/engine/Object.h> +#include <qmf/engine/Event.h> +#include <qmf/engine/Query.h> +#include <qmf/engine/Value.h> +#include <qmf/engine/Message.h> namespace qmf { +namespace engine { /** * AgentEvent @@ -61,18 +62,18 @@ namespace qmf { Value* arguments; // Method parameters (METHOD_CALL) char* exchange; // Exchange for bind (BIND, UNBIND) char* bindingKey; // Key for bind (BIND, UNBIND) - SchemaObjectClass* objectClass; // (METHOD_CALL) + const SchemaObjectClass* objectClass; // (METHOD_CALL) }; - class AgentEngineImpl; + class AgentImpl; /** - * AgentEngine - Protocol engine for the QMF agent + * Agent - Protocol engine for the QMF agent */ - class AgentEngine { + class Agent { public: - AgentEngine(char* label, bool internalStore=true); - ~AgentEngine(); + Agent(char* label, bool internalStore=true); + ~Agent(); /** * Configure the directory path for storing persistent data. @@ -199,9 +200,10 @@ namespace qmf { void raiseEvent(Event& event); private: - AgentEngineImpl* impl; + AgentImpl* impl; }; } +} #endif diff --git a/qpid/cpp/include/qmf/engine/ConnectionSettings.h b/qpid/cpp/include/qmf/engine/ConnectionSettings.h new file mode 100644 index 0000000000..36312400b1 --- /dev/null +++ b/qpid/cpp/include/qmf/engine/ConnectionSettings.h @@ -0,0 +1,150 @@ +#ifndef _QmfEngineConnectionSettings_ +#define _QmfEngineConnectionSettings_ + +/* + * 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/engine/QmfEngineImportExport.h" +#include "qpid/sys/IntegerTypes.h" + +namespace qmf { +namespace engine { + + class ConnectionSettingsImpl; + class Value; + + /** + * Settings for AMQP connections to the broker. + * + * \ingroup qmfapi + */ + class ConnectionSettings { + public: + + /** + * 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). + */ + QMFE_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 + */ + QMFE_EXTERN ConnectionSettings(const char* url); + + /** + * Copy Constructor. + */ + ConnectionSettings(const ConnectionSettings& from); + + /** + * Destroy the connection settings object. + */ + QMFE_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. + * + * @return True if success, False if invalid attribute + */ + QMFE_EXTERN bool 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. + */ + QMFE_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. + */ + QMFE_EXTERN const char* getAttrString() const; + + /** + * Shortcuts for setting the transport for the connection. + * + * @param port The port value for the connection address. + */ + QMFE_EXTERN void transportTcp(uint16_t port = 5672); + QMFE_EXTERN void transportSsl(uint16_t port = 5671); + QMFE_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. + */ + QMFE_EXTERN void authAnonymous(const char* username = 0); + QMFE_EXTERN void authPlain(const char* username = 0, const char* password = 0); + QMFE_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. + */ + QMFE_EXTERN void setRetry(int delayMin = 1, int delayMax = 128, int delayFactor = 2); + + private: + friend class ResilientConnectionImpl; + ConnectionSettingsImpl* impl; + }; + +} +} + +#endif diff --git a/qpid/cpp/src/qmf/ConsoleEngine.h b/qpid/cpp/include/qmf/engine/Console.h index 457e83ad58..ce72360da7 100644 --- a/qpid/cpp/src/qmf/ConsoleEngine.h +++ b/qpid/cpp/include/qmf/engine/Console.h @@ -1,5 +1,5 @@ -#ifndef _QmfConsoleEngine_ -#define _QmfConsoleEngine_ +#ifndef _QmfEngineConsole_ +#define _QmfEngineConsole_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,39 +20,42 @@ * 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> +#include <qmf/engine/ResilientConnection.h> +#include <qmf/engine/Schema.h> +#include <qmf/engine/ObjectId.h> +#include <qmf/engine/Object.h> +#include <qmf/engine/Event.h> +#include <qmf/engine/Query.h> +#include <qmf/engine/Value.h> +#include <qmf/engine/Message.h> namespace qmf { +namespace engine { - class ConsoleEngine; - class ConsoleEngineImpl; + class Console; + struct ConsoleImpl; class BrokerProxyImpl; class AgentProxy; - class AgentProxyImpl; - class MethodResponseImpl; - class QueryResponseImpl; - class QueryContext; + struct AgentProxyImpl; + struct MethodResponseImpl; + struct QueryResponseImpl; + struct QueryContext; /** * */ class MethodResponse { public: - MethodResponse(MethodResponseImpl* impl); + MethodResponse(const MethodResponse& from); ~MethodResponse(); uint32_t getStatus() const; const Value* getException() const; const Value* getArgs() const; private: - friend class ConsoleEngineImpl; + friend struct MethodResponseImpl; + friend struct ConsoleImpl; + MethodResponse(MethodResponseImpl* impl); MethodResponseImpl* impl; }; @@ -61,7 +64,6 @@ namespace qmf { */ class QueryResponse { public: - QueryResponse(QueryResponseImpl* impl); ~QueryResponse(); uint32_t getStatus() const; const Value* getException() const; @@ -69,7 +71,9 @@ namespace qmf { const Object* getObject(uint32_t idx) const; private: - friend class QueryContext; + friend struct QueryResponseImpl; + friend struct QueryContext; + QueryResponse(QueryResponseImpl* impl); QueryResponseImpl *impl; }; @@ -84,21 +88,20 @@ namespace qmf { NEW_CLASS = 4, OBJECT_UPDATE = 5, EVENT_RECEIVED = 7, - AGENT_HEARTBEAT = 8, - METHOD_RESPONSE = 9 + AGENT_HEARTBEAT = 8 }; EventKind kind; AgentProxy* agent; // (AGENT_[ADDED|DELETED|HEARTBEAT]) char* name; // (NEW_PACKAGE) - SchemaClassKey* classKey; // (NEW_CLASS) + const SchemaClassKey* classKey; // (NEW_CLASS) Object* object; // (OBJECT_UPDATE) void* context; // (OBJECT_UPDATE) Event* event; // (EVENT_RECEIVED) uint64_t timestamp; // (AGENT_HEARTBEAT) - uint32_t methodHandle; // (METHOD_RESPONSE) - MethodResponse* methodResponse; // (METHOD_RESPONSE) QueryResponse* queryResponse; // (QUERY_COMPLETE) + bool hasProps; + bool hasStats; }; /** @@ -113,15 +116,17 @@ namespace qmf { UNBIND = 14, SETUP_COMPLETE = 15, STABLE = 16, - QUERY_COMPLETE = 17 + QUERY_COMPLETE = 17, + METHOD_RESPONSE = 18 }; EventKind kind; - char* name; // ([DECLARE|DELETE]_QUEUE, [UN]BIND) - char* exchange; // ([UN]BIND) - char* bindingKey; // ([UN]BIND) - void* context; // (QUERY_COMPLETE) - QueryResponse* queryResponse; // (QUERY_COMPLETE) + char* name; // ([DECLARE|DELETE]_QUEUE, [UN]BIND) + char* exchange; // ([UN]BIND) + char* bindingKey; // ([UN]BIND) + void* context; // (QUERY_COMPLETE, METHOD_RESPONSE) + QueryResponse* queryResponse; // (QUERY_COMPLETE) + MethodResponse* methodResponse; // (METHOD_RESPONSE) }; /** @@ -129,12 +134,17 @@ namespace qmf { */ class AgentProxy { public: - AgentProxy(AgentProxyImpl* impl); ~AgentProxy(); const char* getLabel() const; + uint32_t getBrokerBank() const; + uint32_t getAgentBank() const; private: + friend struct StaticContext; + friend struct QueryContext; + friend struct AgentProxyImpl; friend class BrokerProxyImpl; + AgentProxy(AgentProxyImpl* impl); AgentProxyImpl* impl; }; @@ -143,7 +153,7 @@ namespace qmf { */ class BrokerProxy { public: - BrokerProxy(ConsoleEngine& console); + BrokerProxy(Console& console); ~BrokerProxy(); void sessionOpened(SessionHandle& sh); @@ -162,7 +172,8 @@ namespace qmf { void sendQuery(const Query& query, void* context, const AgentProxy* agent = 0); private: - friend class ConsoleEngineImpl; + friend struct ConsoleImpl; + friend struct StaticContext; BrokerProxyImpl* impl; }; @@ -180,10 +191,10 @@ namespace qmf { userBindings(false) {} }; - class ConsoleEngine { + class Console { public: - ConsoleEngine(const ConsoleSettings& settings = ConsoleSettings()); - ~ConsoleEngine(); + Console(const ConsoleSettings& settings = ConsoleSettings()); + ~Console(); bool getEvent(ConsoleEvent& event) const; void popEvent(); @@ -213,10 +224,12 @@ namespace qmf { private: friend class BrokerProxyImpl; - friend class AgentProxyImpl; - ConsoleEngineImpl* impl; + friend struct AgentProxyImpl; + friend struct StaticContext; + ConsoleImpl* impl; }; } +} #endif diff --git a/qpid/cpp/src/qmf/Event.h b/qpid/cpp/include/qmf/engine/Event.h index f20c6d2fb1..50ab5c1200 100644 --- a/qpid/cpp/src/qmf/Event.h +++ b/qpid/cpp/include/qmf/engine/Event.h @@ -1,5 +1,5 @@ -#ifndef _QmfEvent_ -#define _QmfEvent_ +#ifndef _QmfEngineEvent_ +#define _QmfEngineEvent_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -21,10 +21,12 @@ */ namespace qmf { +namespace engine { class Event { }; } +} #endif diff --git a/qpid/cpp/src/qmf/Message.h b/qpid/cpp/include/qmf/engine/Message.h index 52b8ba72d3..1e95cc6afe 100644 --- a/qpid/cpp/src/qmf/Message.h +++ b/qpid/cpp/include/qmf/engine/Message.h @@ -1,5 +1,5 @@ -#ifndef _QmfMessage_ -#define _QmfMessage_ +#ifndef _QmfEngineMessage_ +#define _QmfEngineMessage_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -23,6 +23,7 @@ #include "qpid/sys/IntegerTypes.h" namespace qmf { +namespace engine { struct Message { char* body; @@ -35,5 +36,6 @@ namespace qmf { }; } +} #endif diff --git a/qpid/cpp/src/qmf/Object.h b/qpid/cpp/include/qmf/engine/Object.h index 9cb3224d9b..ad67cfdb95 100644 --- a/qpid/cpp/src/qmf/Object.h +++ b/qpid/cpp/include/qmf/engine/Object.h @@ -1,5 +1,5 @@ -#ifndef _QmfObject_ -#define _QmfObject_ +#ifndef _QmfEngineObject_ +#define _QmfEngineObject_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,17 +20,17 @@ * under the License. */ -#include <qmf/Schema.h> -#include <qmf/ObjectId.h> -#include <qmf/Value.h> +#include <qmf/engine/Schema.h> +#include <qmf/engine/ObjectId.h> +#include <qmf/engine/Value.h> namespace qmf { +namespace engine { struct ObjectImpl; class Object { public: Object(const SchemaObjectClass* type); - Object(ObjectImpl* impl); Object(const Object& from); virtual ~Object(); @@ -38,11 +38,19 @@ namespace qmf { const ObjectId* getObjectId() const; void setObjectId(ObjectId* oid); const SchemaObjectClass* getClass() const; - Value* getValue(char* key) const; - + Value* getValue(const char* key) const; + void invokeMethod(const char* methodName, const Value* inArgs, void* context) const; + bool isDeleted() const; + void merge(const Object& from); + + private: + friend struct ObjectImpl; + friend class AgentImpl; + Object(ObjectImpl* impl); ObjectImpl* impl; }; } +} #endif diff --git a/qpid/cpp/src/qmf/ObjectId.h b/qpid/cpp/include/qmf/engine/ObjectId.h index e894e0b39c..2055972c00 100644 --- a/qpid/cpp/src/qmf/ObjectId.h +++ b/qpid/cpp/include/qmf/engine/ObjectId.h @@ -1,5 +1,5 @@ -#ifndef _QmfObjectId_ -#define _QmfObjectId_ +#ifndef _QmfEngineObjectId_ +#define _QmfEngineObjectId_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -23,6 +23,7 @@ #include <qpid/sys/IntegerTypes.h> namespace qmf { +namespace engine { // TODO: Add to/from string and << operator @@ -31,13 +32,17 @@ namespace qmf { public: ObjectId(); ObjectId(const ObjectId& from); - ObjectId(ObjectIdImpl* impl); ~ObjectId(); uint64_t getObjectNum() const; uint32_t getObjectNumHi() const; uint32_t getObjectNumLo() const; bool isDurable() const; + const char* str() const; + uint8_t getFlags() const; + uint16_t getSequence() const; + uint32_t getBrokerBank() const; + uint32_t getAgentBank() const; bool operator==(const ObjectId& other) const; bool operator<(const ObjectId& other) const; @@ -45,9 +50,18 @@ namespace qmf { bool operator<=(const ObjectId& other) const; bool operator>=(const ObjectId& other) const; + private: + friend struct ObjectIdImpl; + friend struct ObjectImpl; + friend class BrokerProxyImpl; + friend struct QueryImpl; + friend struct ValueImpl; + friend class AgentImpl; + ObjectId(ObjectIdImpl* impl); ObjectIdImpl* impl; }; } +} #endif diff --git a/qpid/cpp/include/qmf/engine/QmfEngineImportExport.h b/qpid/cpp/include/qmf/engine/QmfEngineImportExport.h new file mode 100644 index 0000000000..70164c749f --- /dev/null +++ b/qpid/cpp/include/qmf/engine/QmfEngineImportExport.h @@ -0,0 +1,33 @@ +#ifndef QMF_ENGINE_IMPORT_EXPORT_H +#define QMF_ENGINE_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 QMFE_EXTERN __declspec(dllexport) +# else +# define QMFE_EXTERN __declspec(dllimport) +# endif +#else +# define QMFE_EXTERN +#endif + +#endif diff --git a/qpid/cpp/src/qmf/Query.h b/qpid/cpp/include/qmf/engine/Query.h index 875749862e..1b11ea83f2 100644 --- a/qpid/cpp/src/qmf/Query.h +++ b/qpid/cpp/include/qmf/engine/Query.h @@ -1,5 +1,5 @@ -#ifndef _QmfQuery_ -#define _QmfQuery_ +#ifndef _QmfEngineQuery_ +#define _QmfEngineQuery_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,16 +20,17 @@ * under the License. */ -#include <qmf/ObjectId.h> -#include <qmf/Value.h> +#include <qmf/engine/ObjectId.h> +#include <qmf/engine/Value.h> namespace qmf { +namespace engine { - struct Object; + class Object; struct QueryElementImpl; struct QueryImpl; struct QueryExpressionImpl; - struct SchemaClassKey; + class SchemaClassKey; enum ValueOper { O_EQ = 1, @@ -77,7 +78,7 @@ namespace qmf { Query(const char* className, const char* packageName); Query(const SchemaClassKey* key); Query(const ObjectId* oid); - Query(QueryImpl* impl); + Query(const Query& from); ~Query(); void setSelect(const QueryOperand* criterion); @@ -96,9 +97,14 @@ namespace qmf { const char* getOrderBy() const; bool getDecreasing() const; + private: + friend struct QueryImpl; + friend class BrokerProxyImpl; + Query(QueryImpl* impl); QueryImpl* impl; }; } +} #endif diff --git a/qpid/cpp/src/qmf/ResilientConnection.h b/qpid/cpp/include/qmf/engine/ResilientConnection.h index 03f1b9c0d5..359c8ea6ff 100644 --- a/qpid/cpp/src/qmf/ResilientConnection.h +++ b/qpid/cpp/include/qmf/engine/ResilientConnection.h @@ -1,5 +1,5 @@ -#ifndef _QmfResilientConnection_ -#define _QmfResilientConnection_ +#ifndef _QmfEngineResilientConnection_ +#define _QmfEngineResilientConnection_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,11 +20,12 @@ * under the License. */ -#include <qmf/Message.h> -#include <qmf/ConnectionSettings.h> +#include <qmf/engine/Message.h> +#include <qmf/engine/ConnectionSettings.h> #include <string> namespace qmf { +namespace engine { class ResilientConnectionImpl; @@ -158,6 +159,7 @@ namespace qmf { ResilientConnectionImpl* impl; }; } +} #endif diff --git a/qpid/cpp/src/qmf/Schema.h b/qpid/cpp/include/qmf/engine/Schema.h index 1123acc3b8..16f11a83f9 100644 --- a/qpid/cpp/src/qmf/Schema.h +++ b/qpid/cpp/include/qmf/engine/Schema.h @@ -1,5 +1,5 @@ -#ifndef _QmfSchema_ -#define _QmfSchema_ +#ifndef _QmfEngineSchema_ +#define _QmfEngineSchema_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,10 +20,11 @@ * under the License. */ -#include <qmf/Typecode.h> +#include <qmf/engine/Typecode.h> #include <qpid/sys/IntegerTypes.h> namespace qmf { +namespace engine { enum Access { ACCESS_READ_CREATE = 1, ACCESS_READ_WRITE = 2, ACCESS_READ_ONLY = 3 }; enum Direction { DIR_IN = 1, DIR_OUT = 2, DIR_IN_OUT = 3 }; @@ -42,7 +43,7 @@ namespace qmf { class SchemaArgument { public: SchemaArgument(const char* name, Typecode typecode); - SchemaArgument(SchemaArgumentImpl* impl); + SchemaArgument(const SchemaArgument& from); ~SchemaArgument(); void setDirection(Direction dir); void setUnit(const char* val); @@ -53,6 +54,11 @@ namespace qmf { const char* getUnit() const; const char* getDesc() const; + private: + friend struct SchemaArgumentImpl; + friend struct SchemaMethodImpl; + friend struct SchemaEventClassImpl; + SchemaArgument(SchemaArgumentImpl* impl); SchemaArgumentImpl* impl; }; @@ -61,15 +67,20 @@ namespace qmf { class SchemaMethod { public: SchemaMethod(const char* name); - SchemaMethod(SchemaMethodImpl* impl); + SchemaMethod(const SchemaMethod& from); ~SchemaMethod(); - void addArgument(const SchemaArgument& argument); + void addArgument(const SchemaArgument* argument); void setDesc(const char* desc); const char* getName() const; const char* getDesc() const; int getArgumentCount() const; const SchemaArgument* getArgument(int idx) const; + private: + friend struct SchemaMethodImpl; + friend struct SchemaObjectClassImpl; + friend class AgentImpl; + SchemaMethod(SchemaMethodImpl* impl); SchemaMethodImpl* impl; }; @@ -78,7 +89,7 @@ namespace qmf { class SchemaProperty { public: SchemaProperty(const char* name, Typecode typecode); - SchemaProperty(SchemaPropertyImpl* impl); + SchemaProperty(const SchemaProperty& from); ~SchemaProperty(); void setAccess(Access access); void setIndex(bool val); @@ -93,6 +104,10 @@ namespace qmf { const char* getUnit() const; const char* getDesc() const; + private: + friend struct SchemaPropertyImpl; + friend struct SchemaObjectClassImpl; + SchemaProperty(SchemaPropertyImpl* impl); SchemaPropertyImpl* impl; }; @@ -101,7 +116,7 @@ namespace qmf { class SchemaStatistic { public: SchemaStatistic(const char* name, Typecode typecode); - SchemaStatistic(SchemaStatisticImpl* impl); + SchemaStatistic(const SchemaStatistic& from); ~SchemaStatistic(); void setUnit(const char* val); void setDesc(const char* desc); @@ -110,6 +125,10 @@ namespace qmf { const char* getUnit() const; const char* getDesc() const; + private: + friend struct SchemaStatisticImpl; + friend struct SchemaObjectClassImpl; + SchemaStatistic(SchemaStatisticImpl* impl); SchemaStatisticImpl* impl; }; @@ -117,13 +136,22 @@ namespace qmf { */ class SchemaClassKey { public: - SchemaClassKey(SchemaClassKeyImpl* impl); + SchemaClassKey(const SchemaClassKey& from); ~SchemaClassKey(); const char* getPackageName() const; const char* getClassName() const; const uint8_t* getHash() const; + const char* asString() const; + + bool operator==(const SchemaClassKey& other) const; + bool operator<(const SchemaClassKey& other) const; + private: + friend struct SchemaClassKeyImpl; + friend class BrokerProxyImpl; + friend struct ConsoleImpl; + SchemaClassKey(SchemaClassKeyImpl* impl); SchemaClassKeyImpl* impl; }; @@ -132,11 +160,11 @@ namespace qmf { class SchemaObjectClass { public: SchemaObjectClass(const char* package, const char* name); - SchemaObjectClass(SchemaObjectClassImpl* impl); + SchemaObjectClass(const SchemaObjectClass& from); ~SchemaObjectClass(); - void addProperty(const SchemaProperty& property); - void addStatistic(const SchemaStatistic& statistic); - void addMethod(const SchemaMethod& method); + void addProperty(const SchemaProperty* property); + void addStatistic(const SchemaStatistic* statistic); + void addMethod(const SchemaMethod* method); const SchemaClassKey* getClassKey() const; int getPropertyCount() const; @@ -146,6 +174,11 @@ namespace qmf { const SchemaStatistic* getStatistic(int idx) const; const SchemaMethod* getMethod(int idx) const; + private: + friend struct SchemaObjectClassImpl; + friend class BrokerProxyImpl; + friend class AgentImpl; + SchemaObjectClass(SchemaObjectClassImpl* impl); SchemaObjectClassImpl* impl; }; @@ -154,18 +187,24 @@ namespace qmf { class SchemaEventClass { public: SchemaEventClass(const char* package, const char* name); - SchemaEventClass(SchemaEventClassImpl* impl); + SchemaEventClass(const SchemaEventClass& from); ~SchemaEventClass(); - void addArgument(const SchemaArgument& argument); + void addArgument(const SchemaArgument* argument); void setDesc(const char* desc); const SchemaClassKey* getClassKey() const; int getArgumentCount() const; const SchemaArgument* getArgument(int idx) const; + private: + friend struct SchemaEventClassImpl; + friend class BrokerProxyImpl; + friend class AgentImpl; + SchemaEventClass(SchemaEventClassImpl* impl); SchemaEventClassImpl* impl; }; } +} #endif diff --git a/qpid/cpp/src/qmf/Typecode.h b/qpid/cpp/include/qmf/engine/Typecode.h index 94614d2977..613f96a483 100644 --- a/qpid/cpp/src/qmf/Typecode.h +++ b/qpid/cpp/include/qmf/engine/Typecode.h @@ -1,5 +1,5 @@ -#ifndef _QmfTypecode_ -#define _QmfTypecode_ +#ifndef _QmfEngineTypecode_ +#define _QmfEngineTypecode_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -21,6 +21,7 @@ */ namespace qmf { +namespace engine { enum Typecode { TYPE_UINT8 = 1, @@ -46,6 +47,7 @@ namespace qmf { TYPE_ARRAY = 22 }; } +} #endif diff --git a/qpid/cpp/src/qmf/Value.h b/qpid/cpp/include/qmf/engine/Value.h index bb946d31d3..8eae382caf 100644 --- a/qpid/cpp/src/qmf/Value.h +++ b/qpid/cpp/include/qmf/engine/Value.h @@ -1,5 +1,5 @@ -#ifndef _QmfValue_ -#define _QmfValue_ +#ifndef _QmfEngineValue_ +#define _QmfEngineValue_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,10 +20,11 @@ * under the License. */ -#include <qmf/ObjectId.h> -#include <qmf/Typecode.h> +#include <qmf/engine/ObjectId.h> +#include <qmf/engine/Typecode.h> namespace qmf { +namespace engine { class Object; struct ValueImpl; @@ -31,8 +32,8 @@ namespace qmf { class Value { public: // Value(); + Value(const Value& from); Value(Typecode t, Typecode arrayType = TYPE_UINT8); - Value(ValueImpl* impl); ~Value(); Typecode getType() const; @@ -80,7 +81,7 @@ namespace qmf { void setUuid(const uint8_t* val); bool isObject() const; - Object* asObject() const; + const Object* asObject() const; void setObject(Object* val); bool isMap() const; @@ -105,9 +106,16 @@ namespace qmf { void appendToArray(Value* val); void deleteArrayItem(uint32_t idx); + private: + friend struct ValueImpl; + friend class BrokerProxyImpl; + friend struct ObjectImpl; + friend class AgentImpl; + Value(ValueImpl* impl); ValueImpl* impl; }; } +} #endif diff --git a/qpid/cpp/include/qpid/client/QueueOptions.h b/qpid/cpp/include/qpid/client/QueueOptions.h index 9418cb092d..f8a4963f06 100644 --- a/qpid/cpp/include/qpid/client/QueueOptions.h +++ b/qpid/cpp/include/qpid/client/QueueOptions.h @@ -90,7 +90,22 @@ class QueueOptions: public framing::FieldTable * Turns on event generation for this queue (either enqueue only * or for enqueue and dequeue events); the events can then be * processed by a regsitered broker plugin. + * + * DEPRECATED + * + * This is confusing to anyone who sees only the function call + * and not the variable name / doxygen. Consider the following call: + * + * options.enableQueueEvents(false); + * + * It looks like it disables queue events, but what it really does is + * enable both enqueue and dequeue events. + * + * Use setInt() instead: + * + * options.setInt("qpid.queue_event_generation", 2); */ + QPID_CLIENT_EXTERN void enableQueueEvents(bool enqueueOnly); static QPID_CLIENT_EXTERN const std::string strMaxCountKey; diff --git a/qpid/cpp/include/qpid/messaging/ListContent.h b/qpid/cpp/include/qpid/messaging/ListContent.h new file mode 100644 index 0000000000..1c4e13716d --- /dev/null +++ b/qpid/cpp/include/qpid/messaging/ListContent.h @@ -0,0 +1,90 @@ +#ifndef QPID_MESSAGING_LISTCONTENT_H +#define QPID_MESSAGING_LISTCONTENT_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 "Variant.h" + +namespace qpid { +namespace messaging { + +class ListContentImpl; +class Message; + +/** + * Allows message content to be manipulated as a list. + */ +class ListContent +{ + public: + typedef Variant::List::iterator iterator; + typedef Variant::List::reverse_iterator reverse_iterator; + typedef Variant::List::const_iterator const_iterator; + typedef Variant::List::const_reverse_iterator const_reverse_iterator; + + QPID_CLIENT_EXTERN ListContent(Message&); + QPID_CLIENT_EXTERN ~ListContent(); + + QPID_CLIENT_EXTERN const_iterator begin() const; + QPID_CLIENT_EXTERN iterator begin(); + QPID_CLIENT_EXTERN const_iterator end() const; + QPID_CLIENT_EXTERN iterator end(); + QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const; + QPID_CLIENT_EXTERN reverse_iterator rbegin(); + QPID_CLIENT_EXTERN const_reverse_iterator rend() const; + QPID_CLIENT_EXTERN reverse_iterator rend(); + + QPID_CLIENT_EXTERN bool empty() const; + QPID_CLIENT_EXTERN size_t size() const; + + QPID_CLIENT_EXTERN const Variant& front() const; + QPID_CLIENT_EXTERN Variant& front(); + QPID_CLIENT_EXTERN const Variant& back() const; + QPID_CLIENT_EXTERN Variant& back(); + + QPID_CLIENT_EXTERN void push_front(const Variant&); + QPID_CLIENT_EXTERN void push_back(const Variant&); + + QPID_CLIENT_EXTERN void pop_front(); + QPID_CLIENT_EXTERN void pop_back(); + + QPID_CLIENT_EXTERN iterator insert(iterator position, const Variant&); + QPID_CLIENT_EXTERN void insert(iterator position, size_t n, const Variant&); + QPID_CLIENT_EXTERN iterator erase(iterator position); + QPID_CLIENT_EXTERN iterator erase(iterator first, iterator last); + QPID_CLIENT_EXTERN void clear(); + + QPID_CLIENT_EXTERN void encode(); + + QPID_CLIENT_EXTERN const Variant::List& asList() const; + QPID_CLIENT_EXTERN Variant::List& asList(); + private: + ListContentImpl* impl; + + QPID_CLIENT_EXTERN ListContent& operator=(const ListContent&); +}; + +QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const ListContent& m); + +}} // namespace qpid::messaging + +#endif /*!QPID_MESSAGING_LISTCONTENT_H*/ diff --git a/qpid/cpp/include/qpid/messaging/ListView.h b/qpid/cpp/include/qpid/messaging/ListView.h new file mode 100644 index 0000000000..4970a20072 --- /dev/null +++ b/qpid/cpp/include/qpid/messaging/ListView.h @@ -0,0 +1,67 @@ +#ifndef QPID_MESSAGING_LISTVIEW_H +#define QPID_MESSAGING_LISTVIEW_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 "Variant.h" + +namespace qpid { +namespace messaging { + +class ListViewImpl; +class Message; + +/** + * Provides a view of message content as a list + */ +class ListView +{ + public: + typedef Variant::List::const_iterator const_iterator; + typedef Variant::List::const_reverse_iterator const_reverse_iterator; + + QPID_CLIENT_EXTERN ListView(const Message&); + QPID_CLIENT_EXTERN ~ListView(); + QPID_CLIENT_EXTERN ListView& operator=(const ListView&); + + QPID_CLIENT_EXTERN const_iterator begin() const; + QPID_CLIENT_EXTERN const_iterator end() const; + QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const; + QPID_CLIENT_EXTERN const_reverse_iterator rend() const; + + QPID_CLIENT_EXTERN bool empty() const; + QPID_CLIENT_EXTERN size_t size() const; + + QPID_CLIENT_EXTERN const Variant& front() const; + QPID_CLIENT_EXTERN const Variant& back() const; + + QPID_CLIENT_EXTERN const Variant::List& asList() const; + private: + ListViewImpl* impl; +}; + +QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const ListView& m); + +}} // namespace qpid::messaging + +#endif /*!QPID_MESSAGING_LISTVIEW_H*/ diff --git a/qpid/cpp/include/qpid/messaging/MapContent.h b/qpid/cpp/include/qpid/messaging/MapContent.h new file mode 100644 index 0000000000..b05cb31295 --- /dev/null +++ b/qpid/cpp/include/qpid/messaging/MapContent.h @@ -0,0 +1,90 @@ +#ifndef QPID_MESSAGING_MAPCONTENT_H +#define QPID_MESSAGING_MAPCONTENT_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 "Variant.h" +#include <map> +#include <string> + +namespace qpid { +namespace messaging { + +class MapContentImpl; +class Message; + +/** + * Allows message content to be manipulated as a map + */ +class MapContent +{ + public: + typedef std::string key_type; + typedef std::pair<std::string, Variant> value_type; + typedef std::map<key_type, Variant>::const_iterator const_iterator; + typedef std::map<key_type, Variant>::iterator iterator; + typedef std::map<key_type, Variant>::const_reverse_iterator const_reverse_iterator; + typedef std::map<key_type, Variant>::reverse_iterator reverse_iterator; + + QPID_CLIENT_EXTERN MapContent(Message&); + QPID_CLIENT_EXTERN ~MapContent(); + + QPID_CLIENT_EXTERN const_iterator begin() const; + QPID_CLIENT_EXTERN const_iterator end() const; + QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const; + QPID_CLIENT_EXTERN const_reverse_iterator rend() const; + QPID_CLIENT_EXTERN iterator begin(); + QPID_CLIENT_EXTERN iterator end(); + QPID_CLIENT_EXTERN reverse_iterator rbegin(); + QPID_CLIENT_EXTERN reverse_iterator rend(); + + QPID_CLIENT_EXTERN bool empty() const; + QPID_CLIENT_EXTERN size_t size() const; + + QPID_CLIENT_EXTERN const_iterator find(const key_type&) const; + QPID_CLIENT_EXTERN iterator find(const key_type&); + QPID_CLIENT_EXTERN const Variant& operator[](const key_type&) const; + QPID_CLIENT_EXTERN Variant& operator[](const key_type&); + + QPID_CLIENT_EXTERN std::pair<iterator,bool> insert(const value_type&); + QPID_CLIENT_EXTERN iterator insert(iterator position, const value_type&); + QPID_CLIENT_EXTERN void erase(iterator position); + QPID_CLIENT_EXTERN void erase(iterator first, iterator last); + QPID_CLIENT_EXTERN size_t erase(const key_type&); + QPID_CLIENT_EXTERN void clear(); + + QPID_CLIENT_EXTERN void encode(); + + QPID_CLIENT_EXTERN const std::map<key_type, Variant>& asMap() const; + QPID_CLIENT_EXTERN std::map<key_type, Variant>& asMap(); + private: + MapContentImpl* impl; + + QPID_CLIENT_EXTERN MapContent& operator=(const MapContent&); +}; + +QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const MapContent& m); + +}} // namespace qpid::messaging + +#endif /*!QPID_MESSAGING_MAPCONTENT_H*/ diff --git a/qpid/cpp/include/qpid/messaging/MapView.h b/qpid/cpp/include/qpid/messaging/MapView.h new file mode 100644 index 0000000000..910dfca5c2 --- /dev/null +++ b/qpid/cpp/include/qpid/messaging/MapView.h @@ -0,0 +1,70 @@ +#ifndef QPID_MESSAGING_MAPVIEW_H +#define QPID_MESSAGING_MAPVIEW_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 "Variant.h" +#include <map> +#include <string> + +namespace qpid { +namespace messaging { + +class MapViewImpl; +class Message; + +/** + * Provides a view of message content as a list + */ +class MapView +{ + public: + typedef std::string key_type; + typedef std::pair<key_type, Variant> value_type; + typedef std::map<key_type, Variant>::const_iterator const_iterator; + typedef std::map<key_type, Variant>::const_reverse_iterator const_reverse_iterator; + + QPID_CLIENT_EXTERN MapView(const Message&); + QPID_CLIENT_EXTERN ~MapView(); + QPID_CLIENT_EXTERN MapView& operator=(const MapView&); + + QPID_CLIENT_EXTERN const_iterator begin() const; + QPID_CLIENT_EXTERN const_iterator end() const; + QPID_CLIENT_EXTERN const_reverse_iterator rbegin() const; + QPID_CLIENT_EXTERN const_reverse_iterator rend() const; + + QPID_CLIENT_EXTERN bool empty() const; + QPID_CLIENT_EXTERN size_t size() const; + + QPID_CLIENT_EXTERN const_iterator find(const key_type&) const; + QPID_CLIENT_EXTERN const Variant& operator[](const key_type&) const; + + QPID_CLIENT_EXTERN const std::map<key_type, Variant>& asMap() const; + private: + MapViewImpl* impl; +}; + +QPID_CLIENT_EXTERN std::ostream& operator<<(std::ostream& out, const MapView& m); + +}} // namespace qpid::messaging + +#endif /*!QPID_MESSAGING_MAPVIEW_H*/ diff --git a/qpid/cpp/include/qpid/messaging/Message.h b/qpid/cpp/include/qpid/messaging/Message.h index e68d8a1141..4477d5a2e9 100644 --- a/qpid/cpp/include/qpid/messaging/Message.h +++ b/qpid/cpp/include/qpid/messaging/Message.h @@ -24,7 +24,6 @@ #include <string> #include "qpid/messaging/Variant.h" -#include "qpid/messaging/MessageContent.h" #include "qpid/client/ClientImportExport.h" namespace qpid { @@ -62,22 +61,11 @@ class Message 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&); + QPID_CLIENT_EXTERN const std::string& getContent() const; + QPID_CLIENT_EXTERN std::string& getContent(); + QPID_CLIENT_EXTERN void setContent(const std::string&); + QPID_CLIENT_EXTERN void setContent(const char* chars, size_t count); + QPID_CLIENT_EXTERN void getContent(std::pair<const char*, size_t>& content) const; private: MessageImpl* impl; diff --git a/qpid/cpp/include/qpid/messaging/MessageContent.h b/qpid/cpp/include/qpid/messaging/MessageContent.h deleted file mode 100644 index 7c3a636c07..0000000000 --- a/qpid/cpp/include/qpid/messaging/MessageContent.h +++ /dev/null @@ -1,90 +0,0 @@ -#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/sys/posix/PrivatePosix.h b/qpid/cpp/include/qpid/sys/posix/PrivatePosix.h index 6ffd3d8383..79cb950275 100644 --- a/qpid/cpp/include/qpid/sys/posix/PrivatePosix.h +++ b/qpid/cpp/include/qpid/sys/posix/PrivatePosix.h @@ -27,6 +27,7 @@ struct timespec; struct timeval; +struct addrinfo; namespace qpid { namespace sys { @@ -36,6 +37,10 @@ struct timespec& toTimespec(struct timespec& ts, const Duration& t); struct timeval& toTimeval(struct timeval& tv, const Duration& t); Duration toTime(const struct timespec& ts); +// Private SocketAddress details +class SocketAddress; +const struct addrinfo& getAddrInfo(const SocketAddress&); + // Private fd related implementation details class IOHandlePrivate { public: diff --git a/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h b/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h index 47b1d16a76..7b2c57ad8e 100755 --- a/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h +++ b/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h @@ -21,6 +21,8 @@ * */ +#include <BaseTsd.h> /* Windows system types */ + typedef unsigned char uint8_t; typedef char int8_t; typedef unsigned short uint16_t; @@ -32,7 +34,7 @@ typedef __int64 int64_t; // Visual Studio doesn't define other common types, so set them up here too. typedef int pid_t; -typedef int ssize_t; +typedef SSIZE_T ssize_t; typedef unsigned int uint; #endif /*!QPID_SYS_WINDOWS_INTEGERTYPES_H*/ diff --git a/qpid/cpp/managementgen/CMakeLists.txt b/qpid/cpp/managementgen/CMakeLists.txt index 8d053e3e08..2511b745a3 100644 --- a/qpid/cpp/managementgen/CMakeLists.txt +++ b/qpid/cpp/managementgen/CMakeLists.txt @@ -20,18 +20,7 @@ project(qpidc-qmfgen) cmake_minimum_required(VERSION 2.4.0 FATAL_ERROR) install(PROGRAMS qmf-gen DESTINATION managementgen - COMPONENT all-source) -install(FILES qmfgen/__init__.py - qmfgen/generate.py - qmfgen/schema.py - qmfgen/templates/Args.h - qmfgen/templates/Class.cpp - qmfgen/templates/Class.h - qmfgen/templates/Event.cpp - qmfgen/templates/Event.h - qmfgen/templates/Makefile.mk - qmfgen/templates/Package.cpp - qmfgen/templates/Package.h - qmfgen/management-types.xml - DESTINATION managementgen - COMPONENT all-source) + COMPONENT ${QPID_COMPONENT_QMF}) +install(DIRECTORY qmfgen DESTINATION managementgen + COMPONENT ${QPID_COMPONENT_QMF} + PATTERN ".svn" EXCLUDE PATTERN "*.pyc" EXCLUDE) diff --git a/qpid/cpp/packaging/NSIS/qpid-icon.ico b/qpid/cpp/packaging/NSIS/qpid-icon.ico Binary files differnew file mode 100644 index 0000000000..112f5d8f1f --- /dev/null +++ b/qpid/cpp/packaging/NSIS/qpid-icon.ico diff --git a/qpid/cpp/packaging/NSIS/qpid-icon.png b/qpid/cpp/packaging/NSIS/qpid-icon.png Binary files differnew file mode 100644 index 0000000000..d9bcc5657f --- /dev/null +++ b/qpid/cpp/packaging/NSIS/qpid-icon.png diff --git a/qpid/cpp/packaging/NSIS/qpid-install-banner.bmp b/qpid/cpp/packaging/NSIS/qpid-install-banner.bmp Binary files differnew file mode 100644 index 0000000000..1dac04c685 --- /dev/null +++ b/qpid/cpp/packaging/NSIS/qpid-install-banner.bmp diff --git a/qpid/cpp/packaging/NSIS/qpid-install-banner.png b/qpid/cpp/packaging/NSIS/qpid-install-banner.png Binary files differnew file mode 100644 index 0000000000..be70d02ee6 --- /dev/null +++ b/qpid/cpp/packaging/NSIS/qpid-install-banner.png diff --git a/qpid/cpp/rubygen/framing.0-10/structs.rb b/qpid/cpp/rubygen/framing.0-10/structs.rb index 809e453381..c3684aea66 100755 --- a/qpid/cpp/rubygen/framing.0-10/structs.rb +++ b/qpid/cpp/rubygen/framing.0-10/structs.rb @@ -381,9 +381,10 @@ EOS else inheritance = ": public AMQMethodBody" end + else + public_api("qpid/framing/#{classname}.h") # Non-method structs are public end - public_api("qpid/framing/#{classname}.h") h_file("qpid/framing/#{classname}.h") { if (s.kind_of? AmqpMethod) gen <<EOS diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt index 786facced9..6deacbbece 100644 --- a/qpid/cpp/src/CMakeLists.txt +++ b/qpid/cpp/src/CMakeLists.txt @@ -118,19 +118,6 @@ if (ENABLE_VALGRIND AND NOT VALGRIND) message(STATUS "Can't locate the valgrind command; no run-time error detection") endif (ENABLE_VALGRIND AND NOT VALGRIND) -set(QPIDC_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib CACHE STRING - "Directory to install library files") -set(QPIDC_INSTALL_CONFDIR ${CMAKE_INSTALL_PREFIX}/etc CACHE STRING - "Directory to install configuration files") -set(QPIDC_MODULE_DIR ${QPIDC_INSTALL_LIBDIR}/qpid/client CACHE STRING - "Directory to load client plug-in modules from") -set(QPIDD_MODULE_DIR ${QPIDC_INSTALL_LIBDIR}/qpid/daemon CACHE STRING - "Directory to load broker plug-in modules from") -set(QPIDC_CONF_FILE ${QPIDC_INSTALL_CONFDIR}/qpid/qpidc.conf CACHE STRING - "Name of the Qpid client configuration file") -set(QPIDD_CONF_FILE ${QPIDC_INSTALL_CONFDIR}/qpid/qpidd.conf CACHE STRING - "Name of the Qpid broker configuration file") - option(ENABLE_WARNINGS "Enable lots of compiler warnings (recommended)" ON) if (ENABLE_WARNINGS AND CMAKE_COMPILER_IS_GNUCXX) # Warnings: Enable as many as possible, keep the code clean. Please @@ -272,6 +259,9 @@ if (BUILD_XML) PREFIX "" LINK_FLAGS -Wl,--no-undefined) endif (CMAKE_COMPILER_IS_GNUCXX) + install (TARGETS xml RUNTIME + DESTINATION ${QPIDD_MODULE_DIR} + COMPONENT ${QPID_COMPONENT_BROKER}) set(xml_tests XmlClientSessionTest) @@ -301,6 +291,9 @@ if (BUILD_ACL) PREFIX "" LINK_FLAGS -Wl,--no-undefined) endif (CMAKE_COMPILER_IS_GNUCXX) + install (TARGETS acl + DESTINATION ${QPIDD_MODULE_DIR} + COMPONENT ${QPID_COMPONENT_BROKER}) endif (BUILD_ACL) # Check for optional cluster support requirements @@ -329,7 +322,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows) ) endif (MSVC) - set (libqpidcommon_platform_SOURCES + set (qpidcommon_platform_SOURCES qpid/log/windows/SinkOptions.cpp qpid/sys/windows/AsynchIO.cpp qpid/sys/windows/FileSysDir.cpp @@ -346,15 +339,22 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows) qpid/sys/windows/Time.cpp qpid/sys/windows/uuid.cpp ) - set (libqpidcommon_platform_LIBS + set (qpidcommon_platform_LIBS rpcrt4 ws2_32 ) - set (libqpidbroker_platform_SOURCES + set (qpidcommon_platform_INSTALL_HEADERS + ../include/qpid/sys/windows/Condition.h + ../include/qpid/sys/windows/IntegerTypes.h + ../include/qpid/sys/windows/Mutex.h + ../include/qpid/sys/windows/Time.h + ../include/qpid/sys/windows/check.h + ) + set (qpidbroker_platform_SOURCES qpid/broker/windows/BrokerDefaults.cpp qpid/broker/windows/SaslAuthenticator.cpp ) - set (libqpidclient_platform_SOURCES + set (qpidclient_platform_SOURCES qpid/client/windows/SaslFactory.cpp ) @@ -375,7 +375,7 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows) set (qpid_poller_module qpid/sys/solaris/ECFPoller.cpp) endif (CMAKE_SYSTEM_NAME STREQUAL SunOS) - set (libqpidcommon_platform_SOURCES + set (qpidcommon_platform_SOURCES qpid/sys/posix/AsynchIO.cpp qpid/sys/posix/Fork.cpp qpid/sys/posix/FileSysDir.cpp @@ -394,14 +394,22 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows) ${qpid_poller_module} ) - set (libqpidcommon_platform_LIBS + set (qpidcommon_platform_LIBS ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} uuid ${CMAKE_DL_LIBS} ) + set (qpidcommon_platform_INSTALL_HEADERS + ../include/qpid/sys/posix/Condition.h + ../include/qpid/sys/posix/IntegerTypes.h + ../include/qpid/sys/posix/Mutex.h + ../include/qpid/sys/posix/PrivatePosix.h + ../include/qpid/sys/posix/Time.h + ../include/qpid/sys/posix/check.h + ) - set (libqpidbroker_platform_SOURCES + set (qpidbroker_platform_SOURCES qpid/broker/Daemon.cpp qpid/broker/SaslAuthenticator.cpp qpid/broker/SignalHandler.h @@ -409,7 +417,7 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows) qpid/broker/posix/BrokerDefaults.cpp ) - set (libqpidclient_platform_SOURCES + set (qpidclient_platform_SOURCES qpid/client/SaslFactory.cpp ) @@ -418,9 +426,9 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows) ) endif (CMAKE_SYSTEM_NAME STREQUAL Windows) -set (libqpidcommon_SOURCES +set (qpidcommon_SOURCES ${rgen_framing_srcs} - ${libqpidcommon_platform_SOURCES} + ${qpidcommon_platform_SOURCES} ${qpidcommon_sasl_source} qpid/assert.cpp qpid/Address.cpp @@ -476,19 +484,23 @@ set (libqpidcommon_SOURCES qpid/sys/Shlib.cpp qpid/sys/Timer.cpp ) -add_library (qpidcommon SHARED ${libqpidcommon_SOURCES}) + +add_library (qpidcommon SHARED ${qpidcommon_SOURCES}) if (CLOCK_GETTIME_IN_RT) - set (libqpidcommon_platform_LIBS ${libqpidcommon_platform_LIBS} rt) + set (qpidcommon_platform_LIBS ${qpidcommon_platform_LIBS} rt) endif (CLOCK_GETTIME_IN_RT) target_link_libraries (qpidcommon - ${libqpidcommon_platform_LIBS} + ${qpidcommon_platform_LIBS} ${qpidcommon_sasl_lib}) set_target_properties (qpidcommon PROPERTIES VERSION ${qpidc_version}) +install (TARGETS qpidcommon + DESTINATION ${QPID_INSTALL_LIBDIR} + COMPONENT ${QPID_COMPONENT_COMMON}) -set (libqpidclient_SOURCES +set (qpidclient_SOURCES ${rgen_client_srcs} - ${libqpidclient_platform_SOURCES} + ${qpidclient_platform_SOURCES} qpid/client/Bounds.cpp qpid/client/Completion.cpp qpid/client/Connection.cpp @@ -527,6 +539,10 @@ set (libqpidclient_SOURCES qpid/messaging/Connection.cpp qpid/messaging/ConnectionImpl.h qpid/messaging/Filter.cpp + qpid/messaging/ListContent.cpp + qpid/messaging/ListView.cpp + qpid/messaging/MapContent.cpp + qpid/messaging/MapView.cpp qpid/messaging/Message.cpp qpid/messaging/MessageImpl.h qpid/messaging/MessageImpl.cpp @@ -558,13 +574,100 @@ set (libqpidclient_SOURCES qpid/client/amqp0_10/SenderImpl.h qpid/client/amqp0_10/SenderImpl.cpp ) -add_library (qpidclient SHARED ${libqpidclient_SOURCES}) +set (qpidclient_INSTALL_HEADERS + ../include/qpid/Address.h + ../include/qpid/CommonImportExport.h + ../include/qpid/Exception.h + ../include/qpid/InlineAllocator.h + ../include/qpid/InlineVector.h + ../include/qpid/Msg.h + ../include/qpid/Options.h + ../include/qpid/RangeSet.h + ../include/qpid/SessionId.h + ../include/qpid/Url.h + ../include/qpid/client/AsyncSession.h + ../include/qpid/client/ClientImportExport.h + ../include/qpid/client/Completion.h + ../include/qpid/client/Connection.h + ../include/qpid/client/ConnectionSettings.h + ../include/qpid/client/FailoverManager.h + ../include/qpid/client/FlowControl.h + ../include/qpid/client/Future.h + ../include/qpid/client/FutureCompletion.h + ../include/qpid/client/FutureResult.h + ../include/qpid/client/Handle.h + ../include/qpid/client/LocalQueue.h + ../include/qpid/client/Message.h + ../include/qpid/client/MessageListener.h + ../include/qpid/client/MessageReplayTracker.h + ../include/qpid/client/QueueOptions.h + ../include/qpid/client/Session.h + ../include/qpid/client/SessionBase_0_10.h + ../include/qpid/client/Subscription.h + ../include/qpid/client/SubscriptionManager.h + ../include/qpid/client/SubscriptionSettings.h + ../include/qpid/client/TypedResult.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/qpid/framing/ProtocolVersion.h + ../include/qpid/framing/SequenceNumber.h + ../include/qpid/framing/SequenceSet.h + ../include/qpid/framing/StructHelper.h + ../include/qpid/framing/Uuid.h + ../include/qpid/framing/amqp_types.h + ../include/qpid/framing/amqp_types_full.h + ../include/qpid/log/Logger.h + ../include/qpid/log/Options.h + ../include/qpid/log/Selector.h + ../include/qpid/log/SinkOptions.h + ../include/qpid/log/Statement.h + ../include/qpid/management/Args.h + ../include/qpid/management/Manageable.h + ../include/qpid/management/ManagementEvent.h + ../include/qpid/management/ManagementObject.h + ../include/qpid/sys/Condition.h + ../include/qpid/sys/IOHandle.h + ../include/qpid/sys/IntegerTypes.h + ../include/qpid/sys/Monitor.h + ../include/qpid/sys/Mutex.h + ../include/qpid/sys/Runnable.h + ../include/qpid/sys/StrError.h + ../include/qpid/sys/SystemInfo.h + ../include/qpid/sys/Thread.h + ../include/qpid/sys/Time.h + ../include/qpid/messaging/Address.h + ../include/qpid/messaging/Connection.h + ../include/qpid/messaging/Codec.h + ../include/qpid/messaging/Filter.h + ../include/qpid/messaging/ListContent.h + ../include/qpid/messaging/ListView.h + ../include/qpid/messaging/MapContent.h + ../include/qpid/messaging/MapView.h + ../include/qpid/messaging/Message.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 +) + +add_library (qpidclient SHARED ${qpidclient_SOURCES}) target_link_libraries (qpidclient qpidcommon) set_target_properties (qpidclient PROPERTIES VERSION ${qpidc_version}) - -set (libqpidbroker_SOURCES +install (TARGETS qpidclient + DESTINATION ${QPID_INSTALL_LIBDIR} + COMPONENT ${QPID_COMPONENT_CLIENT}) +install (DIRECTORY ../include/qpid DESTINATION ${QPID_INSTALL_INCLUDEDIR} + COMPONENT ${QPID_COMPONENT_CLIENT_INCLUDE} + PATTERN ".svn" EXCLUDE) + +set (qpidbroker_SOURCES ${mgen_broker_cpp} - ${libqpidbroker_platform_SOURCES} + ${qpidbroker_platform_SOURCES} qpid/amqp_0_10/Connection.h qpid/amqp_0_10/Connection.cpp qpid/broker/Broker.cpp @@ -629,12 +732,15 @@ set (libqpidbroker_SOURCES qpid/management/ManagementExchange.cpp qpid/sys/TCPIOPlugin.cpp ) -add_library (qpidbroker SHARED ${libqpidbroker_SOURCES}) +add_library (qpidbroker SHARED ${qpidbroker_SOURCES}) target_link_libraries (qpidbroker qpidcommon) set_target_properties (qpidbroker PROPERTIES VERSION ${qpidc_version}) if (MSVC) set_target_properties (qpidbroker PROPERTIES COMPILE_FLAGS /wd4290) endif (MSVC) +install (TARGETS qpidbroker LIBRARY + DESTINATION ${QPID_INSTALL_LIBDIR} + COMPONENT ${QPID_COMPONENT_BROKER}) set (qpidd_SOURCES ${qpidd_platform_SOURCES} @@ -644,53 +750,65 @@ set (qpidd_SOURCES add_executable (qpidd ${qpidd_SOURCES}) target_link_libraries (qpidd qpidbroker qpidcommon ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}) +install (TARGETS qpidd RUNTIME + DESTINATION ${QPID_INSTALL_BINDIR} + COMPONENT ${QPID_COMPONENT_BROKER}) -# QMF agent library -#module_hdr += \ -# qpid/agent/ManagementAgent.h \ -# qpid/agent/ManagementAgentImpl.h -set (qmfagent_SOURCES - qmf/AgentEngine.cpp - qmf/AgentEngine.h +# QMF library +# Library Version Information (CURRENT.REVISION.AGE): +# +# CURRENT => API/ABI version. Bump this if the interface changes +# REVISION => Version of underlying implementation. +# Bump if implementation changes but API/ABI doesn't +# AGE => Number of API/ABI versions this is backward compatible with +set (qmf_version 1.0.0) +set (qmfengine_version 1.0.0) + +set (qmf_SOURCES qpid/agent/ManagementAgentImpl.cpp qpid/agent/ManagementAgentImpl.h ) -add_library (qmfagent SHARED ${qmfagent_SOURCES}) -target_link_libraries (qmfagent qmfcommon) -set_target_properties (qmfagent PROPERTIES - VERSION ${qpidc_version}) - -set (qmfcommon_SOURCES - qmf/ConnectionSettingsImpl.cpp - qmf/ConnectionSettingsImpl.h - qmf/ConsoleEngine.h - qmf/Event.h - qmf/Message.h - qmf/MessageImpl.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 (qmf SHARED ${qmf_SOURCES}) +target_link_libraries (qmf qmfengine) +set_target_properties (qmf PROPERTIES + VERSION ${qmf_version}) +install (TARGETS qmf LIBRARY + DESTINATION ${QPID_INSTALL_LIBDIR} + COMPONENT ${QPID_COMPONENT_QMF}) + +set (qmfengine_SOURCES + qmf/engine/Agent.cpp + qmf/engine/BrokerProxyImpl.cpp + qmf/engine/BrokerProxyImpl.h + qmf/engine/ConnectionSettingsImpl.cpp + qmf/engine/ConnectionSettingsImpl.h + qmf/engine/ConsoleImpl.cpp + qmf/engine/ConsoleImpl.h + qmf/engine/MessageImpl.cpp + qmf/engine/MessageImpl.h + qmf/engine/ObjectIdImpl.cpp + qmf/engine/ObjectIdImpl.h + qmf/engine/ObjectImpl.cpp + qmf/engine/ObjectImpl.h + qmf/engine/Protocol.cpp + qmf/engine/Protocol.h + qmf/engine/QueryImpl.cpp + qmf/engine/QueryImpl.h + qmf/engine/ResilientConnection.cpp + qmf/engine/SequenceManager.cpp + qmf/engine/SequenceManager.h + qmf/engine/SchemaImpl.cpp + qmf/engine/SchemaImpl.h + qmf/engine/ValueImpl.cpp + qmf/engine/ValueImpl.h ) -add_library (qmfcommon SHARED ${qmfcommon_SOURCES}) -target_link_libraries (qmfcommon qpidclient) -set_target_properties (qmfcommon PROPERTIES - VERSION ${qpidc_version}) +add_library (qmfengine SHARED ${qmfengine_SOURCES}) +target_link_libraries (qmfengine qpidclient) +set_target_properties (qmfengine PROPERTIES + VERSION ${qmfengine_version}) +install (TARGETS qmfengine + DESTINATION ${QPID_INSTALL_LIBDIR} + COMPONENT ${QPID_COMPONENT_QMF}) # QMF console library #module_hdr += \ @@ -737,6 +855,9 @@ add_library (qmfconsole SHARED ${qmfconsole_SOURCES}) target_link_libraries (qmfconsole qpidclient) set_target_properties (qmfconsole PROPERTIES VERSION ${qpidc_version}) +install (TARGETS qmfconsole + DESTINATION ${QPID_INSTALL_LIBDIR} + COMPONENT ${QPID_COMPONENT_QMF}) # A queue event listener plugin that creates messages on a replication # queue corresponding to enqueue and dequeue events: @@ -752,6 +873,9 @@ if (CMAKE_COMPILER_IS_GNUCXX) set_target_properties(replicating_listener PROPERTIES LINK_FLAGS -Wl,--no-undefined) endif (CMAKE_COMPILER_IS_GNUCXX) +install (TARGETS replicating_listener + DESTINATION ${QPIDD_MODULE_DIR} + COMPONENT ${QPID_COMPONENT_BROKER}) # A custom exchange plugin that allows an exchange to be created that # can process the messages from a replication queue (populated on the @@ -769,6 +893,9 @@ if (CMAKE_COMPILER_IS_GNUCXX) set_target_properties(replicating_exchange PROPERTIES LINK_FLAGS -Wl,--no-undefined) endif (CMAKE_COMPILER_IS_GNUCXX) +install (TARGETS replicating_exchange + DESTINATION ${QPIDD_MODULE_DIR} + COMPONENT ${QPID_COMPONENT_BROKER}) # This is only really needed until all the trunk builds (Linux, UNIX, Windows) # are all on cmake only. This is because cmake builds always have a config.h diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am index 4988f3f031..a6b90d7bde 100644 --- a/qpid/cpp/src/Makefile.am +++ b/qpid/cpp/src/Makefile.am @@ -144,6 +144,7 @@ libqpidcommon_la_SOURCES += \ qpid/log/posix/SinkOptions.cpp \ qpid/sys/posix/IOHandle.cpp \ qpid/sys/posix/Socket.cpp \ + qpid/sys/posix/SocketAddress.cpp \ qpid/sys/posix/AsynchIO.cpp \ qpid/sys/posix/FileSysDir.cpp \ qpid/sys/posix/LockFile.cpp \ @@ -456,6 +457,7 @@ libqpidcommon_la_SOURCES += \ qpid/sys/Shlib.h \ qpid/sys/ShutdownHandler.h \ qpid/sys/Socket.h \ + qpid/sys/SocketAddress.h \ qpid/sys/StateMonitor.h \ qpid/sys/TimeoutHandler.h \ qpid/sys/Timer.cpp \ @@ -686,6 +688,10 @@ libqpidclient_la_SOURCES = \ qpid/messaging/Address.cpp \ qpid/messaging/Connection.cpp \ qpid/messaging/Filter.cpp \ + qpid/messaging/ListContent.cpp \ + qpid/messaging/ListView.cpp \ + qpid/messaging/MapContent.cpp \ + qpid/messaging/MapView.cpp \ qpid/messaging/Message.cpp \ qpid/messaging/MessageImpl.h \ qpid/messaging/MessageImpl.cpp \ @@ -790,8 +796,11 @@ nobase_include_HEADERS += \ ../include/qpid/messaging/Connection.h \ ../include/qpid/messaging/Codec.h \ ../include/qpid/messaging/Filter.h \ + ../include/qpid/messaging/ListContent.h \ + ../include/qpid/messaging/ListView.h \ + ../include/qpid/messaging/MapContent.h \ + ../include/qpid/messaging/MapView.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 \ diff --git a/qpid/cpp/src/cluster.mk b/qpid/cpp/src/cluster.mk index d90a06e1e2..1a8812d169 100644 --- a/qpid/cpp/src/cluster.mk +++ b/qpid/cpp/src/cluster.mk @@ -82,8 +82,7 @@ cluster_la_SOURCES = \ qpid/cluster/PollerDispatch.h \ qpid/cluster/ProxyInputHandler.h \ qpid/cluster/Quorum.h \ - qpid/cluster/types.h \ - qpid/sys/LatencyTracker.h + qpid/cluster/types.h cluster_la_LIBADD= -lcpg $(libcman) libqpidbroker.la libqpidclient.la cluster_la_CXXFLAGS = $(AM_CXXFLAGS) -fno-strict-aliasing diff --git a/qpid/cpp/src/qmf.mk b/qpid/cpp/src/qmf.mk index 54110ebaf7..2d034cf7c4 100644 --- a/qpid/cpp/src/qmf.mk +++ b/qpid/cpp/src/qmf.mk @@ -20,12 +20,14 @@ # # qmf library makefile fragment, to be included in Makefile.am # -lib_LTLIBRARIES += \ - libqmfcommon.la \ - libqmfagent.la +lib_LTLIBRARIES += \ + libqmf.la \ + libqmfengine.la -# Public header files -nobase_include_HEADERS += \ +# +# Public headers for the QMF API +# +QMF_API = \ ../include/qpid/agent/ManagementAgent.h \ ../include/qpid/agent/QmfAgentImportExport.h \ ../include/qmf/Agent.h \ @@ -34,42 +36,78 @@ nobase_include_HEADERS += \ ../include/qmf/ConnectionSettings.h \ ../include/qmf/AgentObject.h -libqmfcommon_la_SOURCES = \ - qmf/ConnectionSettingsImpl.cpp \ - qmf/ConnectionSettingsImpl.h \ - qmf/ConsoleEngine.cpp \ - qmf/ConsoleEngine.h \ - qmf/Event.h \ - qmf/Message.h \ - qmf/MessageImpl.cpp \ - qmf/MessageImpl.h \ - qmf/Object.h \ - qmf/ObjectId.h \ - qmf/ObjectIdImpl.cpp \ - 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 \ - qmf/Typecode.h \ - qmf/Value.h \ - qmf/ValueImpl.cpp \ - qmf/ValueImpl.h +# +# Public headers for the QMF Engine API +# +QMF_ENGINE_API = \ + ../include/qmf/engine/Agent.h \ + ../include/qmf/engine/ConnectionSettings.h \ + ../include/qmf/engine/Console.h \ + ../include/qmf/engine/Event.h \ + ../include/qmf/engine/Message.h \ + ../include/qmf/engine/Object.h \ + ../include/qmf/engine/ObjectId.h \ + ../include/qmf/engine/QmfEngineImportExport.h \ + ../include/qmf/engine/Query.h \ + ../include/qmf/engine/ResilientConnection.h \ + ../include/qmf/engine/Schema.h \ + ../include/qmf/engine/Typecode.h \ + ../include/qmf/engine/Value.h + +# Public header files +nobase_include_HEADERS += \ + $(QMF_API) \ + $(QMF_ENGINE_API) -libqmfagent_la_SOURCES = \ - qmf/AgentEngine.cpp \ - qmf/AgentEngine.h \ - qpid/agent/ManagementAgentImpl.cpp \ +libqmf_la_SOURCES = \ + $(QMF_API) \ + qpid/agent/ManagementAgentImpl.cpp \ qpid/agent/ManagementAgentImpl.h -libqmfagent_la_LIBADD = libqpidclient.la libqmfcommon.la +libqmfengine_la_SOURCES = \ + $(QMF_ENGINE_API) \ + qmf/engine/Agent.cpp \ + qmf/engine/BrokerProxyImpl.cpp \ + qmf/engine/BrokerProxyImpl.h \ + qmf/engine/ConnectionSettingsImpl.cpp \ + qmf/engine/ConnectionSettingsImpl.h \ + qmf/engine/ConsoleImpl.cpp \ + qmf/engine/ConsoleImpl.h \ + qmf/engine/MessageImpl.cpp \ + qmf/engine/MessageImpl.h \ + qmf/engine/ObjectIdImpl.cpp \ + qmf/engine/ObjectIdImpl.h \ + qmf/engine/ObjectImpl.cpp \ + qmf/engine/ObjectImpl.h \ + qmf/engine/Protocol.cpp \ + qmf/engine/Protocol.h \ + qmf/engine/QueryImpl.cpp \ + qmf/engine/QueryImpl.h \ + qmf/engine/ResilientConnection.cpp \ + qmf/engine/SequenceManager.cpp \ + qmf/engine/SequenceManager.h \ + qmf/engine/SchemaImpl.cpp \ + qmf/engine/SchemaImpl.h \ + qmf/engine/ValueImpl.cpp \ + qmf/engine/ValueImpl.h + +libqmf_la_LIBADD = libqmfengine.la +libqmfengine_la_LIBADD = libqpidclient.la + +# Library Version Information: +# +# CURRENT => API/ABI version. Bump this if the interface changes +# REVISION => Version of underlying implementation. +# Bump if implementation changes but API/ABI doesn't +# AGE => Number of API/ABI versions this is backward compatible with +# +QMF_CURRENT = 1 +QMF_REVISION = 0 +QMF_AGE = 0 + +QMF_ENGINE_CURRENT = 1 +QMF_ENGINE_REVISION = 0 +QMF_ENGINE_AGE = 0 + +libqmf_la_LDFLAGS = -version-info $(QMF_CURRENT):$(QMF_REVISION):$(QMF_AGE) +libqmfengine_la_LDFLAGS = -version-info $(QMF_ENGINE_CURRENT):$(QMF_ENGINE_REVISION):$(QMF_ENGINE_AGE) diff --git a/qpid/cpp/src/qmf/ConsoleEngine.cpp b/qpid/cpp/src/qmf/ConsoleEngine.cpp deleted file mode 100644 index e7991328ee..0000000000 --- a/qpid/cpp/src/qmf/ConsoleEngine.cpp +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#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 <qpid/sys/SystemInfo.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() { delete envelope; } - uint32_t getStatus() const { return status; } - const Value* getException() const { return exception.get(); } - const Value* getArgs() const { return arguments.get(); } - }; - - struct QueryResponseImpl { - typedef boost::shared_ptr<QueryResponseImpl> Ptr; - QueryResponse *envelope; - uint32_t status; - auto_ptr<Value> exception; - vector<ObjectImpl::Ptr> results; - - QueryResponseImpl() : envelope(new QueryResponse(this)), status(0) {} - ~QueryResponseImpl() { delete envelope; } - uint32_t getStatus() const { return status; } - const Value* getException() const { return exception.get(); } - uint32_t getObjectCount() const { return results.size(); } - const Object* getObject(uint32_t idx) const; - }; - - 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; - void* context; - QueryResponseImpl::Ptr queryResponse; - - BrokerEventImpl(BrokerEvent::EventKind k) : kind(k) {} - ~BrokerEventImpl() {} - BrokerEvent copy(); - }; - - struct AgentProxyImpl { - typedef boost::shared_ptr<AgentProxyImpl> Ptr; - AgentProxy* envelope; - ConsoleEngineImpl* console; - BrokerProxyImpl* broker; - uint32_t agentBank; - string label; - - AgentProxyImpl(ConsoleEngineImpl* c, BrokerProxyImpl* b, uint32_t ab, const string& l) : - envelope(new AgentProxy(this)), console(c), broker(b), agentBank(ab), label(l) {} - ~AgentProxyImpl() {} - const string& getLabel() const { return label; } - }; - - class BrokerProxyImpl { - 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(); - - uint32_t agentCount() const; - const AgentProxy* getAgent(uint32_t idx) const; - void sendQuery(const Query& query, void* context, const AgentProxy* agent); - void sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxyImpl* agent); - - void addBinding(const string& exchange, const string& key); - void staticRelease() { decOutstanding(); } - - private: - friend class StaticContext; - friend class QueryContext; - mutable Mutex lock; - BrokerProxy* envelope; - ConsoleEngineImpl* console; - string queueName; - Uuid brokerId; - SequenceManager seqMgr; - uint32_t requestsOutstanding; - bool topicBound; - vector<AgentProxyImpl::Ptr> agentList; - 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(); - BrokerEventImpl::Ptr eventQueryComplete(void* context, QueryResponseImpl::Ptr response); - - 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); - ObjectImpl::Ptr handleObjectIndication(Buffer& inBuffer, uint32_t seq, bool prop, bool stat); - void incOutstandingLH(); - void decOutstanding(); - }; - - struct StaticContext : public SequenceContext { - StaticContext(BrokerProxyImpl& b) : broker(b) {} - ~StaticContext() {} - void reserve() {} - void release() { broker.staticRelease(); } - bool handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer); - BrokerProxyImpl& broker; - }; - - struct QueryContext : public SequenceContext { - QueryContext(BrokerProxyImpl& b, void* u) : - broker(b), userContext(u), requestsOutstanding(0), queryResponse(new QueryResponseImpl()) {} - ~QueryContext() {} - void reserve(); - void release(); - bool handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer); - - mutable Mutex lock; - BrokerProxyImpl& broker; - void* userContext; - uint32_t requestsOutstanding; - QueryResponseImpl::Ptr queryResponse; - }; - - 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); - - /* - 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; - SchemaObjectClassImpl::Ptr getSchema(const SchemaClassKeyImpl& key) const; - }; -} - -namespace { - const char* QMF_EXCHANGE = "qpid.management"; - const char* DIR_EXCHANGE = "amq.direct"; - const char* BROKER_KEY = "broker"; - const char* BROKER_PACKAGE = "org.apache.qpid.broker"; - const char* AGENT_CLASS = "agent"; - const char* BROKER_AGENT_KEY = "agent.1.0"; -} - -const Object* QueryResponseImpl::getObject(uint32_t idx) const -{ - vector<ObjectImpl::Ptr>::const_iterator iter = results.begin(); - - while (idx > 0) { - if (iter == results.end()) - return 0; - iter++; - idx--; - } - - return (*iter)->envelope; -} - -#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); - item.context = context; - item.queryResponse = queryResponse.get() ? queryResponse->envelope : 0; - - return item; -} - -BrokerProxyImpl::BrokerProxyImpl(BrokerProxy* e, ConsoleEngine& _console) : - envelope(e), console(_console.impl) -{ - stringstream qn; - qpid::TcpAddress addr; - - SystemInfo::getLocalHostname(addr); - qn << "qmfc-" << SystemInfo::getProcessName() << "-" << addr << "-" << SystemInfo::getProcessId(); - queueName = qn.str(); - - seqMgr.setUnsolicitedContext(SequenceContext::Ptr(new StaticContext(*this))); -} - -void BrokerProxyImpl::sessionOpened(SessionHandle& /*sh*/) -{ - Mutex::ScopedLock _lock(lock); - agentList.clear(); - 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); - agentList.clear(); - eventQueue.clear(); - xmtQueue.clear(); -} - -void BrokerProxyImpl::startProtocol() -{ - Mutex::ScopedLock _lock(lock); - char rawbuffer[512]; - Buffer buffer(rawbuffer, 512); - - agentList.push_back(AgentProxyImpl::Ptr(new AgentProxyImpl(console, this, 0, "Agent embedded in broker"))); - - requestsOutstanding = 1; - topicBound = false; - uint32_t sequence(seqMgr.reserve()); - Protocol::encodeHeader(buffer, Protocol::OP_BROKER_REQUEST, sequence); - sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY); - QPID_LOG(trace, "SENT BrokerRequest seq=" << sequence); -} - -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)) - seqMgr.dispatch(opcode, sequence, inBuffer); -} - -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(); -} - -uint32_t BrokerProxyImpl::agentCount() const -{ - Mutex::ScopedLock _lock(lock); - return agentList.size(); -} - -const AgentProxy* BrokerProxyImpl::getAgent(uint32_t idx) const -{ - Mutex::ScopedLock _lock(lock); - for (vector<AgentProxyImpl::Ptr>::const_iterator iter = agentList.begin(); - iter != agentList.end(); iter++) - if (idx-- == 0) - return (*iter)->envelope; - return 0; -} - -void BrokerProxyImpl::sendQuery(const Query& query, void* context, const AgentProxy* agent) -{ - SequenceContext::Ptr queryContext(new QueryContext(*this, context)); - Mutex::ScopedLock _lock(lock); - if (agent != 0) { - sendGetRequestLH(queryContext, query, agent->impl); - } else { - // TODO (optimization) only send queries to agents that have the requested class+package - for (vector<AgentProxyImpl::Ptr>::const_iterator iter = agentList.begin(); - iter != agentList.end(); iter++) { - sendGetRequestLH(queryContext, query, (*iter).get()); - } - } -} - -void BrokerProxyImpl::sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxyImpl* agent) -{ - stringstream key; - Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); - uint32_t sequence(seqMgr.reserve(queryContext)); - - Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence); - query.impl->encode(outBuffer); - key << "agent.1." << agent->agentBank; - sendBufferLH(outBuffer, QMF_EXCHANGE, key.str()); - QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << key.str()); -} - -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; -} - -BrokerEventImpl::Ptr BrokerProxyImpl::eventQueryComplete(void* context, QueryResponseImpl::Ptr response) -{ - BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::QUERY_COMPLETE)); - event->context = context; - event->queryResponse = response; - return event; -} - -void BrokerProxyImpl::handleBrokerResponse(Buffer& inBuffer, uint32_t seq) -{ - 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()); - incOutstandingLH(); - 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()); - 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); -} - -void BrokerProxyImpl::handleClassIndication(Buffer& inBuffer, uint32_t seq) -{ - uint8_t kind = inBuffer.getOctet(); - SchemaClassKeyImpl classKey(inBuffer); - - 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()); - 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()); - - // - // If we have just learned about the org.apache.qpid.broker:agent class, send a get - // request for the current list of agents so we can have it on-hand before we declare - // this session "stable". - // - if (key->getClassName() == AGENT_CLASS && key->getPackageName() == BROKER_PACKAGE) { - Mutex::ScopedLock _lock(lock); - incOutstandingLH(); - Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); - uint32_t sequence(seqMgr.reserve()); - Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence); - FieldTable ft; - ft.setString("_class", AGENT_CLASS); - ft.setString("_package", BROKER_PACKAGE); - ft.encode(outBuffer); - sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_AGENT_KEY); - QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << BROKER_AGENT_KEY); - } - } 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); - } -} - -ObjectImpl::Ptr BrokerProxyImpl::handleObjectIndication(Buffer& inBuffer, uint32_t seq, bool prop, bool stat) -{ - SchemaClassKeyImpl classKey(inBuffer); - QPID_LOG(trace, "RCVD ObjectIndication seq=" << seq << " key=" << classKey.str()); - - SchemaObjectClassImpl::Ptr schema = console->getSchema(classKey); - if (schema.get() == 0) { - QPID_LOG(trace, "No Schema Found for ObjectIndication. seq=" << seq << " key=" << classKey.str()); - return ObjectImpl::Ptr(); - } - - return ObjectImpl::Ptr(new ObjectImpl(schema->envelope, inBuffer, prop, stat, true)); -} - -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)); -} - -bool StaticContext::handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer) -{ - bool completeContext = false; - if (opcode == Protocol::OP_BROKER_RESPONSE) { - broker.handleBrokerResponse(buffer, sequence); - completeContext = true; - } - else if (opcode == Protocol::OP_COMMAND_COMPLETE) { - broker.handleCommandComplete(buffer, sequence); - completeContext = true; - } - else if (opcode == Protocol::OP_SCHEMA_RESPONSE) { - broker.handleSchemaResponse(buffer, sequence); - completeContext = true; - } - else if (opcode == Protocol::OP_PACKAGE_INDICATION) - broker.handlePackageIndication(buffer, sequence); - else if (opcode == Protocol::OP_CLASS_INDICATION) - broker.handleClassIndication(buffer, sequence); - else if (opcode == Protocol::OP_HEARTBEAT_INDICATION) - broker.handleHeartbeatIndication(buffer, sequence); - else if (opcode == Protocol::OP_EVENT_INDICATION) - broker.handleEventIndication(buffer, sequence); - else if (opcode == Protocol::OP_PROPERTY_INDICATION) - broker.handleObjectIndication(buffer, sequence, true, false); - else if (opcode == Protocol::OP_STATISTIC_INDICATION) - broker.handleObjectIndication(buffer, sequence, false, true); - else if (opcode == Protocol::OP_OBJECT_INDICATION) - broker.handleObjectIndication(buffer, sequence, true, true); - else { - QPID_LOG(trace, "StaticContext::handleMessage invalid opcode: " << opcode); - completeContext = true; - } - - return completeContext; -} - -void QueryContext::reserve() -{ - Mutex::ScopedLock _lock(lock); - requestsOutstanding++; -} - -void QueryContext::release() -{ - Mutex::ScopedLock _lock(lock); - if (--requestsOutstanding == 0) { - broker.eventQueue.push_back(broker.eventQueryComplete(userContext, queryResponse)); - } -} - -bool QueryContext::handleMessage(uint8_t opcode, uint32_t sequence, Buffer& buffer) -{ - bool completeContext = false; - ObjectImpl::Ptr object; - - if (opcode == Protocol::OP_COMMAND_COMPLETE) { - broker.handleCommandComplete(buffer, sequence); - completeContext = true; - } - else if (opcode == Protocol::OP_OBJECT_INDICATION) { - object = broker.handleObjectIndication(buffer, sequence, true, true); - if (object.get() != 0) - queryResponse->results.push_back(object); - } - else { - QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode); - completeContext = true; - } - - return completeContext; -} - -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()); -} - -/* -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(); -} - -SchemaObjectClassImpl::Ptr ConsoleEngineImpl::getSchema(const SchemaClassKeyImpl& key) const -{ - Mutex::ScopedLock _lock(lock); - PackageList::const_iterator pIter = packages.find(key.getPackageName()); - if (pIter == packages.end()) - return SchemaObjectClassImpl::Ptr(); - - const ObjectClassList& oList = pIter->second.first; - ObjectClassList::const_iterator iter = oList.find(&key); - if (iter == oList.end()) - return SchemaObjectClassImpl::Ptr(); - - return iter->second; -} - -//================================================================== -// Wrappers -//================================================================== - -AgentProxy::AgentProxy(AgentProxyImpl* i) : impl(i) {} -AgentProxy::~AgentProxy() { delete impl; } -const char* AgentProxy::getLabel() const { return impl->getLabel().c_str(); } - -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(); } -uint32_t BrokerProxy::agentCount() const { return impl->agentCount(); } -const AgentProxy* BrokerProxy::getAgent(uint32_t idx) const { return impl->getAgent(idx); } -void BrokerProxy::sendQuery(const Query& query, void* context, const AgentProxy* agent) { impl->sendQuery(query, context, agent); } - -MethodResponse::MethodResponse(MethodResponseImpl* i) : impl(i) {} -MethodResponse::~MethodResponse() {} -uint32_t MethodResponse::getStatus() const { return impl->getStatus(); } -const Value* MethodResponse::getException() const { return impl->getException(); } -const Value* MethodResponse::getArgs() const { return impl->getArgs(); } - -QueryResponse::QueryResponse(QueryResponseImpl* i) : impl(i) {} -QueryResponse::~QueryResponse() {} -uint32_t QueryResponse::getStatus() const { return impl->getStatus(); } -const Value* QueryResponse::getException() const { return impl->getException(); } -uint32_t QueryResponse::getObjectCount() const { return impl->getObjectCount(); } -const Object* QueryResponse::getObject(uint32_t idx) const { return impl->getObject(idx); } - -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); } -//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/AgentEngine.cpp b/qpid/cpp/src/qmf/engine/Agent.cpp index 9ea3be5907..c5d1bff2e0 100644 --- a/qpid/cpp/src/qmf/AgentEngine.cpp +++ b/qpid/cpp/src/qmf/engine/Agent.cpp @@ -17,15 +17,15 @@ * under the License. */ -#include "qmf/AgentEngine.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/engine/Agent.h" +#include "qmf/engine/MessageImpl.h" +#include "qmf/engine/SchemaImpl.h" +#include "qmf/engine/Typecode.h" +#include "qmf/engine/ObjectImpl.h" +#include "qmf/engine/ObjectIdImpl.h" +#include "qmf/engine/QueryImpl.h" +#include "qmf/engine/ValueImpl.h" +#include "qmf/engine/Protocol.h" #include <qpid/framing/Buffer.h> #include <qpid/framing/Uuid.h> #include <qpid/framing/FieldTable.h> @@ -40,13 +40,15 @@ #include <iostream> #include <fstream> #include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> using namespace std; -using namespace qmf; +using namespace qmf::engine; using namespace qpid::framing; using namespace qpid::sys; namespace qmf { +namespace engine { struct AgentEventImpl { typedef boost::shared_ptr<AgentEventImpl> Ptr; @@ -61,7 +63,7 @@ namespace qmf { boost::shared_ptr<Value> arguments; string exchange; string bindingKey; - SchemaObjectClass* objectClass; + const SchemaObjectClass* objectClass; AgentEventImpl(AgentEvent::EventKind k) : kind(k), sequence(0), object(0), objectClass(0) {} @@ -74,14 +76,14 @@ namespace qmf { uint32_t sequence; string exchange; string key; - SchemaMethodImpl* schemaMethod; + const SchemaMethod* schemaMethod; AgentQueryContext() : schemaMethod(0) {} }; - class AgentEngineImpl { + class AgentImpl : public boost::noncopyable { public: - AgentEngineImpl(char* label, bool internalStore); - ~AgentEngineImpl(); + AgentImpl(char* label, bool internalStore); + ~AgentImpl(); void setStoreDir(const char* path); void setTransferDir(const char* path); @@ -163,8 +165,8 @@ namespace qmf { } }; - typedef map<AgentClassKey, SchemaObjectClassImpl*, AgentClassKeyComp> ObjectClassMap; - typedef map<AgentClassKey, SchemaEventClassImpl*, AgentClassKeyComp> EventClassMap; + typedef map<AgentClassKey, SchemaObjectClass*, AgentClassKeyComp> ObjectClassMap; + typedef map<AgentClassKey, SchemaEventClass*, AgentClassKeyComp> EventClassMap; struct ClassMaps { ObjectClassMap objectClasses; @@ -180,7 +182,7 @@ namespace qmf { boost::shared_ptr<ObjectId> oid); AgentEventImpl::Ptr eventMethod(uint32_t num, const string& userId, const string& method, boost::shared_ptr<ObjectId> oid, boost::shared_ptr<Value> argMap, - SchemaObjectClass* objectClass); + const SchemaObjectClass* objectClass); void sendBufferLH(Buffer& buf, const string& destination, const string& routingKey); void sendPackageIndicationLH(const string& packageName); @@ -198,10 +200,11 @@ namespace qmf { void handleConsoleAddedIndication(); }; } +} -const char* AgentEngineImpl::QMF_EXCHANGE = "qpid.management"; -const char* AgentEngineImpl::DIR_EXCHANGE = "amq.direct"; -const char* AgentEngineImpl::BROKER_KEY = "broker"; +const char* AgentImpl::QMF_EXCHANGE = "qpid.management"; +const char* AgentImpl::DIR_EXCHANGE = "amq.direct"; +const char* AgentImpl::BROKER_KEY = "broker"; #define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());} @@ -227,7 +230,7 @@ AgentEvent AgentEventImpl::copy() return item; } -AgentEngineImpl::AgentEngineImpl(char* _label, bool i) : +AgentImpl::AgentImpl(char* _label, bool i) : label(_label), queueName("qmfa-"), internalStore(i), nextTransientId(1), requestedBrokerBank(0), requestedAgentBank(0), assignedBrokerBank(0), assignedAgentBank(0), @@ -236,11 +239,11 @@ AgentEngineImpl::AgentEngineImpl(char* _label, bool i) : queueName += label; } -AgentEngineImpl::~AgentEngineImpl() +AgentImpl::~AgentImpl() { } -void AgentEngineImpl::setStoreDir(const char* path) +void AgentImpl::setStoreDir(const char* path) { Mutex::ScopedLock _lock(lock); if (path) @@ -249,7 +252,7 @@ void AgentEngineImpl::setStoreDir(const char* path) storeDir.clear(); } -void AgentEngineImpl::setTransferDir(const char* path) +void AgentImpl::setTransferDir(const char* path) { Mutex::ScopedLock _lock(lock); if (path) @@ -258,7 +261,7 @@ void AgentEngineImpl::setTransferDir(const char* path) transferDir.clear(); } -void AgentEngineImpl::handleRcvMessage(Message& message) +void AgentImpl::handleRcvMessage(Message& message) { Buffer inBuffer(message.body, message.length); uint8_t opcode; @@ -274,13 +277,13 @@ void AgentEngineImpl::handleRcvMessage(Message& message) 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); + QPID_LOG(error, "AgentImpl::handleRcvMessage invalid opcode=" << opcode); break; } } } -bool AgentEngineImpl::getXmtMessage(Message& item) const +bool AgentImpl::getXmtMessage(Message& item) const { Mutex::ScopedLock _lock(lock); if (xmtQueue.empty()) @@ -289,14 +292,14 @@ bool AgentEngineImpl::getXmtMessage(Message& item) const return true; } -void AgentEngineImpl::popXmt() +void AgentImpl::popXmt() { Mutex::ScopedLock _lock(lock); if (!xmtQueue.empty()) xmtQueue.pop_front(); } -bool AgentEngineImpl::getEvent(AgentEvent& event) const +bool AgentImpl::getEvent(AgentEvent& event) const { Mutex::ScopedLock _lock(lock); if (eventQueue.empty()) @@ -305,14 +308,14 @@ bool AgentEngineImpl::getEvent(AgentEvent& event) const return true; } -void AgentEngineImpl::popEvent() +void AgentImpl::popEvent() { Mutex::ScopedLock _lock(lock); if (!eventQueue.empty()) eventQueue.pop_front(); } -void AgentEngineImpl::newSession() +void AgentImpl::newSession() { Mutex::ScopedLock _lock(lock); eventQueue.clear(); @@ -322,7 +325,7 @@ void AgentEngineImpl::newSession() eventQueue.push_back(eventSetupComplete()); } -void AgentEngineImpl::startProtocol() +void AgentImpl::startProtocol() { Mutex::ScopedLock _lock(lock); char rawbuffer[512]; @@ -338,7 +341,7 @@ void AgentEngineImpl::startProtocol() " reqAgent=" << requestedAgentBank); } -void AgentEngineImpl::heartbeat() +void AgentImpl::heartbeat() { Mutex::ScopedLock _lock(lock); Buffer buffer(outputBuffer, MA_BUFFER_SIZE); @@ -351,7 +354,7 @@ void AgentEngineImpl::heartbeat() QPID_LOG(trace, "SENT HeartbeatIndication"); } -void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* text, +void AgentImpl::methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& argMap) { Mutex::ScopedLock _lock(lock); @@ -366,15 +369,15 @@ void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* t buffer.putLong(status); buffer.putMediumString(text); if (status == 0) { - for (vector<SchemaArgumentImpl*>::const_iterator aIter = context->schemaMethod->arguments.begin(); - aIter != context->schemaMethod->arguments.end(); aIter++) { - const SchemaArgumentImpl* schemaArg = *aIter; - if (schemaArg->dir == DIR_OUT || schemaArg->dir == DIR_IN_OUT) { - if (argMap.keyInMap(schemaArg->name.c_str())) { - const Value* val = argMap.byKey(schemaArg->name.c_str()); + for (vector<const SchemaArgument*>::const_iterator aIter = context->schemaMethod->impl->arguments.begin(); + aIter != context->schemaMethod->impl->arguments.end(); aIter++) { + const SchemaArgument* schemaArg = *aIter; + if (schemaArg->getDirection() == DIR_OUT || schemaArg->getDirection() == DIR_IN_OUT) { + if (argMap.keyInMap(schemaArg->getName())) { + const Value* val = argMap.byKey(schemaArg->getName()); val->impl->encode(buffer); } else { - Value val(schemaArg->typecode); + Value val(schemaArg->getType()); val.impl->encode(buffer); } } @@ -384,7 +387,7 @@ void AgentEngineImpl::methodResponse(uint32_t sequence, uint32_t status, char* t QPID_LOG(trace, "SENT MethodResponse seq=" << context->sequence << " status=" << status << " text=" << text); } -void AgentEngineImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat) +void AgentImpl::queryResponse(uint32_t sequence, Object& object, bool prop, bool stat) { Mutex::ScopedLock _lock(lock); map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence); @@ -406,7 +409,7 @@ void AgentEngineImpl::queryResponse(uint32_t sequence, Object& object, bool prop QPID_LOG(trace, "SENT ContentIndication seq=" << context->sequence); } -void AgentEngineImpl::queryComplete(uint32_t sequence) +void AgentImpl::queryComplete(uint32_t sequence) { Mutex::ScopedLock _lock(lock); map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence); @@ -418,69 +421,67 @@ void AgentEngineImpl::queryComplete(uint32_t sequence) sendCommandCompleteLH(context->exchange, context->key, context->sequence, 0, "OK"); } -void AgentEngineImpl::registerClass(SchemaObjectClass* cls) +void AgentImpl::registerClass(SchemaObjectClass* cls) { Mutex::ScopedLock _lock(lock); - SchemaObjectClassImpl* impl = cls->impl; - map<string, ClassMaps>::iterator iter = packages.find(impl->package); + map<string, ClassMaps>::iterator iter = packages.find(cls->getClassKey()->getPackageName()); if (iter == packages.end()) { - packages[impl->package] = ClassMaps(); - iter = packages.find(impl->getClassKey()->getPackageName()); + packages[cls->getClassKey()->getPackageName()] = ClassMaps(); + iter = packages.find(cls->getClassKey()->getPackageName()); // TODO: Indicate this package if connected } - AgentClassKey key(impl->getClassKey()->getClassName(), impl->getClassKey()->getHash()); - iter->second.objectClasses[key] = impl; + AgentClassKey key(cls->getClassKey()->getClassName(), cls->getClassKey()->getHash()); + iter->second.objectClasses[key] = cls; // TODO: Indicate this schema if connected. } -void AgentEngineImpl::registerClass(SchemaEventClass* cls) +void AgentImpl::registerClass(SchemaEventClass* cls) { Mutex::ScopedLock _lock(lock); - SchemaEventClassImpl* impl = cls->impl; - map<string, ClassMaps>::iterator iter = packages.find(impl->package); + map<string, ClassMaps>::iterator iter = packages.find(cls->getClassKey()->getPackageName()); if (iter == packages.end()) { - packages[impl->package] = ClassMaps(); - iter = packages.find(impl->getClassKey()->getPackageName()); + packages[cls->getClassKey()->getPackageName()] = ClassMaps(); + iter = packages.find(cls->getClassKey()->getPackageName()); // TODO: Indicate this package if connected } - AgentClassKey key(impl->getClassKey()->getClassName(), impl->getClassKey()->getHash()); - iter->second.eventClasses[key] = impl; + AgentClassKey key(cls->getClassKey()->getClassName(), cls->getClassKey()->getHash()); + iter->second.eventClasses[key] = cls; // TODO: Indicate this schema if connected. } -const ObjectId* AgentEngineImpl::addObject(Object&, uint64_t) +const ObjectId* AgentImpl::addObject(Object&, uint64_t) { Mutex::ScopedLock _lock(lock); return 0; } -const ObjectId* AgentEngineImpl::allocObjectId(uint64_t persistId) +const ObjectId* AgentImpl::allocObjectId(uint64_t persistId) { Mutex::ScopedLock _lock(lock); uint16_t sequence = persistId ? 0 : bootSequence; uint64_t objectNum = persistId ? persistId : nextObjectId++; - ObjectIdImpl* oid = new ObjectIdImpl(&attachment, 0, sequence, objectNum); - return oid->envelope; + ObjectId* oid = ObjectIdImpl::factory(&attachment, 0, sequence, objectNum); + return oid; } -const ObjectId* AgentEngineImpl::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi) +const ObjectId* AgentImpl::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi) { return allocObjectId(((uint64_t) persistIdHi) << 32 | (uint64_t) persistIdLo); } -void AgentEngineImpl::raiseEvent(Event&) +void AgentImpl::raiseEvent(Event&) { Mutex::ScopedLock _lock(lock); } -AgentEventImpl::Ptr AgentEngineImpl::eventDeclareQueue(const string& name) +AgentEventImpl::Ptr AgentImpl::eventDeclareQueue(const string& name) { AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::DECLARE_QUEUE)); event->name = name; @@ -488,7 +489,7 @@ AgentEventImpl::Ptr AgentEngineImpl::eventDeclareQueue(const string& name) return event; } -AgentEventImpl::Ptr AgentEngineImpl::eventBind(const string& exchange, const string& queue, +AgentEventImpl::Ptr AgentImpl::eventBind(const string& exchange, const string& queue, const string& key) { AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::BIND)); @@ -499,13 +500,13 @@ AgentEventImpl::Ptr AgentEngineImpl::eventBind(const string& exchange, const str return event; } -AgentEventImpl::Ptr AgentEngineImpl::eventSetupComplete() +AgentEventImpl::Ptr AgentImpl::eventSetupComplete() { AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::SETUP_COMPLETE)); return event; } -AgentEventImpl::Ptr AgentEngineImpl::eventQuery(uint32_t num, const string& userId, const string& package, +AgentEventImpl::Ptr AgentImpl::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)); @@ -518,9 +519,9 @@ AgentEventImpl::Ptr AgentEngineImpl::eventQuery(uint32_t num, const string& user return event; } -AgentEventImpl::Ptr AgentEngineImpl::eventMethod(uint32_t num, const string& userId, const string& method, +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) + const SchemaObjectClass* objectClass) { AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::METHOD_CALL)); event->sequence = num; @@ -532,7 +533,7 @@ AgentEventImpl::Ptr AgentEngineImpl::eventMethod(uint32_t num, const string& use return event; } -void AgentEngineImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey) +void AgentImpl::sendBufferLH(Buffer& buf, const string& destination, const string& routingKey) { uint32_t length = buf.getPosition(); MessageImpl::Ptr message(new MessageImpl); @@ -547,7 +548,7 @@ void AgentEngineImpl::sendBufferLH(Buffer& buf, const string& destination, const xmtQueue.push_back(message); } -void AgentEngineImpl::sendPackageIndicationLH(const string& packageName) +void AgentImpl::sendPackageIndicationLH(const string& packageName) { Buffer buffer(outputBuffer, MA_BUFFER_SIZE); Protocol::encodeHeader(buffer, Protocol::OP_PACKAGE_INDICATION); @@ -556,7 +557,7 @@ void AgentEngineImpl::sendPackageIndicationLH(const string& packageName) QPID_LOG(trace, "SENT PackageIndication: package_name=" << packageName); } -void AgentEngineImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key) +void AgentImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key) { Buffer buffer(outputBuffer, MA_BUFFER_SIZE); Protocol::encodeHeader(buffer, Protocol::OP_CLASS_INDICATION); @@ -568,7 +569,7 @@ void AgentEngineImpl::sendClassIndicationLH(ClassKind kind, const string& packag QPID_LOG(trace, "SENT ClassIndication: package_name=" << packageName << " class_name=" << key.name); } -void AgentEngineImpl::sendCommandCompleteLH(const string& exchange, const string& replyToKey, +void AgentImpl::sendCommandCompleteLH(const string& exchange, const string& replyToKey, uint32_t sequence, uint32_t code, const string& text) { Buffer buffer(outputBuffer, MA_BUFFER_SIZE); @@ -579,7 +580,7 @@ void AgentEngineImpl::sendCommandCompleteLH(const string& exchange, const string QPID_LOG(trace, "SENT CommandComplete: seq=" << sequence << " code=" << code << " text=" << text); } -void AgentEngineImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text) +void AgentImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text) { Buffer buffer(outputBuffer, MA_BUFFER_SIZE); Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, sequence); @@ -605,7 +606,7 @@ void AgentEngineImpl::sendMethodErrorLH(uint32_t sequence, const string& key, ui QPID_LOG(trace, "SENT MethodResponse: errorCode=" << code << " text=" << fulltext); } -void AgentEngineImpl::handleAttachResponse(Buffer& inBuffer) +void AgentImpl::handleAttachResponse(Buffer& inBuffer) { Mutex::ScopedLock _lock(lock); @@ -652,17 +653,17 @@ void AgentEngineImpl::handleAttachResponse(Buffer& inBuffer) } } -void AgentEngineImpl::handlePackageRequest(Buffer&) +void AgentImpl::handlePackageRequest(Buffer&) { Mutex::ScopedLock _lock(lock); } -void AgentEngineImpl::handleClassQuery(Buffer&) +void AgentImpl::handleClassQuery(Buffer&) { Mutex::ScopedLock _lock(lock); } -void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, +void AgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, const string& replyExchange, const string& replyKey) { Mutex::ScopedLock _lock(lock); @@ -688,10 +689,10 @@ void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, ClassMaps cMap = pIter->second; ObjectClassMap::iterator ocIter = cMap.objectClasses.find(key); if (ocIter != cMap.objectClasses.end()) { - SchemaObjectClassImpl* oImpl = ocIter->second; + SchemaObjectClass* oImpl = ocIter->second; Buffer buffer(outputBuffer, MA_BUFFER_SIZE); Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence); - oImpl->encode(buffer); + oImpl->impl->encode(buffer); sendBufferLH(buffer, rExchange, rKey); QPID_LOG(trace, "SENT SchemaResponse: (object) package=" << packageName << " class=" << key.name); return; @@ -699,10 +700,10 @@ void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, EventClassMap::iterator ecIter = cMap.eventClasses.find(key); if (ecIter != cMap.eventClasses.end()) { - SchemaEventClassImpl* eImpl = ecIter->second; + SchemaEventClass* eImpl = ecIter->second; Buffer buffer(outputBuffer, MA_BUFFER_SIZE); Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence); - eImpl->encode(buffer); + eImpl->impl->encode(buffer); sendBufferLH(buffer, rExchange, rKey); QPID_LOG(trace, "SENT SchemaResponse: (event) package=" << packageName << " class=" << key.name); return; @@ -711,7 +712,7 @@ void AgentEngineImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, sendCommandCompleteLH(rExchange, rKey, sequence, 1, "class not found"); } -void AgentEngineImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId) +void AgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId) { Mutex::ScopedLock _lock(lock); FieldTable ft; @@ -763,13 +764,12 @@ void AgentEngineImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const eventQueue.push_back(eventQuery(contextNum, userId, pname, cname, oid)); } -void AgentEngineImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const string& replyTo, const string& userId) +void AgentImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const string& replyTo, const string& userId) { Mutex::ScopedLock _lock(lock); string pname; string method; - ObjectIdImpl* oidImpl = new ObjectIdImpl(buffer); - boost::shared_ptr<ObjectId> oid(oidImpl->envelope); + boost::shared_ptr<ObjectId> oid(ObjectIdImpl::factory(buffer)); buffer.getShortString(pname); AgentClassKey classKey(buffer); buffer.getShortString(method); @@ -788,29 +788,29 @@ void AgentEngineImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, con return; } - const SchemaObjectClassImpl* schema = cIter->second; - vector<SchemaMethodImpl*>::const_iterator mIter = schema->methods.begin(); - for (; mIter != schema->methods.end(); mIter++) { - if ((*mIter)->name == method) + const SchemaObjectClass* schema = cIter->second; + vector<const SchemaMethod*>::const_iterator mIter = schema->impl->methods.begin(); + for (; mIter != schema->impl->methods.end(); mIter++) { + if ((*mIter)->getName() == method) break; } - if (mIter == schema->methods.end()) { + if (mIter == schema->impl->methods.end()) { sendMethodErrorLH(sequence, replyTo, MERR_UNKNOWN_METHOD, method); return; } - SchemaMethodImpl* schemaMethod = *mIter; + const SchemaMethod* schemaMethod = *mIter; boost::shared_ptr<Value> argMap(new Value(TYPE_MAP)); - ValueImpl* value; - for (vector<SchemaArgumentImpl*>::const_iterator aIter = schemaMethod->arguments.begin(); - aIter != schemaMethod->arguments.end(); aIter++) { - const SchemaArgumentImpl* schemaArg = *aIter; - if (schemaArg->dir == DIR_IN || schemaArg->dir == DIR_IN_OUT) - value = new ValueImpl(schemaArg->typecode, buffer); + Value* value; + for (vector<const SchemaArgument*>::const_iterator aIter = schemaMethod->impl->arguments.begin(); + aIter != schemaMethod->impl->arguments.end(); aIter++) { + const SchemaArgument* schemaArg = *aIter; + if (schemaArg->getDirection() == DIR_IN || schemaArg->getDirection() == DIR_IN_OUT) + value = ValueImpl::factory(schemaArg->getType(), buffer); else - value = new ValueImpl(schemaArg->typecode); - argMap->insert(schemaArg->name.c_str(), value->envelope); + value = ValueImpl::factory(schemaArg->getType()); + argMap->insert(schemaArg->getName(), value); } AgentQueryContext::Ptr context(new AgentQueryContext); @@ -821,10 +821,10 @@ void AgentEngineImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, con context->schemaMethod = schemaMethod; contextMap[contextNum] = context; - eventQueue.push_back(eventMethod(contextNum, userId, method, oid, argMap, schema->envelope)); + eventQueue.push_back(eventMethod(contextNum, userId, method, oid, argMap, schema)); } -void AgentEngineImpl::handleConsoleAddedIndication() +void AgentImpl::handleConsoleAddedIndication() { Mutex::ScopedLock _lock(lock); } @@ -833,25 +833,25 @@ void AgentEngineImpl::handleConsoleAddedIndication() // Wrappers //================================================================== -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); } +Agent::Agent(char* label, bool internalStore) { impl = new AgentImpl(label, internalStore); } +Agent::~Agent() { delete impl; } +void Agent::setStoreDir(const char* path) { impl->setStoreDir(path); } +void Agent::setTransferDir(const char* path) { impl->setTransferDir(path); } +void Agent::handleRcvMessage(Message& message) { impl->handleRcvMessage(message); } +bool Agent::getXmtMessage(Message& item) const { return impl->getXmtMessage(item); } +void Agent::popXmt() { impl->popXmt(); } +bool Agent::getEvent(AgentEvent& event) const { 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); } diff --git a/qpid/cpp/src/qmf/engine/BrokerProxyImpl.cpp b/qpid/cpp/src/qmf/engine/BrokerProxyImpl.cpp new file mode 100644 index 0000000000..1a2b3e6555 --- /dev/null +++ b/qpid/cpp/src/qmf/engine/BrokerProxyImpl.cpp @@ -0,0 +1,763 @@ +/* + * 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/engine/BrokerProxyImpl.h" +#include "qmf/engine/ConsoleImpl.h" +#include "qmf/engine/Protocol.h" +#include "qpid/Address.h" +#include "qpid/sys/SystemInfo.h" +#include <qpid/log/Statement.h> +#include <qpid/StringUtils.h> +#include <string.h> +#include <iostream> +#include <fstream> + +using namespace std; +using namespace qmf::engine; +using namespace qpid::framing; +using namespace qpid::sys; + +namespace { + const char* QMF_EXCHANGE = "qpid.management"; + const char* DIR_EXCHANGE = "amq.direct"; + const char* BROKER_KEY = "broker"; + const char* BROKER_PACKAGE = "org.apache.qpid.broker"; + const char* AGENT_CLASS = "agent"; + const char* BROKER_AGENT_KEY = "agent.1.0"; +} + +const Object* QueryResponseImpl::getObject(uint32_t idx) const +{ + vector<ObjectPtr>::const_iterator iter = results.begin(); + + while (idx > 0) { + if (iter == results.end()) + return 0; + iter++; + idx--; + } + + return iter->get(); +} + +#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());} + +BrokerEvent BrokerEventImpl::copy() +{ + BrokerEvent item; + + ::memset(&item, 0, sizeof(BrokerEvent)); + item.kind = kind; + + STRING_REF(name); + STRING_REF(exchange); + STRING_REF(bindingKey); + item.context = context; + item.queryResponse = queryResponse.get(); + item.methodResponse = methodResponse.get(); + + return item; +} + +BrokerProxyImpl::BrokerProxyImpl(BrokerProxy& pub, Console& _console) : publicObject(pub), console(_console) +{ + stringstream qn; + qpid::TcpAddress addr; + + SystemInfo::getLocalHostname(addr); + qn << "qmfc-" << SystemInfo::getProcessName() << "-" << addr << "-" << SystemInfo::getProcessId(); + queueName = qn.str(); + + seqMgr.setUnsolicitedContext(SequenceContext::Ptr(new StaticContext(*this))); +} + +void BrokerProxyImpl::sessionOpened(SessionHandle& /*sh*/) +{ + Mutex::ScopedLock _lock(lock); + agentList.clear(); + 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); + agentList.clear(); + eventQueue.clear(); + xmtQueue.clear(); +} + +void BrokerProxyImpl::startProtocol() +{ + AgentProxyPtr agent(AgentProxyImpl::factory(console, publicObject, 0, "Agent embedded in broker")); + { + Mutex::ScopedLock _lock(lock); + char rawbuffer[512]; + Buffer buffer(rawbuffer, 512); + + agentList[0] = agent; + + requestsOutstanding = 1; + topicBound = false; + uint32_t sequence(seqMgr.reserve()); + Protocol::encodeHeader(buffer, Protocol::OP_BROKER_REQUEST, sequence); + sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY); + QPID_LOG(trace, "SENT BrokerRequest seq=" << sequence); + } + + console.impl->eventAgentAdded(agent); +} + +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)) + seqMgr.dispatch(opcode, sequence, message.routingKey ? string(message.routingKey) : string(), inBuffer); +} + +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(); +} + +uint32_t BrokerProxyImpl::agentCount() const +{ + Mutex::ScopedLock _lock(lock); + return agentList.size(); +} + +const AgentProxy* BrokerProxyImpl::getAgent(uint32_t idx) const +{ + Mutex::ScopedLock _lock(lock); + for (map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.begin(); + iter != agentList.end(); iter++) + if (idx-- == 0) + return iter->second.get(); + return 0; +} + +void BrokerProxyImpl::sendQuery(const Query& query, void* context, const AgentProxy* agent) +{ + SequenceContext::Ptr queryContext(new QueryContext(*this, context)); + Mutex::ScopedLock _lock(lock); + if (agent != 0) { + sendGetRequestLH(queryContext, query, agent); + } else { + // TODO (optimization) only send queries to agents that have the requested class+package + for (map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.begin(); + iter != agentList.end(); iter++) { + sendGetRequestLH(queryContext, query, iter->second.get()); + } + } +} + +void BrokerProxyImpl::sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxy* agent) +{ + stringstream key; + Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); + uint32_t sequence(seqMgr.reserve(queryContext)); + agent->impl->addSequence(sequence); + + Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence); + query.impl->encode(outBuffer); + key << "agent.1." << agent->impl->agentBank; + sendBufferLH(outBuffer, QMF_EXCHANGE, key.str()); + QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << key.str()); +} + +string BrokerProxyImpl::encodeMethodArguments(const SchemaMethod* schema, const Value* argmap, Buffer& buffer) +{ + int argCount = schema->getArgumentCount(); + + if (argmap == 0 || !argmap->isMap()) + return string("Arguments must be in a map value"); + + for (int aIdx = 0; aIdx < argCount; aIdx++) { + const SchemaArgument* arg(schema->getArgument(aIdx)); + if (arg->getDirection() == DIR_IN || arg->getDirection() == DIR_IN_OUT) { + if (argmap->keyInMap(arg->getName())) { + const Value* argVal(argmap->byKey(arg->getName())); + if (argVal->getType() != arg->getType()) + return string("Argument is the wrong type: ") + arg->getName(); + argVal->impl->encode(buffer); + } else { + Value defaultValue(arg->getType()); + defaultValue.impl->encode(buffer); + } + } + } + + return string(); +} + +void BrokerProxyImpl::sendMethodRequest(ObjectId* oid, const SchemaObjectClass* cls, + const string& methodName, const Value* args, void* userContext) +{ + int methodCount = cls->getMethodCount(); + int idx; + for (idx = 0; idx < methodCount; idx++) { + const SchemaMethod* method = cls->getMethod(idx); + if (string(method->getName()) == methodName) { + Mutex::ScopedLock _lock(lock); + SequenceContext::Ptr methodContext(new MethodContext(*this, userContext, method)); + stringstream key; + Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); + uint32_t sequence(seqMgr.reserve(methodContext)); + + Protocol::encodeHeader(outBuffer, Protocol::OP_METHOD_REQUEST, sequence); + oid->impl->encode(outBuffer); + cls->getClassKey()->impl->encode(outBuffer); + outBuffer.putShortString(methodName); + + string argErrorString = encodeMethodArguments(method, args, outBuffer); + if (argErrorString.empty()) { + key << "agent.1." << oid->impl->getAgentBank(); + sendBufferLH(outBuffer, QMF_EXCHANGE, key.str()); + QPID_LOG(trace, "SENT MethodRequest seq=" << sequence << " method=" << methodName << " key=" << key.str()); + } else { + MethodResponsePtr argError(MethodResponseImpl::factory(1, argErrorString)); + eventQueue.push_back(eventMethodResponse(userContext, argError)); + } + return; + } + } + + MethodResponsePtr error(MethodResponseImpl::factory(1, string("Unknown method: ") + methodName)); + Mutex::ScopedLock _lock(lock); + eventQueue.push_back(eventMethodResponse(userContext, error)); +} + +void BrokerProxyImpl::addBinding(const string& exchange, const string& key) +{ + Mutex::ScopedLock _lock(lock); + 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() +{ + QPID_LOG(trace, "Console Link to Broker Stable"); + BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::STABLE)); + return event; +} + +BrokerEventImpl::Ptr BrokerProxyImpl::eventQueryComplete(void* context, QueryResponsePtr response) +{ + BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::QUERY_COMPLETE)); + event->context = context; + event->queryResponse = response; + return event; +} + +BrokerEventImpl::Ptr BrokerProxyImpl::eventMethodResponse(void* context, MethodResponsePtr response) +{ + BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::METHOD_RESPONSE)); + event->context = context; + event->methodResponse = response; + return event; +} + +void BrokerProxyImpl::handleBrokerResponse(Buffer& inBuffer, uint32_t seq) +{ + 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()); + incOutstandingLH(); + 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.impl->learnPackage(package); + + Mutex::ScopedLock _lock(lock); + Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); + uint32_t sequence(seqMgr.reserve()); + 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); +} + +void BrokerProxyImpl::handleClassIndication(Buffer& inBuffer, uint32_t seq) +{ + uint8_t kind = inBuffer.getOctet(); + auto_ptr<SchemaClassKey> classKey(SchemaClassKeyImpl::factory(inBuffer)); + + QPID_LOG(trace, "RCVD ClassIndication seq=" << seq << " kind=" << (int) kind << " key=" << classKey->impl->str()); + + if (!console.impl->haveClass(classKey.get())) { + Mutex::ScopedLock _lock(lock); + incOutstandingLH(); + Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); + uint32_t sequence(seqMgr.reserve()); + Protocol::encodeHeader(outBuffer, Protocol::OP_SCHEMA_REQUEST, sequence); + classKey->impl->encode(outBuffer); + sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_KEY); + QPID_LOG(trace, "SENT SchemaRequest seq=" << sequence <<" key=" << classKey->impl->str()); + } +} + +MethodResponsePtr BrokerProxyImpl::handleMethodResponse(Buffer& inBuffer, uint32_t seq, const SchemaMethod* schema) +{ + MethodResponsePtr response(MethodResponseImpl::factory(inBuffer, schema)); + + QPID_LOG(trace, "RCVD MethodResponse seq=" << seq << " status=" << response->getStatus() << " text=" << + response->getException()->asString()); + + return response; +} + +void BrokerProxyImpl::handleHeartbeatIndication(Buffer& inBuffer, uint32_t seq, const string& routingKey) +{ + vector<string> tokens = qpid::split(routingKey, "."); + uint32_t agentBank; + uint64_t timestamp; + + if (routingKey.empty() || tokens.size() != 4) + agentBank = 0; + else + agentBank = ::atoi(tokens[3].c_str()); + + timestamp = inBuffer.getLongLong(); + map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.find(agentBank); + if (iter != agentList.end()) { + console.impl->eventAgentHeartbeat(iter->second, timestamp); + } + QPID_LOG(trace, "RCVD HeartbeatIndication seq=" << seq << " agentBank=" << agentBank); +} + +void BrokerProxyImpl::handleEventIndication(Buffer& /*inBuffer*/, uint32_t /*seq*/) +{ + // TODO +} + +void BrokerProxyImpl::handleSchemaResponse(Buffer& inBuffer, uint32_t seq) +{ + SchemaObjectClass* oClassPtr; + SchemaEventClass* eClassPtr; + uint8_t kind = inBuffer.getOctet(); + const SchemaClassKey* key; + if (kind == CLASS_OBJECT) { + oClassPtr = SchemaObjectClassImpl::factory(inBuffer); + console.impl->learnClass(oClassPtr); + key = oClassPtr->getClassKey(); + QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=object key=" << key->impl->str()); + + // + // If we have just learned about the org.apache.qpid.broker:agent class, send a get + // request for the current list of agents so we can have it on-hand before we declare + // this session "stable". + // + if (key->impl->getClassName() == AGENT_CLASS && key->impl->getPackageName() == BROKER_PACKAGE) { + Mutex::ScopedLock _lock(lock); + incOutstandingLH(); + Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); + uint32_t sequence(seqMgr.reserve()); + Protocol::encodeHeader(outBuffer, Protocol::OP_GET_QUERY, sequence); + FieldTable ft; + ft.setString("_class", AGENT_CLASS); + ft.setString("_package", BROKER_PACKAGE); + ft.encode(outBuffer); + sendBufferLH(outBuffer, QMF_EXCHANGE, BROKER_AGENT_KEY); + QPID_LOG(trace, "SENT GetQuery seq=" << sequence << " key=" << BROKER_AGENT_KEY); + } + } else if (kind == CLASS_EVENT) { + eClassPtr = SchemaEventClassImpl::factory(inBuffer); + console.impl->learnClass(eClassPtr); + key = eClassPtr->getClassKey(); + QPID_LOG(trace, "RCVD SchemaResponse seq=" << seq << " kind=event key=" << key->impl->str()); + } + else { + QPID_LOG(error, "BrokerProxyImpl::handleSchemaResponse received unknown class kind: " << (int) kind); + } +} + +ObjectPtr BrokerProxyImpl::handleObjectIndication(Buffer& inBuffer, uint32_t seq, bool prop, bool stat) +{ + auto_ptr<SchemaClassKey> classKey(SchemaClassKeyImpl::factory(inBuffer)); + QPID_LOG(trace, "RCVD ObjectIndication seq=" << seq << " key=" << classKey->impl->str()); + + SchemaObjectClass* schema = console.impl->getSchema(classKey.get()); + if (schema == 0) { + QPID_LOG(trace, "No Schema Found for ObjectIndication. seq=" << seq << " key=" << classKey->impl->str()); + return ObjectPtr(); + } + + ObjectPtr optr(ObjectImpl::factory(schema, this, inBuffer, prop, stat, true)); + if (prop && classKey->impl->getPackageName() == BROKER_PACKAGE && classKey->impl->getClassName() == AGENT_CLASS) { + // + // We've intercepted information about a remote agent... update the agent list accordingly + // + updateAgentList(optr); + } + return optr; +} + +void BrokerProxyImpl::updateAgentList(ObjectPtr obj) +{ + Value* value = obj->getValue("agentBank"); + Mutex::ScopedLock _lock(lock); + if (value != 0 && value->isUint()) { + uint32_t agentBank = value->asUint(); + if (obj->isDeleted()) { + map<uint32_t, AgentProxyPtr>::iterator iter = agentList.find(agentBank); + if (iter != agentList.end()) { + AgentProxyPtr agent(iter->second); + console.impl->eventAgentDeleted(agent); + agentList.erase(agentBank); + QPID_LOG(trace, "Agent at bank " << agentBank << " removed from agent list"); + + // + // Release all sequence numbers for requests in-flight to this agent. + // Since the agent is no longer connected, these requests would not + // otherwise complete. + // + agent->impl->releaseInFlight(seqMgr); + } + } else { + Value* str = obj->getValue("label"); + string label; + if (str != 0 && str->isString()) + label = str->asString(); + map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.find(agentBank); + if (iter == agentList.end()) { + AgentProxyPtr agent(AgentProxyImpl::factory(console, publicObject, agentBank, label)); + agentList[agentBank] = agent; + console.impl->eventAgentAdded(agent); + QPID_LOG(trace, "Agent '" << label << "' found at bank " << agentBank); + } + } + } +} + +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.impl->bindingList.begin(); + iter != console.impl->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(const MethodResponseImpl& from) : + status(from.status), schema(from.schema) +{ + if (from.exception.get()) + exception.reset(new Value(*(from.exception))); + if (from.arguments.get()) + arguments.reset(new Value(*(from.arguments))); +} + +MethodResponseImpl::MethodResponseImpl(Buffer& buf, const SchemaMethod* s) : schema(s) +{ + string text; + + status = buf.getLong(); + buf.getMediumString(text); + exception.reset(new Value(TYPE_LSTR)); + exception->setString(text.c_str()); + + if (status != 0) + return; + + arguments.reset(new Value(TYPE_MAP)); + int argCount(schema->getArgumentCount()); + for (int idx = 0; idx < argCount; idx++) { + const SchemaArgument* arg = schema->getArgument(idx); + if (arg->getDirection() == DIR_OUT || arg->getDirection() == DIR_IN_OUT) { + Value* value(ValueImpl::factory(arg->getType(), buf)); + arguments->insert(arg->getName(), value); + } + } +} + +MethodResponseImpl::MethodResponseImpl(uint32_t s, const string& text) : schema(0) +{ + status = s; + exception.reset(new Value(TYPE_LSTR)); + exception->setString(text.c_str()); +} + +MethodResponse* MethodResponseImpl::factory(Buffer& buf, const SchemaMethod* schema) +{ + MethodResponseImpl* impl(new MethodResponseImpl(buf, schema)); + return new MethodResponse(impl); +} + +MethodResponse* MethodResponseImpl::factory(uint32_t status, const std::string& text) +{ + MethodResponseImpl* impl(new MethodResponseImpl(status, text)); + return new MethodResponse(impl); +} + +bool StaticContext::handleMessage(uint8_t opcode, uint32_t sequence, const string& routingKey, Buffer& buffer) +{ + ObjectPtr object; + bool completeContext = false; + + if (opcode == Protocol::OP_BROKER_RESPONSE) { + broker.handleBrokerResponse(buffer, sequence); + completeContext = true; + } + else if (opcode == Protocol::OP_COMMAND_COMPLETE) { + broker.handleCommandComplete(buffer, sequence); + completeContext = true; + } + else if (opcode == Protocol::OP_SCHEMA_RESPONSE) { + broker.handleSchemaResponse(buffer, sequence); + completeContext = true; + } + else if (opcode == Protocol::OP_PACKAGE_INDICATION) + broker.handlePackageIndication(buffer, sequence); + else if (opcode == Protocol::OP_CLASS_INDICATION) + broker.handleClassIndication(buffer, sequence); + else if (opcode == Protocol::OP_HEARTBEAT_INDICATION) + broker.handleHeartbeatIndication(buffer, sequence, routingKey); + else if (opcode == Protocol::OP_EVENT_INDICATION) + broker.handleEventIndication(buffer, sequence); + else if (opcode == Protocol::OP_PROPERTY_INDICATION) { + object = broker.handleObjectIndication(buffer, sequence, true, false); + broker.console.impl->eventObjectUpdate(object, true, false); + } + else if (opcode == Protocol::OP_STATISTIC_INDICATION) { + object = broker.handleObjectIndication(buffer, sequence, false, true); + broker.console.impl->eventObjectUpdate(object, false, true); + } + else if (opcode == Protocol::OP_OBJECT_INDICATION) { + object = broker.handleObjectIndication(buffer, sequence, true, true); + broker.console.impl->eventObjectUpdate(object, true, true); + } + else { + QPID_LOG(trace, "StaticContext::handleMessage invalid opcode: " << opcode); + completeContext = true; + } + + return completeContext; +} + +void QueryContext::reserve() +{ + Mutex::ScopedLock _lock(lock); + requestsOutstanding++; +} + +void QueryContext::release() +{ + { + Mutex::ScopedLock _lock(lock); + if (--requestsOutstanding > 0) + return; + } + + Mutex::ScopedLock _block(broker.lock); + broker.eventQueue.push_back(broker.eventQueryComplete(userContext, queryResponse)); +} + +bool QueryContext::handleMessage(uint8_t opcode, uint32_t sequence, const string& /*routingKey*/, Buffer& buffer) +{ + bool completeContext = false; + ObjectPtr object; + + if (opcode == Protocol::OP_COMMAND_COMPLETE) { + broker.handleCommandComplete(buffer, sequence); + completeContext = true; + + // + // Visit each agent and remove the sequence from that agent's in-flight list. + // This could be made more efficient because only one agent will have this sequence + // in its list. + // + map<uint32_t, AgentProxyPtr> copy; + { + Mutex::ScopedLock _block(broker.lock); + copy = broker.agentList; + } + for (map<uint32_t, AgentProxyPtr>::iterator iter = copy.begin(); iter != copy.end(); iter++) + iter->second->impl->delSequence(sequence); + } + else if (opcode == Protocol::OP_OBJECT_INDICATION) { + object = broker.handleObjectIndication(buffer, sequence, true, true); + if (object.get() != 0) + queryResponse->impl->results.push_back(object); + } + else { + QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode); + completeContext = true; + } + + return completeContext; +} + +void MethodContext::release() +{ + Mutex::ScopedLock _block(broker.lock); + broker.eventQueue.push_back(broker.eventMethodResponse(userContext, methodResponse)); +} + +bool MethodContext::handleMessage(uint8_t opcode, uint32_t sequence, const string& /*routingKey*/, Buffer& buffer) +{ + if (opcode == Protocol::OP_METHOD_RESPONSE) + methodResponse = broker.handleMethodResponse(buffer, sequence, schema); + else + QPID_LOG(trace, "QueryContext::handleMessage invalid opcode: " << opcode); + + return true; +} + + +//================================================================== +// Wrappers +//================================================================== + +AgentProxy::AgentProxy(AgentProxyImpl* i) : impl(i) {} +AgentProxy::~AgentProxy() { delete impl; } +const char* AgentProxy::getLabel() const { return impl->getLabel().c_str(); } +uint32_t AgentProxy::getBrokerBank() const { return impl->getBrokerBank(); } +uint32_t AgentProxy::getAgentBank() const { return impl->getAgentBank(); } + +BrokerProxy::BrokerProxy(Console& 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(); } +uint32_t BrokerProxy::agentCount() const { return impl->agentCount(); } +const AgentProxy* BrokerProxy::getAgent(uint32_t idx) const { return impl->getAgent(idx); } +void BrokerProxy::sendQuery(const Query& query, void* context, const AgentProxy* agent) { impl->sendQuery(query, context, agent); } + +MethodResponse::MethodResponse(const MethodResponse& from) : impl(new MethodResponseImpl(*(from.impl))) {} +MethodResponse::MethodResponse(MethodResponseImpl* i) : impl(i) {} +MethodResponse::~MethodResponse() {} +uint32_t MethodResponse::getStatus() const { return impl->getStatus(); } +const Value* MethodResponse::getException() const { return impl->getException(); } +const Value* MethodResponse::getArgs() const { return impl->getArgs(); } + +QueryResponse::QueryResponse(QueryResponseImpl* i) : impl(i) {} +QueryResponse::~QueryResponse() {} +uint32_t QueryResponse::getStatus() const { return impl->getStatus(); } +const Value* QueryResponse::getException() const { return impl->getException(); } +uint32_t QueryResponse::getObjectCount() const { return impl->getObjectCount(); } +const Object* QueryResponse::getObject(uint32_t idx) const { return impl->getObject(idx); } + diff --git a/qpid/cpp/src/qmf/engine/BrokerProxyImpl.h b/qpid/cpp/src/qmf/engine/BrokerProxyImpl.h new file mode 100644 index 0000000000..798a5fdc76 --- /dev/null +++ b/qpid/cpp/src/qmf/engine/BrokerProxyImpl.h @@ -0,0 +1,239 @@ +#ifndef _QmfEngineBrokerProxyImpl_ +#define _QmfEngineBrokerProxyImpl_ + +/* + * 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/engine/Console.h" +#include "qmf/engine/ObjectImpl.h" +#include "qmf/engine/SchemaImpl.h" +#include "qmf/engine/ValueImpl.h" +#include "qmf/engine/QueryImpl.h" +#include "qmf/engine/SequenceManager.h" +#include "qmf/engine/MessageImpl.h" +#include "qpid/framing/Buffer.h" +#include "qpid/framing/Uuid.h" +#include "qpid/sys/Mutex.h" +#include "boost/shared_ptr.hpp" +#include "boost/noncopyable.hpp" +#include <memory> +#include <string> +#include <deque> +#include <map> +#include <set> +#include <vector> + +namespace qmf { +namespace engine { + + typedef boost::shared_ptr<MethodResponse> MethodResponsePtr; + struct MethodResponseImpl { + uint32_t status; + const SchemaMethod* schema; + std::auto_ptr<Value> exception; + std::auto_ptr<Value> arguments; + + MethodResponseImpl(const MethodResponseImpl& from); + MethodResponseImpl(qpid::framing::Buffer& buf, const SchemaMethod* schema); + MethodResponseImpl(uint32_t status, const std::string& text); + static MethodResponse* factory(qpid::framing::Buffer& buf, const SchemaMethod* schema); + static MethodResponse* factory(uint32_t status, const std::string& text); + ~MethodResponseImpl() {} + uint32_t getStatus() const { return status; } + const Value* getException() const { return exception.get(); } + const Value* getArgs() const { return arguments.get(); } + }; + + typedef boost::shared_ptr<QueryResponse> QueryResponsePtr; + struct QueryResponseImpl { + uint32_t status; + std::auto_ptr<Value> exception; + std::vector<ObjectPtr> results; + + QueryResponseImpl() : status(0) {} + static QueryResponse* factory() { + QueryResponseImpl* impl(new QueryResponseImpl()); + return new QueryResponse(impl); + } + ~QueryResponseImpl() {} + uint32_t getStatus() const { return status; } + const Value* getException() const { return exception.get(); } + uint32_t getObjectCount() const { return results.size(); } + const Object* getObject(uint32_t idx) const; + }; + + struct BrokerEventImpl { + typedef boost::shared_ptr<BrokerEventImpl> Ptr; + BrokerEvent::EventKind kind; + std::string name; + std::string exchange; + std::string bindingKey; + void* context; + QueryResponsePtr queryResponse; + MethodResponsePtr methodResponse; + + BrokerEventImpl(BrokerEvent::EventKind k) : kind(k), context(0) {} + ~BrokerEventImpl() {} + BrokerEvent copy(); + }; + + typedef boost::shared_ptr<AgentProxy> AgentProxyPtr; + struct AgentProxyImpl { + Console& console; + BrokerProxy& broker; + uint32_t agentBank; + std::string label; + std::set<uint32_t> inFlightSequences; + + AgentProxyImpl(Console& c, BrokerProxy& b, uint32_t ab, const std::string& l) : console(c), broker(b), agentBank(ab), label(l) {} + static AgentProxy* factory(Console& c, BrokerProxy& b, uint32_t ab, const std::string& l) { + AgentProxyImpl* impl(new AgentProxyImpl(c, b, ab, l)); + return new AgentProxy(impl); + } + ~AgentProxyImpl() {} + const std::string& getLabel() const { return label; } + uint32_t getBrokerBank() const { return 1; } + uint32_t getAgentBank() const { return agentBank; } + void addSequence(uint32_t seq) { inFlightSequences.insert(seq); } + void delSequence(uint32_t seq) { inFlightSequences.erase(seq); } + void releaseInFlight(SequenceManager& seqMgr) { + for (std::set<uint32_t>::iterator iter = inFlightSequences.begin(); iter != inFlightSequences.end(); iter++) + seqMgr.release(*iter); + inFlightSequences.clear(); + } + }; + + class BrokerProxyImpl : public boost::noncopyable { + public: + BrokerProxyImpl(BrokerProxy& pub, Console& _console); + ~BrokerProxyImpl() {} + + void sessionOpened(SessionHandle& sh); + void sessionClosed(); + void startProtocol(); + + void sendBufferLH(qpid::framing::Buffer& buf, const std::string& destination, const std::string& routingKey); + void handleRcvMessage(Message& message); + bool getXmtMessage(Message& item) const; + void popXmt(); + + bool getEvent(BrokerEvent& event) const; + void popEvent(); + + uint32_t agentCount() const; + const AgentProxy* getAgent(uint32_t idx) const; + void sendQuery(const Query& query, void* context, const AgentProxy* agent); + void sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxy* agent); + std::string encodeMethodArguments(const SchemaMethod* schema, const Value* args, qpid::framing::Buffer& buffer); + void sendMethodRequest(ObjectId* oid, const SchemaObjectClass* cls, const std::string& method, const Value* args, void* context); + + void addBinding(const std::string& exchange, const std::string& key); + void staticRelease() { decOutstanding(); } + + private: + friend struct StaticContext; + friend struct QueryContext; + friend struct MethodContext; + BrokerProxy& publicObject; + mutable qpid::sys::Mutex lock; + Console& console; + std::string queueName; + qpid::framing::Uuid brokerId; + SequenceManager seqMgr; + uint32_t requestsOutstanding; + bool topicBound; + std::map<uint32_t, AgentProxyPtr> agentList; + std::deque<MessageImpl::Ptr> xmtQueue; + std::deque<BrokerEventImpl::Ptr> eventQueue; + +# define MA_BUFFER_SIZE 65536 + char outputBuffer[MA_BUFFER_SIZE]; + + BrokerEventImpl::Ptr eventDeclareQueue(const std::string& queueName); + BrokerEventImpl::Ptr eventBind(const std::string& exchange, const std::string& queue, const std::string& key); + BrokerEventImpl::Ptr eventSetupComplete(); + BrokerEventImpl::Ptr eventStable(); + BrokerEventImpl::Ptr eventQueryComplete(void* context, QueryResponsePtr response); + BrokerEventImpl::Ptr eventMethodResponse(void* context, MethodResponsePtr response); + + void handleBrokerResponse(qpid::framing::Buffer& inBuffer, uint32_t seq); + void handlePackageIndication(qpid::framing::Buffer& inBuffer, uint32_t seq); + void handleCommandComplete(qpid::framing::Buffer& inBuffer, uint32_t seq); + void handleClassIndication(qpid::framing::Buffer& inBuffer, uint32_t seq); + MethodResponsePtr handleMethodResponse(qpid::framing::Buffer& inBuffer, uint32_t seq, const SchemaMethod* schema); + void handleHeartbeatIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, const std::string& routingKey); + void handleEventIndication(qpid::framing::Buffer& inBuffer, uint32_t seq); + void handleSchemaResponse(qpid::framing::Buffer& inBuffer, uint32_t seq); + ObjectPtr handleObjectIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, bool prop, bool stat); + void updateAgentList(ObjectPtr obj); + void incOutstandingLH(); + void decOutstanding(); + }; + + // + // StaticContext is used to handle: + // + // 1) Responses to console-level requests (for schema info, etc.) + // 2) Unsolicited messages from agents (events, published updates, etc.) + // + struct StaticContext : public SequenceContext { + StaticContext(BrokerProxyImpl& b) : broker(b) {} + virtual ~StaticContext() {} + void reserve() {} + void release() { broker.staticRelease(); } + bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer); + BrokerProxyImpl& broker; + }; + + // + // QueryContext is used to track and handle responses associated with a single Get Query + // + struct QueryContext : public SequenceContext { + QueryContext(BrokerProxyImpl& b, void* u) : + broker(b), userContext(u), requestsOutstanding(0), queryResponse(QueryResponseImpl::factory()) {} + virtual ~QueryContext() {} + void reserve(); + void release(); + bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer); + + mutable qpid::sys::Mutex lock; + BrokerProxyImpl& broker; + void* userContext; + uint32_t requestsOutstanding; + QueryResponsePtr queryResponse; + }; + + struct MethodContext : public SequenceContext { + MethodContext(BrokerProxyImpl& b, void* u, const SchemaMethod* s) : broker(b), userContext(u), schema(s) {} + virtual ~MethodContext() {} + void reserve() {} + void release(); + bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer); + + BrokerProxyImpl& broker; + void* userContext; + const SchemaMethod* schema; + MethodResponsePtr methodResponse; + }; + +} +} + +#endif + diff --git a/qpid/cpp/src/qmf/ConnectionSettingsImpl.cpp b/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp index 034ab18395..2cd6af10f8 100644 --- a/qpid/cpp/src/qmf/ConnectionSettingsImpl.cpp +++ b/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp @@ -17,11 +17,11 @@ * under the License. */ -#include "qmf/ConnectionSettingsImpl.h" -#include "qmf/Typecode.h" +#include "qmf/engine/ConnectionSettingsImpl.h" +#include "qmf/engine/Typecode.h" using namespace std; -using namespace qmf; +using namespace qmf::engine; using namespace qpid; const string attrProtocol("protocol"); @@ -43,19 +43,20 @@ const string attrMaxSsf("maxSsf"); const string attrRetryDelayMin("retryDelayMin"); const string attrRetryDelayMax("retryDelayMax"); const string attrRetryDelayFactor("retryDelayFactor"); +const string attrSendUserId("sendUserId"); -ConnectionSettingsImpl::ConnectionSettingsImpl(ConnectionSettings* e) : - envelope(e), retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2) +ConnectionSettingsImpl::ConnectionSettingsImpl() : + retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2), sendUserId(true) { } -ConnectionSettingsImpl::ConnectionSettingsImpl(ConnectionSettings* e, const string& /*url*/) : - envelope(e), retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2) +ConnectionSettingsImpl::ConnectionSettingsImpl(const string& /*url*/) : + retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2), sendUserId(true) { // TODO: Parse the URL } -void ConnectionSettingsImpl::setAttr(const string& key, const Value& value) +bool ConnectionSettingsImpl::setAttr(const string& key, const Value& value) { if (key == attrProtocol) clientSettings.protocol = value.asString(); else if (key == attrHost) clientSettings.host = value.asString(); @@ -77,6 +78,10 @@ void ConnectionSettingsImpl::setAttr(const string& key, const Value& value) else if (key == attrRetryDelayMin) retryDelayMin = value.asUint(); else if (key == attrRetryDelayMax) retryDelayMax = value.asUint(); else if (key == attrRetryDelayFactor) retryDelayFactor = value.asUint(); + else if (key == attrSendUserId) sendUserId = value.asBool(); + else + return false; + return true; } Value ConnectionSettingsImpl::getAttr(const string& key) const @@ -251,73 +256,18 @@ void ConnectionSettingsImpl::getRetrySettings(int* min, int* max, int* factor) c // 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); -} +ConnectionSettings::ConnectionSettings(const ConnectionSettings& from) { impl = new ConnectionSettingsImpl(*from.impl); } +ConnectionSettings::ConnectionSettings() { impl = new ConnectionSettingsImpl(); } +ConnectionSettings::ConnectionSettings(const char* url) { impl = new ConnectionSettingsImpl(url); } +ConnectionSettings::~ConnectionSettings() { delete impl; } +bool ConnectionSettings::setAttr(const char* key, const Value& value) { return 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/engine/ConnectionSettingsImpl.h index a177233cf3..98bf87868b 100644 --- a/qpid/cpp/src/qmf/ConnectionSettingsImpl.h +++ b/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.h @@ -1,5 +1,5 @@ -#ifndef _QmfConnectionSettingsImpl_ -#define _QmfConnectionSettingsImpl_ +#ifndef _QmfEngineConnectionSettingsImpl_ +#define _QmfEngineConnectionSettingsImpl_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,27 +20,28 @@ * under the License. */ -#include "qmf/ConnectionSettings.h" -#include "qmf/Value.h" +#include "qmf/engine/ConnectionSettings.h" +#include "qmf/engine/Value.h" #include "qpid/client/ConnectionSettings.h" #include <string> #include <map> namespace qmf { +namespace engine { class ConnectionSettingsImpl { - ConnectionSettings* envelope; qpid::client::ConnectionSettings clientSettings; mutable std::string attrString; int retryDelayMin; int retryDelayMax; int retryDelayFactor; + bool sendUserId; public: - ConnectionSettingsImpl(ConnectionSettings* e); - ConnectionSettingsImpl(ConnectionSettings* e, const std::string& url); + ConnectionSettingsImpl(); + ConnectionSettingsImpl(const std::string& url); ~ConnectionSettingsImpl() {} - void setAttr(const std::string& key, const Value& value); + bool 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); @@ -53,8 +54,10 @@ namespace qmf { const qpid::client::ConnectionSettings& getClientSettings() const; void getRetrySettings(int* delayMin, int* delayMax, int* delayFactor) const; + bool getSendUserId() const { return sendUserId; } }; } +} #endif diff --git a/qpid/cpp/src/qmf/engine/ConsoleImpl.cpp b/qpid/cpp/src/qmf/engine/ConsoleImpl.cpp new file mode 100644 index 0000000000..c2d1f51f2b --- /dev/null +++ b/qpid/cpp/src/qmf/engine/ConsoleImpl.cpp @@ -0,0 +1,419 @@ +/* + * 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/engine/ConsoleImpl.h" +#include "qmf/engine/MessageImpl.h" +#include "qmf/engine/SchemaImpl.h" +#include "qmf/engine/Typecode.h" +#include "qmf/engine/ObjectImpl.h" +#include "qmf/engine/ObjectIdImpl.h" +#include "qmf/engine/QueryImpl.h" +#include "qmf/engine/ValueImpl.h" +#include "qmf/engine/Protocol.h" +#include "qmf/engine/SequenceManager.h" +#include "qmf/engine/BrokerProxyImpl.h" +#include <qpid/framing/Buffer.h> +#include <qpid/framing/Uuid.h> +#include <qpid/framing/FieldTable.h> +#include <qpid/framing/FieldValue.h> +#include <qpid/log/Statement.h> +#include <qpid/sys/Time.h> +#include <qpid/sys/SystemInfo.h> +#include <string.h> +#include <iostream> +#include <fstream> + +using namespace std; +using namespace qmf::engine; +using namespace qpid::framing; +using namespace qpid::sys; + +namespace { + const char* QMF_EXCHANGE = "qpid.management"; +} + +#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(); + item.classKey = classKey; + item.object = object.get(); + item.context = context; + item.event = event; + item.timestamp = timestamp; + item.hasProps = hasProps; + item.hasStats = hasStats; + + STRING_REF(name); + + return item; +} + +ConsoleImpl::ConsoleImpl(const ConsoleSettings& s) : 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.#")); + } +} + +ConsoleImpl::~ConsoleImpl() +{ + // This function intentionally left blank. +} + +bool ConsoleImpl::getEvent(ConsoleEvent& event) const +{ + Mutex::ScopedLock _lock(lock); + if (eventQueue.empty()) + return false; + event = eventQueue.front()->copy(); + return true; +} + +void ConsoleImpl::popEvent() +{ + Mutex::ScopedLock _lock(lock); + if (!eventQueue.empty()) + eventQueue.pop_front(); +} + +void ConsoleImpl::addConnection(BrokerProxy& broker, void* /*context*/) +{ + Mutex::ScopedLock _lock(lock); + brokerList.push_back(broker.impl); +} + +void ConsoleImpl::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 ConsoleImpl::packageCount() const +{ + Mutex::ScopedLock _lock(lock); + return packages.size(); +} + +const string& ConsoleImpl::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 ConsoleImpl::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* ConsoleImpl::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 ConsoleImpl::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) != eList.end()) + return CLASS_EVENT; + return CLASS_OBJECT; +} + +const SchemaObjectClass* ConsoleImpl::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); + if (iter == oList.end()) + return 0; + return iter->second; +} + +const SchemaEventClass* ConsoleImpl::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); + if (iter == eList.end()) + return 0; + return iter->second; +} + +void ConsoleImpl::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 ConsoleImpl::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 ConsoleImpl::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()); +} + +/* +void ConsoleImpl::startSync(const Query& query, void* context, SyncQuery& sync) +{ +} + +void ConsoleImpl::touchSync(SyncQuery& sync) +{ +} + +void ConsoleImpl::endSync(SyncQuery& sync) +{ +} +*/ + +void ConsoleImpl::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()))); + eventNewPackage(packageName); + } +} + +void ConsoleImpl::learnClass(SchemaObjectClass* 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) == list.end()) { + list[key] = cls; + eventNewClass(key); + } +} + +void ConsoleImpl::learnClass(SchemaEventClass* 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) == list.end()) { + list[key] = cls; + eventNewClass(key); + } +} + +bool ConsoleImpl::haveClass(const SchemaClassKey* 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(); +} + +SchemaObjectClass* ConsoleImpl::getSchema(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); + if (iter == oList.end()) + return 0; + + return iter->second; +} + +void ConsoleImpl::eventAgentAdded(boost::shared_ptr<AgentProxy> agent) +{ + ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::AGENT_ADDED)); + event->agent = agent; + Mutex::ScopedLock _lock(lock); + eventQueue.push_back(event); +} + +void ConsoleImpl::eventAgentDeleted(boost::shared_ptr<AgentProxy> agent) +{ + ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::AGENT_DELETED)); + event->agent = agent; + Mutex::ScopedLock _lock(lock); + eventQueue.push_back(event); +} + +void ConsoleImpl::eventNewPackage(const string& packageName) +{ + ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::NEW_PACKAGE)); + event->name = packageName; + Mutex::ScopedLock _lock(lock); + eventQueue.push_back(event); +} + +void ConsoleImpl::eventNewClass(const SchemaClassKey* key) +{ + ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::NEW_CLASS)); + event->classKey = key; + Mutex::ScopedLock _lock(lock); + eventQueue.push_back(event); +} + +void ConsoleImpl::eventObjectUpdate(ObjectPtr object, bool prop, bool stat) +{ + ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::OBJECT_UPDATE)); + event->object = object; + event->hasProps = prop; + event->hasStats = stat; + Mutex::ScopedLock _lock(lock); + eventQueue.push_back(event); +} + +void ConsoleImpl::eventAgentHeartbeat(boost::shared_ptr<AgentProxy> agent, uint64_t timestamp) +{ + ConsoleEventImpl::Ptr event(new ConsoleEventImpl(ConsoleEvent::AGENT_HEARTBEAT)); + event->agent = agent; + event->timestamp = timestamp; + Mutex::ScopedLock _lock(lock); + eventQueue.push_back(event); +} + +//================================================================== +// Wrappers +//================================================================== + +Console::Console(const ConsoleSettings& settings) : impl(new ConsoleImpl(settings)) {} +Console::~Console() { delete impl; } +bool Console::getEvent(ConsoleEvent& event) const { return impl->getEvent(event); } +void Console::popEvent() { impl->popEvent(); } +void Console::addConnection(BrokerProxy& broker, void* context) { impl->addConnection(broker, context); } +void Console::delConnection(BrokerProxy& broker) { impl->delConnection(broker); } +uint32_t Console::packageCount() const { return impl->packageCount(); } +const char* Console::getPackageName(uint32_t idx) const { return impl->getPackageName(idx).c_str(); } +uint32_t Console::classCount(const char* packageName) const { return impl->classCount(packageName); } +const SchemaClassKey* Console::getClass(const char* packageName, uint32_t idx) const { return impl->getClass(packageName, idx); } +ClassKind Console::getClassKind(const SchemaClassKey* key) const { return impl->getClassKind(key); } +const SchemaObjectClass* Console::getObjectClass(const SchemaClassKey* key) const { return impl->getObjectClass(key); } +const SchemaEventClass* Console::getEventClass(const SchemaClassKey* key) const { return impl->getEventClass(key); } +void Console::bindPackage(const char* packageName) { impl->bindPackage(packageName); } +void Console::bindClass(const SchemaClassKey* key) { impl->bindClass(key); } +void Console::bindClass(const char* packageName, const char* className) { impl->bindClass(packageName, className); } +//void Console::startSync(const Query& query, void* context, SyncQuery& sync) { impl->startSync(query, context, sync); } +//void Console::touchSync(SyncQuery& sync) { impl->touchSync(sync); } +//void Console::endSync(SyncQuery& sync) { impl->endSync(sync); } + + diff --git a/qpid/cpp/src/qmf/engine/ConsoleImpl.h b/qpid/cpp/src/qmf/engine/ConsoleImpl.h new file mode 100644 index 0000000000..8f99c5e6b9 --- /dev/null +++ b/qpid/cpp/src/qmf/engine/ConsoleImpl.h @@ -0,0 +1,145 @@ +#ifndef _QmfEngineConsoleEngineImpl_ +#define _QmfEngineConsoleEngineImpl_ + +/* + * 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/engine/Console.h" +#include "qmf/engine/MessageImpl.h" +#include "qmf/engine/SchemaImpl.h" +#include "qmf/engine/Typecode.h" +#include "qmf/engine/ObjectImpl.h" +#include "qmf/engine/ObjectIdImpl.h" +#include "qmf/engine/QueryImpl.h" +#include "qmf/engine/ValueImpl.h" +#include "qmf/engine/Protocol.h" +#include "qmf/engine/SequenceManager.h" +#include "qmf/engine/BrokerProxyImpl.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/sys/Time.h> +#include <qpid/sys/SystemInfo.h> +#include <string.h> +#include <string> +#include <deque> +#include <map> +#include <vector> +#include <iostream> +#include <fstream> +#include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> + +namespace qmf { +namespace engine { + + struct ConsoleEventImpl { + typedef boost::shared_ptr<ConsoleEventImpl> Ptr; + ConsoleEvent::EventKind kind; + boost::shared_ptr<AgentProxy> agent; + std::string name; + const SchemaClassKey* classKey; + boost::shared_ptr<Object> object; + void* context; + Event* event; + uint64_t timestamp; + bool hasProps; + bool hasStats; + + ConsoleEventImpl(ConsoleEvent::EventKind k) : + kind(k), classKey(0), context(0), event(0), timestamp(0) {} + ~ConsoleEventImpl() {} + ConsoleEvent copy(); + }; + + class ConsoleImpl : public boost::noncopyable { + public: + ConsoleImpl(const ConsoleSettings& settings = ConsoleSettings()); + ~ConsoleImpl(); + + bool getEvent(ConsoleEvent& event) const; + void popEvent(); + + void addConnection(BrokerProxy& broker, void* context); + void delConnection(BrokerProxy& broker); + + uint32_t packageCount() const; + const std::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); + + /* + void startSync(const Query& query, void* context, SyncQuery& sync); + void touchSync(SyncQuery& sync); + void endSync(SyncQuery& sync); + */ + + private: + friend class BrokerProxyImpl; + friend struct StaticContext; + const ConsoleSettings& settings; + mutable qpid::sys::Mutex lock; + std::deque<ConsoleEventImpl::Ptr> eventQueue; + std::vector<BrokerProxyImpl*> brokerList; + std::vector<std::pair<std::string, std::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 SchemaClassKey* left, const SchemaClassKey* right) const { + return *left < *right; + } + }; + + typedef std::map<const SchemaClassKey*, SchemaObjectClass*, KeyCompare> ObjectClassList; + typedef std::map<const SchemaClassKey*, SchemaEventClass*, KeyCompare> EventClassList; + typedef std::map<std::string, std::pair<ObjectClassList, EventClassList> > PackageList; + + PackageList packages; + + void learnPackage(const std::string& packageName); + void learnClass(SchemaObjectClass* cls); + void learnClass(SchemaEventClass* cls); + bool haveClass(const SchemaClassKey* key) const; + SchemaObjectClass* getSchema(const SchemaClassKey* key) const; + + void eventAgentAdded(boost::shared_ptr<AgentProxy> agent); + void eventAgentDeleted(boost::shared_ptr<AgentProxy> agent); + void eventNewPackage(const std::string& packageName); + void eventNewClass(const SchemaClassKey* key); + void eventObjectUpdate(ObjectPtr object, bool prop, bool stat); + void eventAgentHeartbeat(boost::shared_ptr<AgentProxy> agent, uint64_t timestamp); + }; +} +} + +#endif + diff --git a/qpid/cpp/src/qmf/MessageImpl.cpp b/qpid/cpp/src/qmf/engine/MessageImpl.cpp index f2625c7202..0047d3eb9d 100644 --- a/qpid/cpp/src/qmf/MessageImpl.cpp +++ b/qpid/cpp/src/qmf/engine/MessageImpl.cpp @@ -17,11 +17,11 @@ * under the License. */ -#include "qmf/MessageImpl.h" +#include "qmf/engine/MessageImpl.h" #include <string.h> using namespace std; -using namespace qmf; +using namespace qmf::engine; #define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());} diff --git a/qpid/cpp/src/qmf/MessageImpl.h b/qpid/cpp/src/qmf/engine/MessageImpl.h index 137f435699..b91291d2e4 100644 --- a/qpid/cpp/src/qmf/MessageImpl.h +++ b/qpid/cpp/src/qmf/engine/MessageImpl.h @@ -1,5 +1,5 @@ -#ifndef _QmfMessageImpl_ -#define _QmfMessageImpl_ +#ifndef _QmfEngineMessageImpl_ +#define _QmfEngineMessageImpl_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,11 +20,12 @@ * under the License. */ -#include "qmf/Message.h" +#include "qmf/engine/Message.h" #include <string> #include <boost/shared_ptr.hpp> namespace qmf { +namespace engine { struct MessageImpl { typedef boost::shared_ptr<MessageImpl> Ptr; @@ -38,5 +39,6 @@ namespace qmf { Message copy(); }; } +} #endif diff --git a/qpid/cpp/src/qmf/ObjectIdImpl.cpp b/qpid/cpp/src/qmf/engine/ObjectIdImpl.cpp index c0618ccc49..b08ae2756c 100644 --- a/qpid/cpp/src/qmf/ObjectIdImpl.cpp +++ b/qpid/cpp/src/qmf/engine/ObjectIdImpl.cpp @@ -17,11 +17,11 @@ * under the License. */ -#include "qmf/ObjectIdImpl.h" +#include "qmf/engine/ObjectIdImpl.h" #include <stdlib.h> using namespace std; -using namespace qmf; +using namespace qmf::engine; using qpid::framing::Buffer; @@ -32,13 +32,12 @@ void AgentAttachment::setBanks(uint32_t broker, uint32_t agent) ((uint64_t) (agent & 0x0fffffff)); } -ObjectIdImpl::ObjectIdImpl(Buffer& buffer) : envelope(new ObjectId(this)), agent(0) +ObjectIdImpl::ObjectIdImpl(Buffer& buffer) : agent(0) { decode(buffer); } -ObjectIdImpl::ObjectIdImpl(AgentAttachment* a, uint8_t flags, uint16_t seq, uint64_t object) : - envelope(new ObjectId(this)), agent(a) +ObjectIdImpl::ObjectIdImpl(AgentAttachment* a, uint8_t flags, uint16_t seq, uint64_t object) : agent(a) { first = ((uint64_t) (flags & 0x0f)) << 60 | @@ -46,6 +45,18 @@ ObjectIdImpl::ObjectIdImpl(AgentAttachment* a, uint8_t flags, uint16_t seq, uint second = object; } +ObjectId* ObjectIdImpl::factory(Buffer& buffer) +{ + ObjectIdImpl* impl(new ObjectIdImpl(buffer)); + return new ObjectId(impl); +} + +ObjectId* ObjectIdImpl::factory(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object) +{ + ObjectIdImpl* impl(new ObjectIdImpl(agent, flags, seq, object)); + return new ObjectId(impl); +} + void ObjectIdImpl::decode(Buffer& buffer) { first = buffer.getLongLong(); @@ -100,13 +111,14 @@ void ObjectIdImpl::fromString(const std::string& repr) agent = 0; } -std::string ObjectIdImpl::asString() const +const string& ObjectIdImpl::asString() const { stringstream val; - val << getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" << + val << (int) getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" << getAgentBank() << "-" << getObjectNum(); - return val.str(); + repr = val.str(); + return repr; } bool ObjectIdImpl::operator==(const ObjectIdImpl& other) const @@ -135,58 +147,22 @@ bool ObjectIdImpl::operator>(const ObjectIdImpl& other) const // Wrappers //================================================================== -ObjectId::ObjectId() : impl(new ObjectIdImpl(this)) {} - +ObjectId::ObjectId() : impl(new ObjectIdImpl()) {} ObjectId::ObjectId(const ObjectId& from) : impl(new ObjectIdImpl(*(from.impl))) {} - ObjectId::ObjectId(ObjectIdImpl* i) : impl(i) {} +ObjectId::~ObjectId() { delete impl; } +uint64_t ObjectId::getObjectNum() const { return impl->getObjectNum(); } +uint32_t ObjectId::getObjectNumHi() const { return impl->getObjectNumHi(); } +uint32_t ObjectId::getObjectNumLo() const { return impl->getObjectNumLo(); } +bool ObjectId::isDurable() const { return impl->isDurable(); } +const char* ObjectId::str() const { return impl->asString().c_str(); } +uint8_t ObjectId::getFlags() const { return impl->getFlags(); } +uint16_t ObjectId::getSequence() const { return impl->getSequence(); } +uint32_t ObjectId::getBrokerBank() const { return impl->getBrokerBank(); } +uint32_t ObjectId::getAgentBank() const { return impl->getAgentBank(); } +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; } +bool ObjectId::operator<=(const ObjectId& other) const { return !(*impl > *other.impl); } +bool ObjectId::operator>=(const ObjectId& other) const { return !(*impl < *other.impl); } -ObjectId::~ObjectId() -{ - delete impl; -} - -uint64_t ObjectId::getObjectNum() const -{ - return impl->getObjectNum(); -} - -uint32_t ObjectId::getObjectNumHi() const -{ - return impl->getObjectNumHi(); -} - -uint32_t ObjectId::getObjectNumLo() const -{ - return impl->getObjectNumLo(); -} - -bool ObjectId::isDurable() const -{ - return impl->isDurable(); -} - -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; -} - -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/ObjectIdImpl.h b/qpid/cpp/src/qmf/engine/ObjectIdImpl.h index 38d231237f..d9871ac217 100644 --- a/qpid/cpp/src/qmf/ObjectIdImpl.h +++ b/qpid/cpp/src/qmf/engine/ObjectIdImpl.h @@ -1,5 +1,5 @@ -#ifndef _QmfObjectIdImpl_ -#define _QmfObjectIdImpl_ +#ifndef _QmfEngineObjectIdImpl_ +#define _QmfEngineObjectIdImpl_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,10 +20,11 @@ * under the License. */ -#include <qmf/ObjectId.h> +#include <qmf/engine/ObjectId.h> #include <qpid/framing/Buffer.h> namespace qmf { +namespace engine { struct AgentAttachment { uint64_t first; @@ -34,19 +35,22 @@ namespace qmf { }; struct ObjectIdImpl { - ObjectId* envelope; AgentAttachment* agent; uint64_t first; uint64_t second; + mutable std::string repr; - ObjectIdImpl(ObjectId* e) : envelope(e), agent(0), first(0), second(0) {} + ObjectIdImpl() : agent(0), first(0), second(0) {} ObjectIdImpl(qpid::framing::Buffer& buffer); ObjectIdImpl(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object); + static ObjectId* factory(qpid::framing::Buffer& buffer); + static ObjectId* factory(AgentAttachment* agent, uint8_t flags, uint16_t seq, uint64_t object); + void decode(qpid::framing::Buffer& buffer); void encode(qpid::framing::Buffer& buffer) const; void fromString(const std::string& repr); - std::string asString() const; + const std::string& asString() const; uint8_t getFlags() const { return (first & 0xF000000000000000LL) >> 60; } uint16_t getSequence() const { return (first & 0x0FFF000000000000LL) >> 48; } uint32_t getBrokerBank() const { return (first & 0x0000FFFFF0000000LL) >> 28; } @@ -62,6 +66,7 @@ namespace qmf { bool operator>(const ObjectIdImpl& other) const; }; } +} #endif diff --git a/qpid/cpp/src/qmf/ObjectImpl.cpp b/qpid/cpp/src/qmf/engine/ObjectImpl.cpp index 1ea2d54527..cae0e0da68 100644 --- a/qpid/cpp/src/qmf/ObjectImpl.cpp +++ b/qpid/cpp/src/qmf/engine/ObjectImpl.cpp @@ -17,18 +17,17 @@ * under the License. */ -#include "qmf/ObjectImpl.h" -#include "qmf/ValueImpl.h" +#include "qmf/engine/ObjectImpl.h" +#include "qmf/engine/ValueImpl.h" +#include "qmf/engine/BrokerProxyImpl.h" #include <qpid/sys/Time.h> using namespace std; -using namespace qmf; +using namespace qmf::engine; using namespace qpid::sys; using qpid::framing::Buffer; -ObjectImpl::ObjectImpl(Object* e, const SchemaObjectClass* type) : - envelope(e), objectClass(type), createTime(uint64_t(Duration(now()))), - destroyTime(0), lastUpdatedTime(createTime) +ObjectImpl::ObjectImpl(const SchemaObjectClass* type) : objectClass(type), broker(0), createTime(uint64_t(Duration(now()))), destroyTime(0), lastUpdatedTime(createTime) { int propCount = objectClass->getPropertyCount(); int statCount = objectClass->getStatisticCount(); @@ -45,8 +44,8 @@ ObjectImpl::ObjectImpl(Object* e, const SchemaObjectClass* type) : } } -ObjectImpl::ObjectImpl(const SchemaObjectClass* type, Buffer& buffer, bool prop, bool stat, bool managed) : - envelope(new Object(this)), objectClass(type), createTime(0), destroyTime(0), lastUpdatedTime(0) +ObjectImpl::ObjectImpl(const SchemaObjectClass* type, BrokerProxyImpl* b, Buffer& buffer, bool prop, bool stat, bool managed) : + objectClass(type), broker(b), createTime(0), destroyTime(0), lastUpdatedTime(0) { int idx; @@ -54,7 +53,7 @@ ObjectImpl::ObjectImpl(const SchemaObjectClass* type, Buffer& buffer, bool prop, lastUpdatedTime = buffer.getLongLong(); createTime = buffer.getLongLong(); destroyTime = buffer.getLongLong(); - objectId.reset(new ObjectIdImpl(buffer)); + objectId.reset(ObjectIdImpl::factory(buffer)); } if (prop) { @@ -66,8 +65,8 @@ ObjectImpl::ObjectImpl(const SchemaObjectClass* type, Buffer& buffer, bool prop, if (excludes.count(prop->getName()) != 0) { properties[prop->getName()] = ValuePtr(new Value(prop->getType())); } else { - ValueImpl* pval = new ValueImpl(prop->getType(), buffer); - properties[prop->getName()] = ValuePtr(pval->envelope); + Value* pval = ValueImpl::factory(prop->getType(), buffer); + properties[prop->getName()] = ValuePtr(pval); } } } @@ -76,12 +75,18 @@ ObjectImpl::ObjectImpl(const SchemaObjectClass* type, Buffer& buffer, bool prop, int statCount = objectClass->getStatisticCount(); for (idx = 0; idx < statCount; idx++) { const SchemaStatistic* stat = objectClass->getStatistic(idx); - ValueImpl* sval = new ValueImpl(stat->getType(), buffer); - statistics[stat->getName()] = ValuePtr(sval->envelope); + Value* sval = ValueImpl::factory(stat->getType(), buffer); + statistics[stat->getName()] = ValuePtr(sval); } } } +Object* ObjectImpl::factory(const SchemaObjectClass* type, BrokerProxyImpl* b, Buffer& buffer, bool prop, bool stat, bool managed) +{ + ObjectImpl* impl(new ObjectImpl(type, b, buffer, prop, stat, managed)); + return new Object(impl); +} + ObjectImpl::~ObjectImpl() { } @@ -107,6 +112,22 @@ Value* ObjectImpl::getValue(const string& key) const return 0; } +void ObjectImpl::invokeMethod(const string& methodName, const Value* inArgs, void* context) const +{ + if (broker != 0 && objectId.get() != 0) + broker->sendMethodRequest(objectId.get(), objectClass, methodName, inArgs, context); +} + +void ObjectImpl::merge(const Object& from) +{ + for (map<string, ValuePtr>::const_iterator piter = from.impl->properties.begin(); + piter != from.impl->properties.end(); piter++) + properties[piter->first] = piter->second; + for (map<string, ValuePtr>::const_iterator siter = from.impl->statistics.begin(); + siter != from.impl->statistics.end(); siter++) + statistics[siter->first] = siter->second; +} + void ObjectImpl::parsePresenceMasks(Buffer& buffer, set<string>& excludeList) { int propCount = objectClass->getPropertyCount(); @@ -143,7 +164,7 @@ void ObjectImpl::encodeManagedObjectData(qpid::framing::Buffer& buffer) const buffer.putLongLong(lastUpdatedTime); buffer.putLongLong(createTime); buffer.putLongLong(destroyTime); - objectId->encode(buffer); + objectId->impl->encode(buffer); } void ObjectImpl::encodeProperties(qpid::framing::Buffer& buffer) const @@ -196,7 +217,7 @@ void ObjectImpl::encodeStatistics(qpid::framing::Buffer& buffer) const // Wrappers //================================================================== -Object::Object(const SchemaObjectClass* type) : impl(new ObjectImpl(this, type)) {} +Object::Object(const SchemaObjectClass* type) : impl(new ObjectImpl(type)) {} Object::Object(ObjectImpl* i) : impl(i) {} Object::Object(const Object& from) : impl(new ObjectImpl(*(from.impl))) {} Object::~Object() { delete impl; } @@ -204,5 +225,8 @@ void Object::destroy() { impl->destroy(); } const ObjectId* Object::getObjectId() const { return impl->getObjectId(); } void Object::setObjectId(ObjectId* oid) { impl->setObjectId(oid); } const SchemaObjectClass* Object::getClass() const { return impl->getClass(); } -Value* Object::getValue(char* key) const { return impl->getValue(key); } +Value* Object::getValue(const char* key) const { return impl->getValue(key); } +void Object::invokeMethod(const char* m, const Value* a, void* c) const { impl->invokeMethod(m, a, c); } +bool Object::isDeleted() const { return impl->isDeleted(); } +void Object::merge(const Object& from) { impl->merge(from); } diff --git a/qpid/cpp/src/qmf/ObjectImpl.h b/qpid/cpp/src/qmf/engine/ObjectImpl.h index d69979e0da..ddd20bfea2 100644 --- a/qpid/cpp/src/qmf/ObjectImpl.h +++ b/qpid/cpp/src/qmf/engine/ObjectImpl.h @@ -1,5 +1,5 @@ -#ifndef _QmfObjectImpl_ -#define _QmfObjectImpl_ +#ifndef _QmfEngineObjectImpl_ +#define _QmfEngineObjectImpl_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,8 +20,8 @@ * under the License. */ -#include <qmf/Object.h> -#include <qmf/ObjectIdImpl.h> +#include <qmf/engine/Object.h> +#include <qmf/engine/ObjectIdImpl.h> #include <map> #include <set> #include <string> @@ -30,28 +30,38 @@ #include <qpid/sys/Mutex.h> namespace qmf { +namespace engine { + + class BrokerProxyImpl; + + typedef boost::shared_ptr<Object> ObjectPtr; struct ObjectImpl { - typedef boost::shared_ptr<ObjectImpl> Ptr; typedef boost::shared_ptr<Value> ValuePtr; - Object* envelope; const SchemaObjectClass* objectClass; - boost::shared_ptr<ObjectIdImpl> objectId; + BrokerProxyImpl* broker; + boost::shared_ptr<ObjectId> objectId; uint64_t createTime; uint64_t destroyTime; uint64_t lastUpdatedTime; mutable std::map<std::string, ValuePtr> properties; mutable std::map<std::string, ValuePtr> statistics; - ObjectImpl(Object* e, const SchemaObjectClass* type); - ObjectImpl(const SchemaObjectClass* type, qpid::framing::Buffer& buffer, bool prop, bool stat, bool managed); + ObjectImpl(const SchemaObjectClass* type); + ObjectImpl(const SchemaObjectClass* type, BrokerProxyImpl* b, qpid::framing::Buffer& buffer, + bool prop, bool stat, bool managed); + static Object* factory(const SchemaObjectClass* type, BrokerProxyImpl* b, qpid::framing::Buffer& buffer, + bool prop, bool stat, bool managed); ~ObjectImpl(); void destroy(); - const ObjectId* getObjectId() const { return objectId.get() ? objectId->envelope : 0; } - void setObjectId(ObjectId* oid) { objectId.reset(oid->impl); } + const ObjectId* getObjectId() const { return objectId.get(); } + void setObjectId(ObjectId* oid) { objectId.reset(oid); } const SchemaObjectClass* getClass() const { return objectClass; } Value* getValue(const std::string& key) const; + void invokeMethod(const std::string& methodName, const Value* inArgs, void* context) const; + bool isDeleted() const { return destroyTime != 0; } + void merge(const Object& from); void parsePresenceMasks(qpid::framing::Buffer& buffer, std::set<std::string>& excludeList); void encodeSchemaKey(qpid::framing::Buffer& buffer) const; @@ -60,6 +70,7 @@ namespace qmf { void encodeStatistics(qpid::framing::Buffer& buffer) const; }; } +} #endif diff --git a/qpid/cpp/src/qmf/Protocol.cpp b/qpid/cpp/src/qmf/engine/Protocol.cpp index 0a3beeb276..6061b70a8d 100644 --- a/qpid/cpp/src/qmf/Protocol.cpp +++ b/qpid/cpp/src/qmf/engine/Protocol.cpp @@ -17,11 +17,11 @@ * under the License. */ -#include "qmf/Protocol.h" +#include "qmf/engine/Protocol.h" #include "qpid/framing/Buffer.h" using namespace std; -using namespace qmf; +using namespace qmf::engine; using namespace qpid::framing; diff --git a/qpid/cpp/src/qmf/Protocol.h b/qpid/cpp/src/qmf/engine/Protocol.h index d5da08c1db..1cdfa60c84 100644 --- a/qpid/cpp/src/qmf/Protocol.h +++ b/qpid/cpp/src/qmf/engine/Protocol.h @@ -1,5 +1,5 @@ -#ifndef _QmfProtocol_ -#define _QmfProtocol_ +#ifndef _QmfEngineProtocol_ +#define _QmfEngineProtocol_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -29,6 +29,7 @@ namespace qpid { } namespace qmf { +namespace engine { class Protocol { public: @@ -62,6 +63,7 @@ namespace qmf { }; } +} #endif diff --git a/qpid/cpp/src/qmf/QueryImpl.cpp b/qpid/cpp/src/qmf/engine/QueryImpl.cpp index f75a9aa5d5..6f2beeee87 100644 --- a/qpid/cpp/src/qmf/QueryImpl.cpp +++ b/qpid/cpp/src/qmf/engine/QueryImpl.cpp @@ -17,13 +17,13 @@ * under the License. */ -#include "qmf/QueryImpl.h" -#include "qmf/ObjectIdImpl.h" +#include "qmf/engine/QueryImpl.h" +#include "qmf/engine/ObjectIdImpl.h" #include "qpid/framing/Buffer.h" #include "qpid/framing/FieldTable.h" using namespace std; -using namespace qmf; +using namespace qmf::engine; using namespace qpid::framing; bool QueryElementImpl::evaluate(const Object* /*object*/) const @@ -45,6 +45,12 @@ QueryImpl::QueryImpl(Buffer& buffer) // TODO } +Query* QueryImpl::factory(Buffer& buffer) +{ + QueryImpl* impl(new QueryImpl(buffer)); + return new Query(impl); +} + void QueryImpl::encode(Buffer& buffer) const { FieldTable ft; @@ -69,14 +75,17 @@ QueryElement::QueryElement(const char* attrName, const Value* value, ValueOper o QueryElement::QueryElement(QueryElementImpl* i) : impl(i) {} QueryElement::~QueryElement() { delete impl; } bool QueryElement::evaluate(const Object* object) const { return impl->evaluate(object); } + QueryExpression::QueryExpression(ExprOper oper, const QueryOperand* operand1, const QueryOperand* operand2) : impl(new QueryExpressionImpl(oper, operand1, operand2)) {} QueryExpression::QueryExpression(QueryExpressionImpl* i) : impl(i) {} QueryExpression::~QueryExpression() { delete impl; } bool QueryExpression::evaluate(const Object* object) const { return impl->evaluate(object); } + Query::Query(const char* className, const char* packageName) : impl(new QueryImpl(className, packageName)) {} Query::Query(const SchemaClassKey* key) : impl(new QueryImpl(key)) {} Query::Query(const ObjectId* oid) : impl(new QueryImpl(oid)) {} Query::Query(QueryImpl* i) : impl(i) {} +Query::Query(const Query& from) : impl(new QueryImpl(*(from.impl))) {} Query::~Query() { delete impl; } void Query::setSelect(const QueryOperand* criterion) { impl->setSelect(criterion); } void Query::setLimit(uint32_t maxResults) { impl->setLimit(maxResults); } diff --git a/qpid/cpp/src/qmf/QueryImpl.h b/qpid/cpp/src/qmf/engine/QueryImpl.h index 4a56a457c0..2c64c6739c 100644 --- a/qpid/cpp/src/qmf/QueryImpl.h +++ b/qpid/cpp/src/qmf/engine/QueryImpl.h @@ -1,5 +1,5 @@ -#ifndef _QmfQueryImpl_ -#define _QmfQueryImpl_ +#ifndef _QmfEngineQueryImpl_ +#define _QmfEngineQueryImpl_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,8 +20,8 @@ * under the License. */ -#include "qmf/Query.h" -#include "qmf/Schema.h" +#include "qmf/engine/Query.h" +#include "qmf/engine/Schema.h" #include <string> #include <boost/shared_ptr.hpp> @@ -32,41 +32,39 @@ namespace qpid { } namespace qmf { +namespace engine { struct QueryElementImpl { - QueryElementImpl(const std::string& a, const Value* v, ValueOper o) : - envelope(new QueryElement(this)), attrName(a), value(v), oper(o) {} + QueryElementImpl(const std::string& a, const Value* v, ValueOper o) : attrName(a), value(v), oper(o) {} ~QueryElementImpl() {} bool evaluate(const Object* object) const; - QueryElement* envelope; std::string attrName; const Value* value; ValueOper oper; }; struct QueryExpressionImpl { - QueryExpressionImpl(ExprOper o, const QueryOperand* operand1, const QueryOperand* operand2) : - envelope(new QueryExpression(this)), oper(o), left(operand1), right(operand2) {} + QueryExpressionImpl(ExprOper o, const QueryOperand* operand1, const QueryOperand* operand2) : oper(o), left(operand1), right(operand2) {} ~QueryExpressionImpl() {} bool evaluate(const Object* object) const; - QueryExpression* envelope; ExprOper oper; const QueryOperand* left; const QueryOperand* right; }; struct QueryImpl { - QueryImpl(Query* e) : envelope(e), select(0) {} - QueryImpl(const std::string& c, const std::string& p) : - envelope(new Query(this)), packageName(p), className(c) {} - QueryImpl(const SchemaClassKey* key) : - envelope(new Query(this)), packageName(key->getPackageName()), className(key->getClassName()) {} - QueryImpl(const ObjectId* oid) : - envelope(new Query(this)), oid(new ObjectId(*oid)) {} + // Constructors mapped to public + QueryImpl(const std::string& c, const std::string& p) : packageName(p), className(c), select(0), resultLimit(0) {} + QueryImpl(const SchemaClassKey* key) : packageName(key->getPackageName()), className(key->getClassName()), select(0), resultLimit(0) {} + QueryImpl(const ObjectId* oid) : oid(new ObjectId(*oid)), select(0), resultLimit(0) {} + + // Factory constructors QueryImpl(qpid::framing::Buffer& buffer); + ~QueryImpl() {}; + static Query* factory(qpid::framing::Buffer& buffer); void setSelect(const QueryOperand* criterion) { select = criterion; } void setLimit(uint32_t maxResults) { resultLimit = maxResults; } @@ -88,7 +86,6 @@ namespace qmf { void encode(qpid::framing::Buffer& buffer) const; - Query* envelope; std::string packageName; std::string className; boost::shared_ptr<ObjectId> oid; @@ -98,5 +95,6 @@ namespace qmf { bool orderDecreasing; }; } +} #endif diff --git a/qpid/cpp/src/qmf/ResilientConnection.cpp b/qpid/cpp/src/qmf/engine/ResilientConnection.cpp index 7ec03cf4da..9502130288 100644 --- a/qpid/cpp/src/qmf/ResilientConnection.cpp +++ b/qpid/cpp/src/qmf/engine/ResilientConnection.cpp @@ -17,9 +17,9 @@ * under the License. */ -#include "qmf/ResilientConnection.h" -#include "qmf/MessageImpl.h" -#include "qmf/ConnectionSettingsImpl.h" +#include "qmf/engine/ResilientConnection.h" +#include "qmf/engine/MessageImpl.h" +#include "qmf/engine/ConnectionSettingsImpl.h" #include <qpid/client/Connection.h> #include <qpid/client/Session.h> #include <qpid/client/MessageListener.h> @@ -38,13 +38,15 @@ #include <vector> #include <set> #include <boost/intrusive_ptr.hpp> +#include <boost/noncopyable.hpp> using namespace std; -using namespace qmf; +using namespace qmf::engine; using namespace qpid; using qpid::sys::Mutex; namespace qmf { +namespace engine { struct ResilientConnectionEventImpl { ResilientConnectionEvent::EventKind kind; void* sessionContext; @@ -64,20 +66,19 @@ namespace qmf { client::Connection& connection; client::Session session; client::SubscriptionManager* subscriptions; + string userId; void* userContext; vector<string> dests; qpid::sys::Thread thread; - RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc) : - connImpl(ci), name(n), connection(c), session(connection.newSession(name)), - subscriptions(new client::SubscriptionManager(session)), userContext(uc), thread(*this) {} + RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc); ~RCSession(); void received(client::Message& msg); void run(); void stop(); }; - class ResilientConnectionImpl : public qpid::sys::Runnable { + class ResilientConnectionImpl : public qpid::sys::Runnable, public boost::noncopyable { public: ResilientConnectionImpl(const ConnectionSettings& settings); ~ResilientConnectionImpl(); @@ -87,7 +88,7 @@ namespace qmf { void popEvent(); bool createSession(const char* name, void* sessionContext, SessionHandle& handle); void destroySession(SessionHandle handle); - void sendMessage(SessionHandle handle, qmf::Message& message); + void sendMessage(SessionHandle handle, qmf::engine::Message& message); void declareQueue(SessionHandle handle, char* queue); void deleteQueue(SessionHandle handle, char* queue); void bind(SessionHandle handle, char* exchange, char* queue, char* key); @@ -120,6 +121,7 @@ namespace qmf { set<RCSession::Ptr> sessions; }; } +} ResilientConnectionEvent ResilientConnectionEventImpl::copy() { @@ -134,6 +136,14 @@ ResilientConnectionEvent ResilientConnectionEventImpl::copy() return item; } +RCSession::RCSession(ResilientConnectionImpl& ci, const string& n, client::Connection& c, void* uc) : + connImpl(ci), name(n), connection(c), session(connection.newSession(name)), + subscriptions(new client::SubscriptionManager(session)), userContext(uc), thread(*this) +{ + const qpid::client::ConnectionSettings& operSettings = connection.getNegotiatedSettings(); + userId = operSettings.username; +} + RCSession::~RCSession() { subscriptions->stop(); @@ -158,18 +168,23 @@ void RCSession::stop() void RCSession::received(client::Message& msg) { - qmf::MessageImpl qmsg; + MessageImpl qmsg; qmsg.body = msg.getData(); - qpid::framing::MessageProperties p = msg.getMessageProperties(); - if (p.hasReplyTo()) { - const qpid::framing::ReplyTo& rt = p.getReplyTo(); + qpid::framing::DeliveryProperties dp = msg.getDeliveryProperties(); + if (dp.hasRoutingKey()) { + qmsg.routingKey = dp.getRoutingKey(); + } + + qpid::framing::MessageProperties mp = msg.getMessageProperties(); + if (mp.hasReplyTo()) { + const qpid::framing::ReplyTo& rt = mp.getReplyTo(); qmsg.replyExchange = rt.getExchange(); qmsg.replyKey = rt.getRoutingKey(); } - if (p.hasUserId()) { - qmsg.userId = p.getUserId(); + if (mp.hasUserId()) { + qmsg.userId = mp.getUserId(); } connImpl.EnqueueEvent(ResilientConnectionEvent::RECV, userContext, qmsg); @@ -244,7 +259,7 @@ void ResilientConnectionImpl::destroySession(SessionHandle handle) } } -void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& message) +void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::engine::Message& message) { Mutex::ScopedLock _lock(lock); RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl); @@ -253,6 +268,8 @@ void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::Message& me string data(message.body, message.length); msg.getDeliveryProperties().setRoutingKey(message.routingKey); msg.getMessageProperties().setReplyTo(qpid::framing::ReplyTo(message.replyExchange, message.replyKey)); + if (settings.impl->getSendUserId()) + msg.getMessageProperties().setUserId(sess->userId); msg.setData(data); try { @@ -383,7 +400,7 @@ void ResilientConnectionImpl::sessionClosed(RCSession*) void ResilientConnectionImpl::EnqueueEvent(ResilientConnectionEvent::EventKind kind, void* sessionContext, - const qmf::MessageImpl& message, + const MessageImpl& message, const string& errorText) { Mutex::ScopedLock _lock(lock); @@ -440,7 +457,7 @@ void ResilientConnection::destroySession(SessionHandle handle) impl->destroySession(handle); } -void ResilientConnection::sendMessage(SessionHandle handle, qmf::Message& message) +void ResilientConnection::sendMessage(SessionHandle handle, qmf::engine::Message& message) { impl->sendMessage(handle, message); } diff --git a/qpid/cpp/src/qmf/SchemaImpl.cpp b/qpid/cpp/src/qmf/engine/SchemaImpl.cpp index 3eb14c3952..e366a66826 100644 --- a/qpid/cpp/src/qmf/SchemaImpl.cpp +++ b/qpid/cpp/src/qmf/engine/SchemaImpl.cpp @@ -17,7 +17,7 @@ * under the License. */ -#include "qmf/SchemaImpl.h" +#include "qmf/engine/SchemaImpl.h" #include <qpid/framing/Buffer.h> #include <qpid/framing/FieldTable.h> #include <qpid/framing/Uuid.h> @@ -26,7 +26,7 @@ #include <vector> using namespace std; -using namespace qmf; +using namespace qmf::engine; using qpid::framing::Buffer; using qpid::framing::FieldTable; using qpid::framing::Uuid; @@ -81,7 +81,7 @@ bool SchemaHash::operator>(const SchemaHash& other) const return ::memcmp(&hash, &other.hash, 16) > 0; } -SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer) : envelope(new SchemaArgument(this)) +SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer) { FieldTable map; map.decode(buffer); @@ -99,6 +99,12 @@ SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer) : envelope(new SchemaArgu dir = DIR_IN_OUT; } +SchemaArgument* SchemaArgumentImpl::factory(Buffer& buffer) +{ + SchemaArgumentImpl* impl(new SchemaArgumentImpl(buffer)); + return new SchemaArgument(impl); +} + void SchemaArgumentImpl::encode(Buffer& buffer) const { FieldTable map; @@ -128,7 +134,7 @@ void SchemaArgumentImpl::updateHash(SchemaHash& hash) const hash.update(description); } -SchemaMethodImpl::SchemaMethodImpl(Buffer& buffer) : envelope(new SchemaMethod(this)) +SchemaMethodImpl::SchemaMethodImpl(Buffer& buffer) { FieldTable map; int argCount; @@ -139,11 +145,17 @@ SchemaMethodImpl::SchemaMethodImpl(Buffer& buffer) : envelope(new SchemaMethod(t description = map.getAsString("desc"); for (int idx = 0; idx < argCount; idx++) { - SchemaArgumentImpl* arg = new SchemaArgumentImpl(buffer); - addArgument(*arg->envelope); + SchemaArgument* arg = SchemaArgumentImpl::factory(buffer); + addArgument(arg); } } +SchemaMethod* SchemaMethodImpl::factory(Buffer& buffer) +{ + SchemaMethodImpl* impl(new SchemaMethodImpl(buffer)); + return new SchemaMethod(impl); +} + void SchemaMethodImpl::encode(Buffer& buffer) const { FieldTable map; @@ -154,23 +166,23 @@ void SchemaMethodImpl::encode(Buffer& buffer) const map.setString("desc", description); map.encode(buffer); - for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin(); + for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); iter != arguments.end(); iter++) - (*iter)->encode(buffer); + (*iter)->impl->encode(buffer); } -void SchemaMethodImpl::addArgument(const SchemaArgument& argument) +void SchemaMethodImpl::addArgument(const SchemaArgument* argument) { - arguments.push_back(argument.impl); + arguments.push_back(argument); } const SchemaArgument* SchemaMethodImpl::getArgument(int idx) const { int count = 0; - for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin(); + for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); iter != arguments.end(); iter++, count++) if (idx == count) - return (*iter)->envelope; + return (*iter); return 0; } @@ -178,12 +190,12 @@ void SchemaMethodImpl::updateHash(SchemaHash& hash) const { hash.update(name); hash.update(description); - for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin(); + for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); iter != arguments.end(); iter++) - (*iter)->updateHash(hash); + (*iter)->impl->updateHash(hash); } -SchemaPropertyImpl::SchemaPropertyImpl(Buffer& buffer) : envelope(new SchemaProperty(this)) +SchemaPropertyImpl::SchemaPropertyImpl(Buffer& buffer) { FieldTable map; map.decode(buffer); @@ -197,6 +209,12 @@ SchemaPropertyImpl::SchemaPropertyImpl(Buffer& buffer) : envelope(new SchemaProp description = map.getAsString("desc"); } +SchemaProperty* SchemaPropertyImpl::factory(Buffer& buffer) +{ + SchemaPropertyImpl* impl(new SchemaPropertyImpl(buffer)); + return new SchemaProperty(impl); +} + void SchemaPropertyImpl::encode(Buffer& buffer) const { FieldTable map; @@ -225,7 +243,7 @@ void SchemaPropertyImpl::updateHash(SchemaHash& hash) const hash.update(description); } -SchemaStatisticImpl::SchemaStatisticImpl(Buffer& buffer) : envelope(new SchemaStatistic(this)) +SchemaStatisticImpl::SchemaStatisticImpl(Buffer& buffer) { FieldTable map; map.decode(buffer); @@ -236,6 +254,12 @@ SchemaStatisticImpl::SchemaStatisticImpl(Buffer& buffer) : envelope(new SchemaSt description = map.getAsString("desc"); } +SchemaStatistic* SchemaStatisticImpl::factory(Buffer& buffer) +{ + SchemaStatisticImpl* impl(new SchemaStatisticImpl(buffer)); + return new SchemaStatistic(impl); +} + void SchemaStatisticImpl::encode(Buffer& buffer) const { FieldTable map; @@ -258,16 +282,26 @@ void SchemaStatisticImpl::updateHash(SchemaHash& hash) const hash.update(description); } -SchemaClassKeyImpl::SchemaClassKeyImpl(const string& p, const string& n, const SchemaHash& h) : - envelope(new SchemaClassKey(this)), package(p), name(n), hash(h) {} +SchemaClassKeyImpl::SchemaClassKeyImpl(const string& p, const string& n, const SchemaHash& h) : package(p), name(n), hash(h) {} -SchemaClassKeyImpl::SchemaClassKeyImpl(Buffer& buffer) : - envelope(new SchemaClassKey(this)), package(packageContainer), name(nameContainer), hash(hashContainer) +SchemaClassKeyImpl::SchemaClassKeyImpl(Buffer& buffer) : package(packageContainer), name(nameContainer), hash(hashContainer) { buffer.getShortString(packageContainer); buffer.getShortString(nameContainer); hashContainer.decode(buffer); -} +} + +SchemaClassKey* SchemaClassKeyImpl::factory(const string& package, const string& name, const SchemaHash& hash) +{ + SchemaClassKeyImpl* impl(new SchemaClassKeyImpl(package, name, hash)); + return new SchemaClassKey(impl); +} + +SchemaClassKey* SchemaClassKeyImpl::factory(Buffer& buffer) +{ + SchemaClassKeyImpl* impl(new SchemaClassKeyImpl(buffer)); + return new SchemaClassKey(impl); +} void SchemaClassKeyImpl::encode(Buffer& buffer) const { @@ -292,16 +326,16 @@ bool SchemaClassKeyImpl::operator<(const SchemaClassKeyImpl& other) const return hash < other.hash; } -string SchemaClassKeyImpl::str() const +const string& SchemaClassKeyImpl::str() const { Uuid printableHash(hash.get()); stringstream str; str << package << ":" << name << "(" << printableHash << ")"; - return str.str(); + repr = str.str(); + return repr; } -SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) : - envelope(new SchemaObjectClass(this)), hasHash(true), classKey(package, name, hash) +SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) : hasHash(true), classKey(SchemaClassKeyImpl::factory(package, name, hash)) { buffer.getShortString(package); buffer.getShortString(name); @@ -313,21 +347,27 @@ SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) : uint16_t methodCount = buffer.getShort(); for (uint16_t idx = 0; idx < propCount; idx++) { - SchemaPropertyImpl* property = new SchemaPropertyImpl(buffer); - addProperty(*property->envelope); + const SchemaProperty* property = SchemaPropertyImpl::factory(buffer); + addProperty(property); } for (uint16_t idx = 0; idx < statCount; idx++) { - SchemaStatisticImpl* statistic = new SchemaStatisticImpl(buffer); - addStatistic(*statistic->envelope); + const SchemaStatistic* statistic = SchemaStatisticImpl::factory(buffer); + addStatistic(statistic); } for (uint16_t idx = 0; idx < methodCount; idx++) { - SchemaMethodImpl* method = new SchemaMethodImpl(buffer); - addMethod(*method->envelope); + SchemaMethod* method = SchemaMethodImpl::factory(buffer); + addMethod(method); } } +SchemaObjectClass* SchemaObjectClassImpl::factory(Buffer& buffer) +{ + SchemaObjectClassImpl* impl(new SchemaObjectClassImpl(buffer)); + return new SchemaObjectClass(impl); +} + void SchemaObjectClassImpl::encode(Buffer& buffer) const { buffer.putOctet((uint8_t) CLASS_OBJECT); @@ -339,15 +379,15 @@ void SchemaObjectClassImpl::encode(Buffer& buffer) const buffer.putShort((uint16_t) statistics.size()); buffer.putShort((uint16_t) methods.size()); - for (vector<SchemaPropertyImpl*>::const_iterator iter = properties.begin(); + for (vector<const SchemaProperty*>::const_iterator iter = properties.begin(); iter != properties.end(); iter++) - (*iter)->encode(buffer); - for (vector<SchemaStatisticImpl*>::const_iterator iter = statistics.begin(); + (*iter)->impl->encode(buffer); + for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin(); iter != statistics.end(); iter++) - (*iter)->encode(buffer); - for (vector<SchemaMethodImpl*>::const_iterator iter = methods.begin(); + (*iter)->impl->encode(buffer); + for (vector<const SchemaMethod*>::const_iterator iter = methods.begin(); iter != methods.end(); iter++) - (*iter)->encode(buffer); + (*iter)->impl->encode(buffer); } const SchemaClassKey* SchemaObjectClassImpl::getClassKey() const @@ -356,67 +396,66 @@ const SchemaClassKey* SchemaObjectClassImpl::getClassKey() const hasHash = true; hash.update(package); hash.update(name); - for (vector<SchemaPropertyImpl*>::const_iterator iter = properties.begin(); + for (vector<const SchemaProperty*>::const_iterator iter = properties.begin(); iter != properties.end(); iter++) - (*iter)->updateHash(hash); - for (vector<SchemaStatisticImpl*>::const_iterator iter = statistics.begin(); + (*iter)->impl->updateHash(hash); + for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin(); iter != statistics.end(); iter++) - (*iter)->updateHash(hash); - for (vector<SchemaMethodImpl*>::const_iterator iter = methods.begin(); + (*iter)->impl->updateHash(hash); + for (vector<const SchemaMethod*>::const_iterator iter = methods.begin(); iter != methods.end(); iter++) - (*iter)->updateHash(hash); + (*iter)->impl->updateHash(hash); } - return classKey.envelope; + return classKey.get(); } -void SchemaObjectClassImpl::addProperty(const SchemaProperty& property) +void SchemaObjectClassImpl::addProperty(const SchemaProperty* property) { - properties.push_back(property.impl); + properties.push_back(property); } -void SchemaObjectClassImpl::addStatistic(const SchemaStatistic& statistic) +void SchemaObjectClassImpl::addStatistic(const SchemaStatistic* statistic) { - statistics.push_back(statistic.impl); + statistics.push_back(statistic); } -void SchemaObjectClassImpl::addMethod(const SchemaMethod& method) +void SchemaObjectClassImpl::addMethod(const SchemaMethod* method) { - methods.push_back(method.impl); + methods.push_back(method); } const SchemaProperty* SchemaObjectClassImpl::getProperty(int idx) const { int count = 0; - for (vector<SchemaPropertyImpl*>::const_iterator iter = properties.begin(); + for (vector<const SchemaProperty*>::const_iterator iter = properties.begin(); iter != properties.end(); iter++, count++) if (idx == count) - return (*iter)->envelope; + return *iter; return 0; } const SchemaStatistic* SchemaObjectClassImpl::getStatistic(int idx) const { int count = 0; - for (vector<SchemaStatisticImpl*>::const_iterator iter = statistics.begin(); + for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin(); iter != statistics.end(); iter++, count++) if (idx == count) - return (*iter)->envelope; + return *iter; return 0; } const SchemaMethod* SchemaObjectClassImpl::getMethod(int idx) const { int count = 0; - for (vector<SchemaMethodImpl*>::const_iterator iter = methods.begin(); + for (vector<const SchemaMethod*>::const_iterator iter = methods.begin(); iter != methods.end(); iter++, count++) if (idx == count) - return (*iter)->envelope; + return *iter; return 0; } -SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) : - envelope(new SchemaEventClass(this)), hasHash(true), classKey(package, name, hash) +SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) : hasHash(true), classKey(SchemaClassKeyImpl::factory(package, name, hash)) { buffer.getShortString(package); buffer.getShortString(name); @@ -426,11 +465,17 @@ SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) : uint16_t argCount = buffer.getShort(); for (uint16_t idx = 0; idx < argCount; idx++) { - SchemaArgumentImpl* argument = new SchemaArgumentImpl(buffer); - addArgument(*argument->envelope); + SchemaArgument* argument = SchemaArgumentImpl::factory(buffer); + addArgument(argument); } } +SchemaEventClass* SchemaEventClassImpl::factory(Buffer& buffer) +{ + SchemaEventClassImpl* impl(new SchemaEventClassImpl(buffer)); + return new SchemaEventClass(impl); +} + void SchemaEventClassImpl::encode(Buffer& buffer) const { buffer.putOctet((uint8_t) CLASS_EVENT); @@ -439,9 +484,9 @@ void SchemaEventClassImpl::encode(Buffer& buffer) const hash.encode(buffer); buffer.putShort((uint16_t) arguments.size()); - for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin(); + for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); iter != arguments.end(); iter++) - (*iter)->encode(buffer); + (*iter)->impl->encode(buffer); } const SchemaClassKey* SchemaEventClassImpl::getClassKey() const @@ -450,25 +495,25 @@ const SchemaClassKey* SchemaEventClassImpl::getClassKey() const hasHash = true; hash.update(package); hash.update(name); - for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin(); + for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); iter != arguments.end(); iter++) - (*iter)->updateHash(hash); + (*iter)->impl->updateHash(hash); } - return classKey.envelope; + return classKey.get(); } -void SchemaEventClassImpl::addArgument(const SchemaArgument& argument) +void SchemaEventClassImpl::addArgument(const SchemaArgument* argument) { - arguments.push_back(argument.impl); + arguments.push_back(argument); } const SchemaArgument* SchemaEventClassImpl::getArgument(int idx) const { int count = 0; - for (vector<SchemaArgumentImpl*>::const_iterator iter = arguments.begin(); + for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); iter != arguments.end(); iter++, count++) if (idx == count) - return (*iter)->envelope; + return (*iter); return 0; } @@ -477,8 +522,9 @@ const SchemaArgument* SchemaEventClassImpl::getArgument(int idx) const // Wrappers //================================================================== -SchemaArgument::SchemaArgument(const char* name, Typecode typecode) { impl = new SchemaArgumentImpl(this, name, typecode); } +SchemaArgument::SchemaArgument(const char* name, Typecode typecode) { impl = new SchemaArgumentImpl(name, typecode); } SchemaArgument::SchemaArgument(SchemaArgumentImpl* i) : impl(i) {} +SchemaArgument::SchemaArgument(const SchemaArgument& from) : impl(new SchemaArgumentImpl(*(from.impl))) {} SchemaArgument::~SchemaArgument() { delete impl; } void SchemaArgument::setDirection(Direction dir) { impl->setDirection(dir); } void SchemaArgument::setUnit(const char* val) { impl->setUnit(val); } @@ -488,17 +534,21 @@ 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(const char* name) : impl(new SchemaMethodImpl(name)) {} SchemaMethod::SchemaMethod(SchemaMethodImpl* i) : impl(i) {} +SchemaMethod::SchemaMethod(const SchemaMethod& from) : impl(new SchemaMethodImpl(*(from.impl))) {} SchemaMethod::~SchemaMethod() { delete impl; } -void SchemaMethod::addArgument(const SchemaArgument& argument) { impl->addArgument(argument); } +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(const char* name, Typecode typecode) : impl(new SchemaPropertyImpl(name, typecode)) {} SchemaProperty::SchemaProperty(SchemaPropertyImpl* i) : impl(i) {} +SchemaProperty::SchemaProperty(const SchemaProperty& from) : impl(new SchemaPropertyImpl(*(from.impl))) {} SchemaProperty::~SchemaProperty() { delete impl; } void SchemaProperty::setAccess(Access access) { impl->setAccess(access); } void SchemaProperty::setIndex(bool val) { impl->setIndex(val); } @@ -512,8 +562,10 @@ 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(const char* name, Typecode typecode) : impl(new SchemaStatisticImpl(name, typecode)) {} SchemaStatistic::SchemaStatistic(SchemaStatisticImpl* i) : impl(i) {} +SchemaStatistic::SchemaStatistic(const SchemaStatistic& from) : impl(new SchemaStatisticImpl(*(from.impl))) {} SchemaStatistic::~SchemaStatistic() { delete impl; } void SchemaStatistic::setUnit(const char* val) { impl->setUnit(val); } void SchemaStatistic::setDesc(const char* desc) { impl->setDesc(desc); } @@ -521,17 +573,24 @@ 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(const SchemaClassKey& from) : impl(new SchemaClassKeyImpl(*(from.impl))) {} 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); } +const char* SchemaClassKey::asString() const { return impl->str().c_str(); } +bool SchemaClassKey::operator==(const SchemaClassKey& other) const { return *impl == *(other.impl); } +bool SchemaClassKey::operator<(const SchemaClassKey& other) const { return *impl < *(other.impl); } + +SchemaObjectClass::SchemaObjectClass(const char* package, const char* name) : impl(new SchemaObjectClassImpl(package, name)) {} SchemaObjectClass::SchemaObjectClass(SchemaObjectClassImpl* i) : impl(i) {} +SchemaObjectClass::SchemaObjectClass(const SchemaObjectClass& from) : impl(new SchemaObjectClassImpl(*(from.impl))) {} 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); } +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(); } @@ -539,10 +598,12 @@ 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(const char* package, const char* name) : impl(new SchemaEventClassImpl(package, name)) {} SchemaEventClass::SchemaEventClass(SchemaEventClassImpl* i) : impl(i) {} +SchemaEventClass::SchemaEventClass(const SchemaEventClass& from) : impl(new SchemaEventClassImpl(*(from.impl))) {} SchemaEventClass::~SchemaEventClass() { delete impl; } -void SchemaEventClass::addArgument(const SchemaArgument& argument) { impl->addArgument(argument); } +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(); } diff --git a/qpid/cpp/src/qmf/SchemaImpl.h b/qpid/cpp/src/qmf/engine/SchemaImpl.h index 035d99aecd..af3a1d98e4 100644 --- a/qpid/cpp/src/qmf/SchemaImpl.h +++ b/qpid/cpp/src/qmf/engine/SchemaImpl.h @@ -1,5 +1,5 @@ -#ifndef _QmfSchemaImpl_ -#define _QmfSchemaImpl_ +#ifndef _QmfEngineSchemaImpl_ +#define _QmfEngineSchemaImpl_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,13 +20,13 @@ * under the License. */ -#include "qmf/Schema.h" -#include <boost/shared_ptr.hpp> +#include "qmf/engine/Schema.h" #include <string> #include <vector> #include <qpid/framing/Buffer.h> namespace qmf { +namespace engine { // TODO: Destructors for schema classes // TODO: Add "frozen" attribute for schema classes so they can't be modified after @@ -52,16 +52,15 @@ namespace qmf { }; struct SchemaArgumentImpl { - SchemaArgument* envelope; std::string name; Typecode typecode; Direction dir; std::string unit; std::string description; - SchemaArgumentImpl(SchemaArgument* e, const char* n, Typecode t) : - envelope(e), name(n), typecode(t), dir(DIR_IN) {} + SchemaArgumentImpl(const char* n, Typecode t) : name(n), typecode(t), dir(DIR_IN) {} SchemaArgumentImpl(qpid::framing::Buffer& buffer); + static SchemaArgument* factory(qpid::framing::Buffer& buffer); void encode(qpid::framing::Buffer& buffer) const; void setDirection(Direction d) { dir = d; } void setUnit(const char* val) { unit = val; } @@ -75,15 +74,15 @@ namespace qmf { }; struct SchemaMethodImpl { - SchemaMethod* envelope; std::string name; std::string description; - std::vector<SchemaArgumentImpl*> arguments; + std::vector<const SchemaArgument*> arguments; - SchemaMethodImpl(SchemaMethod* e, const char* n) : envelope(e), name(n) {} + SchemaMethodImpl(const char* n) : name(n) {} SchemaMethodImpl(qpid::framing::Buffer& buffer); + static SchemaMethod* factory(qpid::framing::Buffer& buffer); void encode(qpid::framing::Buffer& buffer) const; - void addArgument(const SchemaArgument& argument); + void addArgument(const SchemaArgument* argument); void setDesc(const char* desc) { description = desc; } const std::string& getName() const { return name; } const std::string& getDesc() const { return description; } @@ -93,7 +92,6 @@ namespace qmf { }; struct SchemaPropertyImpl { - SchemaProperty* envelope; std::string name; Typecode typecode; Access access; @@ -102,10 +100,9 @@ namespace qmf { std::string unit; std::string description; - SchemaPropertyImpl(SchemaProperty* e, const char* n, Typecode t) : - envelope(e), name(n), typecode(t), access(ACCESS_READ_ONLY), - index(false), optional(false) {} + SchemaPropertyImpl(const char* n, Typecode t) : name(n), typecode(t), access(ACCESS_READ_ONLY), index(false), optional(false) {} SchemaPropertyImpl(qpid::framing::Buffer& buffer); + static SchemaProperty* factory(qpid::framing::Buffer& buffer); void encode(qpid::framing::Buffer& buffer) const; void setAccess(Access a) { access = a; } void setIndex(bool val) { index = val; } @@ -123,15 +120,14 @@ namespace qmf { }; struct SchemaStatisticImpl { - SchemaStatistic* envelope; std::string name; Typecode typecode; std::string unit; std::string description; - SchemaStatisticImpl(SchemaStatistic* e, const char* n, Typecode t) : - envelope(e), name(n), typecode(t) {} + SchemaStatisticImpl(const char* n, Typecode t) : name(n), typecode(t) {} SchemaStatisticImpl(qpid::framing::Buffer& buffer); + static SchemaStatistic* factory(qpid::framing::Buffer& buffer); void encode(qpid::framing::Buffer& buffer) const; void setUnit(const char* val) { unit = val; } void setDesc(const char* desc) { description = desc; } @@ -143,10 +139,10 @@ namespace qmf { }; struct SchemaClassKeyImpl { - const SchemaClassKey* envelope; const std::string& package; const std::string& name; const SchemaHash& hash; + mutable std::string repr; // The *Container elements are only used if there isn't an external place to // store these values. @@ -156,6 +152,8 @@ namespace qmf { SchemaClassKeyImpl(const std::string& package, const std::string& name, const SchemaHash& hash); SchemaClassKeyImpl(qpid::framing::Buffer& buffer); + static SchemaClassKey* factory(const std::string& package, const std::string& name, const SchemaHash& hash); + static SchemaClassKey* factory(qpid::framing::Buffer& buffer); const std::string& getPackageName() const { return package; } const std::string& getClassName() const { return name; } @@ -164,28 +162,28 @@ namespace qmf { void encode(qpid::framing::Buffer& buffer) const; bool operator==(const SchemaClassKeyImpl& other) const; bool operator<(const SchemaClassKeyImpl& other) const; - std::string str() const; + 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; + std::auto_ptr<SchemaClassKey> classKey; + std::vector<const SchemaProperty*> properties; + std::vector<const SchemaStatistic*> statistics; + std::vector<const SchemaMethod*> methods; - SchemaObjectClassImpl(SchemaObjectClass* e, const char* p, const char* n) : - envelope(e), package(p), name(n), hasHash(false), classKey(package, name, hash) {} + SchemaObjectClassImpl(const char* p, const char* n) : + package(p), name(n), hasHash(false), classKey(SchemaClassKeyImpl::factory(package, name, hash)) {} SchemaObjectClassImpl(qpid::framing::Buffer& buffer); + static SchemaObjectClass* factory(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); + void addProperty(const SchemaProperty* property); + void addStatistic(const SchemaStatistic* statistic); + void addMethod(const SchemaMethod* method); const SchemaClassKey* getClassKey() const; int getPropertyCount() const { return properties.size(); } @@ -197,21 +195,21 @@ 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::auto_ptr<SchemaClassKey> classKey; std::string description; - std::vector<SchemaArgumentImpl*> arguments; + std::vector<const SchemaArgument*> arguments; - SchemaEventClassImpl(SchemaEventClass* e, const char* p, const char* n) : - envelope(e), package(p), name(n), hasHash(false), classKey(package, name, hash) {} + SchemaEventClassImpl(const char* p, const char* n) : + package(p), name(n), hasHash(false), classKey(SchemaClassKeyImpl::factory(package, name, hash)) {} SchemaEventClassImpl(qpid::framing::Buffer& buffer); + static SchemaEventClass* factory(qpid::framing::Buffer& buffer); + void encode(qpid::framing::Buffer& buffer) const; - void addArgument(const SchemaArgument& argument); + void addArgument(const SchemaArgument* argument); void setDesc(const char* desc) { description = desc; } const SchemaClassKey* getClassKey() const; @@ -219,6 +217,7 @@ namespace qmf { const SchemaArgument* getArgument(int idx) const; }; } +} #endif diff --git a/qpid/cpp/src/qmf/SequenceManager.cpp b/qpid/cpp/src/qmf/engine/SequenceManager.cpp index 3171e66fac..4a4644a8b9 100644 --- a/qpid/cpp/src/qmf/SequenceManager.cpp +++ b/qpid/cpp/src/qmf/engine/SequenceManager.cpp @@ -17,10 +17,10 @@ * under the License. */ -#include "qmf/SequenceManager.h" +#include "qmf/engine/SequenceManager.h" using namespace std; -using namespace qmf; +using namespace qmf::engine; using namespace qpid::sys; SequenceManager::SequenceManager() : nextSequence(1) {} @@ -68,14 +68,14 @@ void SequenceManager::releaseAll() contextMap.clear(); } -void SequenceManager::dispatch(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer) +void SequenceManager::dispatch(uint8_t opcode, uint32_t sequence, const string& routingKey, qpid::framing::Buffer& buffer) { Mutex::ScopedLock _lock(lock); bool done; if (sequence == 0) { if (unsolicitedContext.get() != 0) { - done = unsolicitedContext->handleMessage(opcode, sequence, buffer); + done = unsolicitedContext->handleMessage(opcode, sequence, routingKey, buffer); if (done) unsolicitedContext->release(); } @@ -85,7 +85,7 @@ void SequenceManager::dispatch(uint8_t opcode, uint32_t sequence, qpid::framing: map<uint32_t, SequenceContext::Ptr>::iterator iter = contextMap.find(sequence); if (iter != contextMap.end()) { if (iter->second != 0) { - done = iter->second->handleMessage(opcode, sequence, buffer); + done = iter->second->handleMessage(opcode, sequence, routingKey, buffer); if (done) { iter->second->release(); contextMap.erase(iter); diff --git a/qpid/cpp/src/qmf/SequenceManager.h b/qpid/cpp/src/qmf/engine/SequenceManager.h index bbfd0728a7..9e47e38610 100644 --- a/qpid/cpp/src/qmf/SequenceManager.h +++ b/qpid/cpp/src/qmf/engine/SequenceManager.h @@ -1,5 +1,5 @@ -#ifndef _QmfSequenceManager_ -#define _QmfSequenceManager_ +#ifndef _QmfEngineSequenceManager_ +#define _QmfEngineSequenceManager_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -31,6 +31,7 @@ namespace qpid { } namespace qmf { +namespace engine { class SequenceContext { public: @@ -39,7 +40,7 @@ namespace qmf { virtual ~SequenceContext() {} virtual void reserve() = 0; - virtual bool handleMessage(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer) = 0; + virtual bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer) = 0; virtual void release() = 0; }; @@ -51,7 +52,7 @@ namespace qmf { uint32_t reserve(SequenceContext::Ptr ctx = SequenceContext::Ptr()); void release(uint32_t sequence); void releaseAll(); - void dispatch(uint8_t opcode, uint32_t sequence, qpid::framing::Buffer& buffer); + void dispatch(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer); private: mutable qpid::sys::Mutex lock; @@ -61,6 +62,7 @@ namespace qmf { }; } +} #endif diff --git a/qpid/cpp/src/qmf/ValueImpl.cpp b/qpid/cpp/src/qmf/engine/ValueImpl.cpp index f42c85eb33..f80bdab866 100644 --- a/qpid/cpp/src/qmf/ValueImpl.cpp +++ b/qpid/cpp/src/qmf/engine/ValueImpl.cpp @@ -17,14 +17,14 @@ * under the License. */ -#include "qmf/ValueImpl.h" +#include "qmf/engine/ValueImpl.h" #include <qpid/framing/FieldTable.h> using namespace std; -using namespace qmf; +using namespace qmf::engine; using qpid::framing::Buffer; -ValueImpl::ValueImpl(Typecode t, Buffer& buf) : envelope(new Value(this)), typecode(t) +ValueImpl::ValueImpl(Typecode t, Buffer& buf) : typecode(t) { uint64_t first; uint64_t second; @@ -42,8 +42,8 @@ ValueImpl::ValueImpl(Typecode t, Buffer& buf) : envelope(new Value(this)), typec case TYPE_BOOL : value.boolVal = (buf.getOctet() != 0); break; case TYPE_FLOAT : value.floatVal = buf.getFloat(); break; case TYPE_DOUBLE : value.doubleVal = buf.getDouble(); break; - case TYPE_INT8 : value.s32 = (int32_t) buf.getOctet(); break; - case TYPE_INT16 : value.s32 = (int32_t) buf.getShort(); break; + case TYPE_INT8 : value.s32 = (int32_t) ((int8_t) buf.getOctet()); break; + case TYPE_INT16 : value.s32 = (int32_t) ((int16_t) buf.getShort()); break; case TYPE_INT32 : value.s32 = (int32_t) buf.getLong(); break; case TYPE_INT64 : value.s64 = buf.getLongLong(); break; case TYPE_UUID : buf.getBin128(value.uuidVal); break; @@ -67,11 +67,27 @@ ValueImpl::ValueImpl(Typecode t, Buffer& buf) : envelope(new Value(this)), typec } } -ValueImpl::ValueImpl(Typecode t) : envelope(new Value(this)), typecode(t) +ValueImpl::ValueImpl(Typecode t, Typecode at) : typecode(t), valid(false), arrayTypecode(at) +{ +} + +ValueImpl::ValueImpl(Typecode t) : typecode(t) { ::memset(&value, 0, sizeof(value)); } +Value* ValueImpl::factory(Typecode t, Buffer& b) +{ + ValueImpl* impl(new ValueImpl(t, b)); + return new Value(impl); +} + +Value* ValueImpl::factory(Typecode t) +{ + ValueImpl* impl(new ValueImpl(t)); + return new Value(impl); +} + ValueImpl::~ValueImpl() { } @@ -113,9 +129,9 @@ bool ValueImpl::keyInMap(const char* key) const Value* ValueImpl::byKey(const char* key) { if (keyInMap(key)) { - map<std::string, VPtr>::iterator iter = mapVal.find(key); + map<std::string, Value>::iterator iter = mapVal.find(key); if (iter != mapVal.end()) - return iter->second.get(); + return &iter->second; } return 0; } @@ -123,9 +139,9 @@ Value* ValueImpl::byKey(const char* key) const Value* ValueImpl::byKey(const char* key) const { if (keyInMap(key)) { - map<std::string, VPtr>::const_iterator iter = mapVal.find(key); + map<std::string, Value>::const_iterator iter = mapVal.find(key); if (iter != mapVal.end()) - return iter->second.get(); + return &iter->second; } return 0; } @@ -137,12 +153,13 @@ void ValueImpl::deleteKey(const char* key) void ValueImpl::insert(const char* key, Value* val) { - mapVal[key] = VPtr(val); + pair<string, Value> entry(key, *val); + mapVal.insert(entry); } const char* ValueImpl::key(uint32_t idx) const { - map<std::string, VPtr>::const_iterator iter = mapVal.begin(); + map<std::string, Value>::const_iterator iter = mapVal.begin(); for (uint32_t i = 0; i < idx; i++) { if (iter == mapVal.end()) break; @@ -186,293 +203,64 @@ void ValueImpl::deleteArrayItem(uint32_t) // Wrappers //================================================================== -Value::Value(Typecode t, Typecode at) -{ - impl = new ValueImpl(this, t, at); -} - -Value::Value(ValueImpl* i) -{ - impl = i; -} - -Value::~Value() -{ - delete impl; -} - -Typecode Value::getType() const -{ - return impl->getType(); -} - -bool Value::isNull() const -{ - return impl->isNull(); -} - -void Value::setNull() -{ - impl->setNull(); -} - -bool Value::isObjectId() const -{ - return impl->isObjectId(); -} - -const ObjectId& Value::asObjectId() const -{ - return impl->asObjectId(); -} - -void Value::setObjectId(const ObjectId& oid) -{ - impl->setObjectId(oid); -} - -bool Value::isUint() const -{ - return impl->isUint(); -} - -uint32_t Value::asUint() const -{ - return impl->asUint(); -} - -void Value::setUint(uint32_t val) -{ - impl->setUint(val); -} - -bool Value::isInt() const -{ - return impl->isInt(); -} - -int32_t Value::asInt() const -{ - return impl->asInt(); -} - -void Value::setInt(int32_t val) -{ - impl->setInt(val); -} - -bool Value::isUint64() const -{ - return impl->isUint64(); -} - -uint64_t Value::asUint64() const -{ - return impl->asUint64(); -} - -void Value::setUint64(uint64_t val) -{ - impl->setUint64(val); -} - -bool Value::isInt64() const -{ - return impl->isInt64(); -} - -int64_t Value::asInt64() const -{ - return impl->asInt64(); -} - -void Value::setInt64(int64_t val) -{ - impl->setInt64(val); -} - -bool Value::isString() const -{ - return impl->isString(); -} - -const char* Value::asString() const -{ - return impl->asString(); -} - -void Value::setString(const char* val) -{ - impl->setString(val); -} - -bool Value::isBool() const -{ - return impl->isBool(); -} - -bool Value::asBool() const -{ - return impl->asBool(); -} - -void Value::setBool(bool val) -{ - impl->setBool(val); -} - -bool Value::isFloat() const -{ - return impl->isFloat(); -} - -float Value::asFloat() const -{ - return impl->asFloat(); -} - -void Value::setFloat(float val) -{ - impl->setFloat(val); -} - -bool Value::isDouble() const -{ - return impl->isDouble(); -} - -double Value::asDouble() const -{ - return impl->asDouble(); -} - -void Value::setDouble(double val) -{ - impl->setDouble(val); -} - -bool Value::isUuid() const -{ - return impl->isUuid(); -} - -const uint8_t* Value::asUuid() const -{ - return impl->asUuid(); -} - -void Value::setUuid(const uint8_t* val) -{ - impl->setUuid(val); -} - -bool Value::isObject() const -{ - return impl->isObject(); -} - -Object* Value::asObject() const -{ - return impl->asObject(); -} - -void Value::setObject(Object* val) -{ - impl->setObject(val); -} - -bool Value::isMap() const -{ - return impl->isMap(); -} - -bool Value::keyInMap(const char* key) const -{ - return impl->keyInMap(key); -} - -Value* Value::byKey(const char* key) -{ - return impl->byKey(key); -} - -const Value* Value::byKey(const char* key) const -{ - return impl->byKey(key); -} - -void Value::deleteKey(const char* key) -{ - impl->deleteKey(key); -} - -void Value::insert(const char* key, Value* val) -{ - impl->insert(key, val); -} - -uint32_t Value::keyCount() const -{ - return impl->keyCount(); -} - -const char* Value::key(uint32_t idx) const -{ - return impl->key(idx); -} - -bool Value::isList() const -{ - return impl->isList(); -} - -uint32_t Value::listItemCount() const -{ - return impl->listItemCount(); -} - -Value* Value::listItem(uint32_t idx) -{ - return impl->listItem(idx); -} - -void Value::appendToList(Value* val) -{ - impl->appendToList(val); -} - -void Value::deleteListItem(uint32_t idx) -{ - impl->deleteListItem(idx); -} - -bool Value::isArray() const -{ - return impl->isArray(); -} - -Typecode Value::arrayType() const -{ - return impl->arrayType(); -} - -uint32_t Value::arrayItemCount() const -{ - return impl->arrayItemCount(); -} - -Value* Value::arrayItem(uint32_t idx) -{ - return impl->arrayItem(idx); -} - -void Value::appendToArray(Value* val) -{ - impl->appendToArray(val); -} - -void Value::deleteArrayItem(uint32_t idx) -{ - impl->deleteArrayItem(idx); -} +Value::Value(const Value& from) : impl(new ValueImpl(*(from.impl))) {} +Value::Value(Typecode t, Typecode at) : impl(new ValueImpl(t, at)) {} +Value::Value(ValueImpl* i) : impl(i) {} +Value::~Value() { delete impl;} + +Typecode Value::getType() const { return impl->getType(); } +bool Value::isNull() const { return impl->isNull(); } +void Value::setNull() { impl->setNull(); } +bool Value::isObjectId() const { return impl->isObjectId(); } +const ObjectId& Value::asObjectId() const { return impl->asObjectId(); } +void Value::setObjectId(const ObjectId& oid) { impl->setObjectId(oid); } +bool Value::isUint() const { return impl->isUint(); } +uint32_t Value::asUint() const { return impl->asUint(); } +void Value::setUint(uint32_t val) { impl->setUint(val); } +bool Value::isInt() const { return impl->isInt(); } +int32_t Value::asInt() const { return impl->asInt(); } +void Value::setInt(int32_t val) { impl->setInt(val); } +bool Value::isUint64() const { return impl->isUint64(); } +uint64_t Value::asUint64() const { return impl->asUint64(); } +void Value::setUint64(uint64_t val) { impl->setUint64(val); } +bool Value::isInt64() const { return impl->isInt64(); } +int64_t Value::asInt64() const { return impl->asInt64(); } +void Value::setInt64(int64_t val) { impl->setInt64(val); } +bool Value::isString() const { return impl->isString(); } +const char* Value::asString() const { return impl->asString(); } +void Value::setString(const char* val) { impl->setString(val); } +bool Value::isBool() const { return impl->isBool(); } +bool Value::asBool() const { return impl->asBool(); } +void Value::setBool(bool val) { impl->setBool(val); } +bool Value::isFloat() const { return impl->isFloat(); } +float Value::asFloat() const { return impl->asFloat(); } +void Value::setFloat(float val) { impl->setFloat(val); } +bool Value::isDouble() const { return impl->isDouble(); } +double Value::asDouble() const { return impl->asDouble(); } +void Value::setDouble(double val) { impl->setDouble(val); } +bool Value::isUuid() const { return impl->isUuid(); } +const uint8_t* Value::asUuid() const { return impl->asUuid(); } +void Value::setUuid(const uint8_t* val) { impl->setUuid(val); } +bool Value::isObject() const { return impl->isObject(); } +const Object* Value::asObject() const { return impl->asObject(); } +void Value::setObject(Object* val) { impl->setObject(val); } +bool Value::isMap() const { return impl->isMap(); } +bool Value::keyInMap(const char* key) const { return impl->keyInMap(key); } +Value* Value::byKey(const char* key) { return impl->byKey(key); } +const Value* Value::byKey(const char* key) const { return impl->byKey(key); } +void Value::deleteKey(const char* key) { impl->deleteKey(key); } +void Value::insert(const char* key, Value* val) { impl->insert(key, val); } +uint32_t Value::keyCount() const { return impl->keyCount(); } +const char* Value::key(uint32_t idx) const { return impl->key(idx); } +bool Value::isList() const { return impl->isList(); } +uint32_t Value::listItemCount() const { return impl->listItemCount(); } +Value* Value::listItem(uint32_t idx) { return impl->listItem(idx); } +void Value::appendToList(Value* val) { impl->appendToList(val); } +void Value::deleteListItem(uint32_t idx) { impl->deleteListItem(idx); } +bool Value::isArray() const { return impl->isArray(); } +Typecode Value::arrayType() const { return impl->arrayType(); } +uint32_t Value::arrayItemCount() const { return impl->arrayItemCount(); } +Value* Value::arrayItem(uint32_t idx) { return impl->arrayItem(idx); } +void Value::appendToArray(Value* val) { impl->appendToArray(val); } +void Value::deleteArrayItem(uint32_t idx) { impl->deleteArrayItem(idx); } diff --git a/qpid/cpp/src/qmf/ValueImpl.h b/qpid/cpp/src/qmf/engine/ValueImpl.h index cf33035bf7..b6adae5d93 100644 --- a/qpid/cpp/src/qmf/ValueImpl.h +++ b/qpid/cpp/src/qmf/engine/ValueImpl.h @@ -1,5 +1,5 @@ -#ifndef _QmfValueImpl_ -#define _QmfValueImpl_ +#ifndef _QmfEngineValueImpl_ +#define _QmfEngineValueImpl_ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -20,9 +20,9 @@ * under the License. */ -#include <qmf/Value.h> -#include <qmf/ObjectIdImpl.h> -#include <qmf/Object.h> +#include <qmf/engine/Value.h> +#include <qmf/engine/ObjectIdImpl.h> +#include <qmf/engine/Object.h> #include <qpid/framing/Buffer.h> #include <string> #include <string.h> @@ -31,22 +31,20 @@ #include <boost/shared_ptr.hpp> namespace qmf { +namespace engine { // TODO: set valid flag on all value settors // TODO: add a modified flag and accessors struct ValueImpl { - typedef boost::shared_ptr<Value> VPtr; - typedef boost::shared_ptr<Object> OPtr; - Value* envelope; const Typecode typecode; bool valid; ObjectId refVal; std::string stringVal; - OPtr objectVal; - std::map<std::string, VPtr> mapVal; - std::vector<VPtr> vectorVal; + std::auto_ptr<Object> objectVal; + std::map<std::string, Value> mapVal; + std::vector<Value> vectorVal; Typecode arrayTypecode; union { @@ -60,10 +58,17 @@ namespace qmf { uint8_t uuidVal[16]; } value; - ValueImpl(Value* e, Typecode t, Typecode at) : - envelope(e), typecode(t), valid(false), arrayTypecode(at) {} + ValueImpl(const ValueImpl& from) : + typecode(from.typecode), valid(from.valid), refVal(from.refVal), stringVal(from.stringVal), + objectVal(from.objectVal.get() ? new Object(*(from.objectVal)) : 0), + mapVal(from.mapVal), vectorVal(from.vectorVal), arrayTypecode(from.arrayTypecode), + value(from.value) {} + + ValueImpl(Typecode t, Typecode at); ValueImpl(Typecode t, qpid::framing::Buffer& b); ValueImpl(Typecode t); + static Value* factory(Typecode t, qpid::framing::Buffer& b); + static Value* factory(Typecode t); ~ValueImpl(); void encode(qpid::framing::Buffer& b) const; @@ -139,6 +144,7 @@ namespace qmf { void deleteArrayItem(uint32_t idx); }; } +} #endif diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp index 81519c3311..5d7a028736 100644 --- a/qpid/cpp/src/qpid/acl/AclData.cpp +++ b/qpid/cpp/src/qpid/acl/AclData.cpp @@ -18,7 +18,8 @@ #include "qpid/acl/AclData.h" #include "qpid/log/Statement.h" - +#include "qpid/sys/IntegerTypes.h" +#include <boost/lexical_cast.hpp> namespace qpid { namespace acl { @@ -57,14 +58,15 @@ AclResult AclData::lookup(const std::string& id, const Action& action, const Obj const std::string& name, std::map<Property, std::string>* params) { QPID_LOG(debug, "ACL: Lookup for id:" << id << " action:" << AclHelper::getActionStr((Action) action) - << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " name:" << name - << " with params " << AclHelper::propertyMapToString(params)); + << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " name:" << name + << " with params " << AclHelper::propertyMapToString(params)); AclResult aclresult = decisionMode; if (actionList[action] && actionList[action][objType]) { AclData::actObjItr itrRule = actionList[action][objType]->find(id); if (itrRule == actionList[action][objType]->end()) itrRule = actionList[action][objType]->find("*"); + if (itrRule != actionList[action][objType]->end()) { QPID_LOG(debug, "ACL: checking the following rules for : " << itrRule->first ); @@ -79,25 +81,48 @@ AclResult AclData::lookup(const std::string& id, const Action& action, const Obj if (pMItr->first == acl::PROP_NAME) { if (matchProp(pMItr->second, name)){ QPID_LOG(debug, "ACL: name '" << name << "' matched with name '" - << pMItr->second << "' given in the rule"); - }else{ + << pMItr->second << "' given in the rule"); + }else{ match = false; QPID_LOG(debug, "ACL: name '" << name << "' didn't match with name '" - << pMItr->second << "' given in the rule"); + << pMItr->second << "' given in the rule"); } } else if (params) { //match pMItr against params propertyMapItr paramItr = params->find(pMItr->first); if (paramItr == params->end()) { match = false; QPID_LOG(debug, "ACL: the given parameter map in lookup doesn't contain the property '" - << AclHelper::getPropertyStr(pMItr->first) << "'"); - } else if (!matchProp(pMItr->second, paramItr->second)) { + << AclHelper::getPropertyStr(pMItr->first) << "'"); + }else if ( pMItr->first == acl::PROP_MAXQUEUECOUNT || pMItr->first == acl::PROP_MAXQUEUESIZE ) { + if ( pMItr->first == paramItr->first ) { + uint64_t aclMax = boost::lexical_cast<uint64_t>(pMItr->second); + uint64_t paramMax = boost::lexical_cast<uint64_t>(paramItr->second); + QPID_LOG(debug, "ACL: Numeric comparison for property " << + AclHelper::getPropertyStr(paramItr->first) << + " (value given in lookup = " << + boost::lexical_cast<std::string>(paramItr->second) << + ", value give in rule = " << + boost::lexical_cast<std::string>(pMItr->second) << " )"); + if (( aclMax ) && ( paramMax == 0 || paramMax > aclMax)){ + match = decisionMode == qpid::acl::ALLOW ; + QPID_LOG(debug, "ACL: Limit exceeded and match=" << + (match ? "true": "false") << + " as decision mode is " << AclHelper::getAclResultStr(decisionMode)); + } + } + }else if (matchProp(pMItr->second, paramItr->second)) { + QPID_LOG(debug, "ACL: the pair(" + << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second + << ") given in lookup matched the pair(" + << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule"); + } else { QPID_LOG(debug, "ACL: the pair(" - << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second - << ") given in lookup doesn't match the pair(" - << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule"); + << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second + << ") given in lookup doesn't match the pair(" + << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule"); match = false; - } + + } } } if (match) @@ -116,37 +141,63 @@ AclResult AclData::lookup(const std::string& id, const Action& action, const Obj AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& /*Exchange*/ name, const std::string& RoutingKey) { - AclResult aclresult = decisionMode; + + QPID_LOG(debug, "ACL: Lookup for id:" << id << " action:" << AclHelper::getActionStr((Action) action) + << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " exchange name:" << name + << " with routing key " << RoutingKey); + + AclResult aclresult = decisionMode; - if (actionList[action] && actionList[action][objType]){ - AclData::actObjItr itrRule = actionList[action][objType]->find(id); - if (itrRule == actionList[action][objType]->end()) + if (actionList[action] && actionList[action][objType]){ + AclData::actObjItr itrRule = actionList[action][objType]->find(id); + + if (itrRule == actionList[action][objType]->end()) itrRule = actionList[action][objType]->find("*"); + if (itrRule != actionList[action][objType]->end() ) { + QPID_LOG(debug, "ACL: checking the following rules for : " << itrRule->first ); + //loop the vector - for (ruleSetItr i=itrRule->second.begin(); i<itrRule->second.end(); i++) { - + for (ruleSetItr i=itrRule->second.begin(); i<itrRule->second.end(); i++) { + QPID_LOG(debug, "ACL: checking rule " << i->toString()); + // loop the names looking for match bool match =true; for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++) { - //match name is exists first + //match name is exists first if (pMItr->first == acl::PROP_NAME){ - if (!matchProp(pMItr->second, name)){ - match= false; - } + if (matchProp(pMItr->second, name)){ + QPID_LOG(debug, "ACL: name '" << name << "' matched with name '" + << pMItr->second << "' given in the rule"); + + }else{ + match= false; + QPID_LOG(debug, "ACL: name '" << name << "' didn't match with name '" + << pMItr->second << "' given in the rule"); + } }else if (pMItr->first == acl::PROP_ROUTINGKEY){ - if (!matchProp(pMItr->second, RoutingKey)){ - match= false; - } + if (matchProp(pMItr->second, RoutingKey)){ + QPID_LOG(debug, "ACL: name '" << name << "' matched with routing_key '" + << pMItr->second << "' given in the rule"); + }else{ + match= false; + QPID_LOG(debug, "ACL: name '" << name << "' didn't match with routing_key '" + << pMItr->second << "' given in the rule"); + } } } - if (match) return getACLResult(i->logOnly, i->log); - } + if (match){ + aclresult = getACLResult(i->logOnly, i->log); + QPID_LOG(debug,"Successful match, the decision is:" << AclHelper::getAclResultStr(aclresult)); + return aclresult; + } + } } - } - return aclresult; + } + QPID_LOG(debug,"No successful match, defaulting to the decision mode " << AclHelper::getAclResultStr(aclresult)); + return aclresult; } diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp index 093e9cea32..f9f39316e2 100644 --- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp +++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp @@ -78,7 +78,7 @@ ManagementAgent* ManagementAgent::Singleton::getInstance() const string ManagementAgentImpl::storeMagicNumber("MA02"); ManagementAgentImpl::ManagementAgentImpl() : - interval(10), extThread(false), + interval(10), extThread(false), pipeHandle(0), initialized(false), connected(false), lastFailure("never connected"), clientWasAdded(true), requestedBrokerBank(0), requestedAgentBank(0), assignedBrokerBank(0), assignedAgentBank(0), bootSequence(0), @@ -89,13 +89,12 @@ ManagementAgentImpl::ManagementAgentImpl() : ManagementAgentImpl::~ManagementAgentImpl() { + // shutdown & cleanup all threads connThreadBody.close(); + pubThreadBody.close(); - // If the thread is doing work on the connection, we must wait for it to - // complete before shutting down. - if (!connThreadBody.isSleeping()) { - connThread.join(); - } + connThread.join(); + pubThread.join(); // Release the memory associated with stored management objects. { @@ -777,6 +776,7 @@ void ManagementAgentImpl::ConnectionThread::run() static const int delayFactor(2); int delay(delayMin); string dest("qmfagent"); + ConnectionThread::shared_ptr tmp; sessionId.generate(); queueName << "qmfagent-" << sessionId; @@ -787,7 +787,7 @@ void ManagementAgentImpl::ConnectionThread::run() QPID_LOG(debug, "QMF Agent attempting to connect to the broker..."); connection.open(agent.connectionSettings); session = connection.newSession(queueName.str()); - subscriptions = new client::SubscriptionManager(session); + subscriptions.reset(new client::SubscriptionManager(session)); session.queueDeclare(arg::queue=queueName.str(), arg::autoDelete=true, arg::exclusive=true); @@ -811,11 +811,12 @@ void ManagementAgentImpl::ConnectionThread::run() operational = false; agent.connected = false; + tmp = subscriptions; + subscriptions.reset(); } + tmp.reset(); // frees the subscription outside the lock delay = delayMin; connection.close(); - delete subscriptions; - subscriptions = 0; } } catch (exception &e) { if (delay < delayMax) @@ -824,14 +825,19 @@ void ManagementAgentImpl::ConnectionThread::run() } { + // sleep for "delay" seconds, but peridically check if the + // agent is shutting down so we don't hang for up to delayMax + // seconds during agent shutdown Mutex::ScopedLock _lock(connLock); if (shutdown) return; sleeping = true; - { - Mutex::ScopedUnlock _unlock(connLock); - ::sleep(delay); - } + int totalSleep = 0; + do { + Mutex::ScopedUnlock _unlock(connLock); + ::sleep(delayMin); + totalSleep += delayMin; + } while (totalSleep < delay && !shutdown); sleeping = false; if (shutdown) return; @@ -848,10 +854,12 @@ void ManagementAgentImpl::ConnectionThread::sendBuffer(Buffer& buf, const string& exchange, const string& routingKey) { + ConnectionThread::shared_ptr s; { Mutex::ScopedLock _lock(connLock); if (!operational) return; + s = subscriptions; } Message msg; @@ -866,8 +874,8 @@ void ManagementAgentImpl::ConnectionThread::sendBuffer(Buffer& buf, } catch(exception& e) { QPID_LOG(error, "Exception caught in sendBuffer: " << e.what()); // Bounce the connection - if (subscriptions) - subscriptions->stop(); + if (s) + s->stop(); } } @@ -881,12 +889,14 @@ void ManagementAgentImpl::ConnectionThread::bindToBank(uint32_t brokerBank, uint void ManagementAgentImpl::ConnectionThread::close() { + ConnectionThread::shared_ptr s; { Mutex::ScopedLock _lock(connLock); shutdown = true; + s = subscriptions; } - if (subscriptions) - subscriptions->stop(); + if (s) + s->stop(); } bool ManagementAgentImpl::ConnectionThread::isSleeping() const @@ -898,8 +908,13 @@ bool ManagementAgentImpl::ConnectionThread::isSleeping() const void ManagementAgentImpl::PublishThread::run() { - while (true) { + uint16_t totalSleep; + + while (!shutdown) { agent.periodicProcessing(); - ::sleep(agent.getInterval()); + totalSleep = 0; + while (totalSleep++ < agent.getInterval() && !shutdown) { + ::sleep(1); + } } } diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h index f9cad9ebf5..a876496e98 100644 --- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h +++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h @@ -163,12 +163,14 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen friend class ConnectionThread; class ConnectionThread : public sys::Runnable { + typedef boost::shared_ptr<client::SubscriptionManager> shared_ptr; + bool operational; ManagementAgentImpl& agent; framing::Uuid sessionId; client::Connection connection; client::Session session; - client::SubscriptionManager* subscriptions; + ConnectionThread::shared_ptr subscriptions; std::stringstream queueName; mutable sys::Mutex connLock; bool shutdown; @@ -176,7 +178,7 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen void run(); public: ConnectionThread(ManagementAgentImpl& _agent) : - operational(false), agent(_agent), subscriptions(0), + operational(false), agent(_agent), shutdown(false), sleeping(false) {} ~ConnectionThread(); void sendBuffer(qpid::framing::Buffer& buf, @@ -192,8 +194,11 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen { ManagementAgentImpl& agent; void run(); + bool shutdown; public: - PublishThread(ManagementAgentImpl& _agent) : agent(_agent) {} + PublishThread(ManagementAgentImpl& _agent) : + agent(_agent), shutdown(false) {} + void close() { shutdown = true; } }; ConnectionThread connThreadBody; diff --git a/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp b/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp index 96d5146c30..bf2e7d5713 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp +++ b/qpid/cpp/src/qpid/amqp_0_10/Connection.cpp @@ -31,7 +31,7 @@ namespace amqp_0_10 { using sys::Mutex; Connection::Connection(sys::OutputControl& o, const std::string& id, bool _isClient) - : frameQueueClosed(false), output(o), identifier(id), initialized(false), + : pushClosed(false), popClosed(false), output(o), identifier(id), initialized(false), isClient(_isClient), buffered(0), version(0,10) {} @@ -61,19 +61,23 @@ size_t Connection::decode(const char* buffer, size_t size) { } bool Connection::canEncode() { - if (!frameQueueClosed) connection->doOutput(); Mutex::ScopedLock l(frameQueueLock); - return (!isClient && !initialized) || !frameQueue.empty(); + if (!popClosed) { + Mutex::ScopedUnlock u(frameQueueLock); + connection->doOutput(); + } + return !popClosed && ((!isClient && !initialized) || !frameQueue.empty()); } bool Connection::isClosed() const { Mutex::ScopedLock l(frameQueueLock); - return frameQueueClosed; + return pushClosed && popClosed; } size_t Connection::encode(const char* buffer, size_t size) { { // Swap frameQueue data into workQueue to avoid holding lock while we encode. Mutex::ScopedLock l(frameQueueLock); + if (popClosed) return 0; // Can't pop any more frames. assert(workQueue.empty()); workQueue.swap(frameQueue); } @@ -102,6 +106,8 @@ size_t Connection::encode(const char* buffer, size_t size) { // Put back any frames we did not encode. frameQueue.insert(frameQueue.begin(), workQueue.begin(), workQueue.end()); workQueue.clear(); + if (frameQueue.empty() && pushClosed) + popClosed = true; } return out.getPosition(); } @@ -111,9 +117,10 @@ void Connection::activateOutput() { output.activateOutput(); } void Connection::giveReadCredit(int32_t credit) { output.giveReadCredit(credit); } void Connection::close() { - // Close the output queue. + // No more frames can be pushed onto the queue. + // Frames aleady on the queue can be popped. Mutex::ScopedLock l(frameQueueLock); - frameQueueClosed = true; + pushClosed = true; } void Connection::closed() { @@ -123,7 +130,7 @@ void Connection::closed() { void Connection::send(framing::AMQFrame& f) { { Mutex::ScopedLock l(frameQueueLock); - if (!frameQueueClosed) + if (!pushClosed) frameQueue.push_back(f); buffered += f.encodedSize(); } diff --git a/qpid/cpp/src/qpid/amqp_0_10/Connection.h b/qpid/cpp/src/qpid/amqp_0_10/Connection.h index 6fd51381fc..995d824796 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Connection.h +++ b/qpid/cpp/src/qpid/amqp_0_10/Connection.h @@ -47,7 +47,7 @@ class Connection : public sys::ConnectionCodec, FrameQueue frameQueue; FrameQueue workQueue; - bool frameQueueClosed; + bool pushClosed, popClosed; mutable sys::Mutex frameQueueLock; sys::OutputControl& output; std::auto_ptr<sys::ConnectionInputHandler> connection; diff --git a/qpid/cpp/src/qpid/broker/AclModule.h b/qpid/cpp/src/qpid/broker/AclModule.h index 536fa21b2b..2f4f7eaacc 100644 --- a/qpid/cpp/src/qpid/broker/AclModule.h +++ b/qpid/cpp/src/qpid/broker/AclModule.h @@ -40,7 +40,8 @@ enum Action {ACT_CONSUME, ACT_PUBLISH, ACT_CREATE, ACT_ACCESS, ACT_BIND, enum Property {PROP_NAME, PROP_DURABLE, PROP_OWNER, PROP_ROUTINGKEY, PROP_PASSIVE, PROP_AUTODELETE, PROP_EXCLUSIVE, PROP_TYPE, PROP_ALTERNATE, PROP_QUEUENAME, PROP_SCHEMAPACKAGE, - PROP_SCHEMACLASS}; + PROP_SCHEMACLASS, PROP_POLICYTYPE, PROP_MAXQUEUESIZE, + PROP_MAXQUEUECOUNT}; enum AclResult {ALLOW, ALLOWLOG, DENY, DENYLOG}; } // namespace acl @@ -132,6 +133,9 @@ class AclHelper { if (str.compare("queuename") == 0) return PROP_QUEUENAME; if (str.compare("schemapackage") == 0) return PROP_SCHEMAPACKAGE; if (str.compare("schemaclass") == 0) return PROP_SCHEMACLASS; + if (str.compare("policytype") == 0) return PROP_POLICYTYPE; + if (str.compare("maxqueuesize") == 0) return PROP_MAXQUEUESIZE; + if (str.compare("maxqueuecount") == 0) return PROP_MAXQUEUECOUNT; throw str; } static inline std::string getPropertyStr(const Property p) { @@ -148,6 +152,9 @@ class AclHelper { case PROP_QUEUENAME: return "queuename"; case PROP_SCHEMAPACKAGE: return "schemapackage"; case PROP_SCHEMACLASS: return "schemaclass"; + case PROP_POLICYTYPE: return "policytype"; + case PROP_MAXQUEUESIZE: return "maxqueuesize"; + case PROP_MAXQUEUECOUNT: return "maxqueuecount"; default: assert(false); // should never get here } return ""; @@ -217,11 +224,14 @@ class AclHelper { // == Queues == propSetPtr p4(new propSet); - p3->insert(PROP_ALTERNATE); - p3->insert(PROP_PASSIVE); - p3->insert(PROP_DURABLE); - p3->insert(PROP_EXCLUSIVE); - p3->insert(PROP_AUTODELETE); + p4->insert(PROP_ALTERNATE); + p4->insert(PROP_PASSIVE); + p4->insert(PROP_DURABLE); + p4->insert(PROP_EXCLUSIVE); + p4->insert(PROP_AUTODELETE); + p4->insert(PROP_POLICYTYPE); + p4->insert(PROP_MAXQUEUESIZE); + p4->insert(PROP_MAXQUEUECOUNT); actionMapPtr a1(new actionMap); a1->insert(actionPair(ACT_ACCESS, p0)); diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp index 13cf88fb11..4259bb2f31 100644 --- a/qpid/cpp/src/qpid/broker/Broker.cpp +++ b/qpid/cpp/src/qpid/broker/Broker.cpp @@ -91,7 +91,8 @@ Broker::Options::Options(const std::string& name) : queueLimit(100*1048576/*100M default limit*/), tcpNoDelay(false), requireEncrypted(false), - maxSessionRate(0) + maxSessionRate(0), + asyncQueueEvents(true) { int c = sys::SystemInfo::concurrency(); workerThreads=c+1; @@ -121,7 +122,8 @@ Broker::Options::Options(const std::string& name) : ("tcp-nodelay", optValue(tcpNoDelay), "Set TCP_NODELAY on TCP connections") ("require-encryption", optValue(requireEncrypted), "Only accept connections that are encrypted") ("known-hosts-url", optValue(knownHosts, "URL or 'none'"), "URL to send as 'known-hosts' to clients ('none' implies empty list)") - ("max-session-rate", optValue(maxSessionRate, "MESSAGES/S"), "Sets the maximum message rate per session (0=unlimited)"); + ("max-session-rate", optValue(maxSessionRate, "MESSAGES/S"), "Sets the maximum message rate per session (0=unlimited)") + ("async-queue-events", optValue(asyncQueueEvents, "yes|no"), "Set Queue Events async, used for services like replication"); } const std::string empty; @@ -150,7 +152,7 @@ Broker::Broker(const Broker::Options& conf) : *this), managementAgent(conf.enableMgmt ? new ManagementAgent() : 0), queueCleaner(queues, timer), - queueEvents(poller), + queueEvents(poller,!conf.asyncQueueEvents), recovery(true), expiryPolicy(new ExpiryPolicy), getKnownBrokers(boost::bind(&Broker::getKnownBrokersImpl, this)) @@ -208,8 +210,10 @@ Broker::Broker(const Broker::Options& conf) : (*i)->earlyInitialize(*this); // If no plugin store module registered itself, set up the null store. - if (store.get() == 0) - setStore (new NullMessageStore()); + if (store.get() == 0) { + boost::shared_ptr<MessageStore> p(new NullMessageStore()); + setStore (p); + } exchanges.declare(empty, DirectExchange::typeName); // Default exchange. @@ -296,7 +300,7 @@ boost::intrusive_ptr<Broker> Broker::create(const Options& opts) return boost::intrusive_ptr<Broker>(new Broker(opts)); } -void Broker::setStore (MessageStore* _store) +void Broker::setStore (boost::shared_ptr<MessageStore>& _store) { store.reset(new MessageStoreModule (_store)); queues.setStore (store.get()); diff --git a/qpid/cpp/src/qpid/broker/Broker.h b/qpid/cpp/src/qpid/broker/Broker.h index 0517ceca95..5ca01e0867 100644 --- a/qpid/cpp/src/qpid/broker/Broker.h +++ b/qpid/cpp/src/qpid/broker/Broker.h @@ -111,6 +111,7 @@ public: bool requireEncrypted; std::string knownHosts; uint32_t maxSessionRate; + bool asyncQueueEvents; private: std::string getHome(); @@ -171,7 +172,7 @@ public: /** Shut down the broker */ virtual void shutdown(); - QPID_BROKER_EXTERN void setStore (MessageStore*); + QPID_BROKER_EXTERN void setStore (boost::shared_ptr<MessageStore>& store); MessageStore& getStore() { return *store; } void setAcl (AclModule* _acl) {acl = _acl;} AclModule* getAcl() { return acl; } diff --git a/qpid/cpp/src/qpid/broker/DirectExchange.cpp b/qpid/cpp/src/qpid/broker/DirectExchange.cpp index b9f24dee5f..29fe47beac 100644 --- a/qpid/cpp/src/qpid/broker/DirectExchange.cpp +++ b/qpid/cpp/src/qpid/broker/DirectExchange.cpp @@ -145,39 +145,12 @@ bool DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, c void DirectExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/) { PreRoute pr(msg, this); - Queues::ConstPtr p; + ConstBindingList b; { Mutex::ScopedLock l(lock); - p = bindings[routingKey].queues.snapshot(); - } - int count(0); - - if (p) { - for(std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++, count++) { - msg.deliverTo((*i)->queue); - if ((*i)->mgmtBinding != 0) - (*i)->mgmtBinding->inc_msgMatched(); - } - } - - if(!count){ - QPID_LOG(info, "DirectExchange " << getName() << " could not route message with key " << routingKey - << "; no matching binding found"); - if (mgmtExchange != 0) { - mgmtExchange->inc_msgDrops(); - mgmtExchange->inc_byteDrops(msg.contentSize()); - } - } else { - if (mgmtExchange != 0) { - mgmtExchange->inc_msgRoutes(count); - mgmtExchange->inc_byteRoutes(count * msg.contentSize()); - } - } - - if (mgmtExchange != 0) { - mgmtExchange->inc_msgReceives(); - mgmtExchange->inc_byteReceives(msg.contentSize()); + b = bindings[routingKey].queues.snapshot(); } + doRoute(msg, b); } diff --git a/qpid/cpp/src/qpid/broker/DtxAck.cpp b/qpid/cpp/src/qpid/broker/DtxAck.cpp index b189ef4cdb..bca3f90bbe 100644 --- a/qpid/cpp/src/qpid/broker/DtxAck.cpp +++ b/qpid/cpp/src/qpid/broker/DtxAck.cpp @@ -48,12 +48,26 @@ bool DtxAck::prepare(TransactionContext* ctxt) throw() void DtxAck::commit() throw() { - for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::committed)); - pending.clear(); + try { + for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::committed)); + pending.clear(); + } catch (const std::exception& e) { + QPID_LOG(error, "Failed to commit: " << e.what()); + } catch(...) { + QPID_LOG(error, "Failed to commit (unknown error)"); + } + } void DtxAck::rollback() throw() { - for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::requeue)); - pending.clear(); + try { + for_each(pending.begin(), pending.end(), mem_fun_ref(&DeliveryRecord::requeue)); + pending.clear(); + } catch (const std::exception& e) { + QPID_LOG(error, "Failed to complete rollback: " << e.what()); + } catch(...) { + QPID_LOG(error, "Failed to complete rollback (unknown error)"); + } + } diff --git a/qpid/cpp/src/qpid/broker/Exchange.cpp b/qpid/cpp/src/qpid/broker/Exchange.cpp index 90d81b81c6..757127eef2 100644 --- a/qpid/cpp/src/qpid/broker/Exchange.cpp +++ b/qpid/cpp/src/qpid/broker/Exchange.cpp @@ -76,6 +76,40 @@ Exchange::PreRoute::~PreRoute(){ } } +void Exchange::doRoute(Deliverable& msg, ConstBindingList b) +{ + int count = 0; + + if (b.get()) { + // Block the content release if the message is transient AND there is more than one binding + if (!msg.getMessage().isPersistent() && b->size() > 1) + msg.getMessage().blockContentRelease(); + + for(std::vector<Binding::shared_ptr>::const_iterator i = b->begin(); i != b->end(); i++, count++) { + msg.deliverTo((*i)->queue); + if ((*i)->mgmtBinding != 0) + (*i)->mgmtBinding->inc_msgMatched(); + } + } + + if (mgmtExchange != 0) + { + mgmtExchange->inc_msgReceives (); + mgmtExchange->inc_byteReceives (msg.contentSize ()); + if (count == 0) + { + //QPID_LOG(warning, "Exchange " << getName() << " could not route message; no matching binding found"); + mgmtExchange->inc_msgDrops (); + mgmtExchange->inc_byteDrops (msg.contentSize ()); + } + else + { + mgmtExchange->inc_msgRoutes (count); + mgmtExchange->inc_byteRoutes (count * msg.contentSize ()); + } + } +} + void Exchange::routeIVE(){ if (ive && lastMsg.get()){ DeliverableMessage dmsg(lastMsg); diff --git a/qpid/cpp/src/qpid/broker/Exchange.h b/qpid/cpp/src/qpid/broker/Exchange.h index c1e878200f..9bea376c28 100644 --- a/qpid/cpp/src/qpid/broker/Exchange.h +++ b/qpid/cpp/src/qpid/broker/Exchange.h @@ -79,6 +79,9 @@ protected: Exchange* parent; }; + typedef boost::shared_ptr<const std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> > > ConstBindingList; + typedef boost::shared_ptr< std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> > > BindingList; + void doRoute(Deliverable& msg, ConstBindingList b); void routeIVE(); diff --git a/qpid/cpp/src/qpid/broker/FanOutExchange.cpp b/qpid/cpp/src/qpid/broker/FanOutExchange.cpp index e9007ba682..b7d46a33fe 100644 --- a/qpid/cpp/src/qpid/broker/FanOutExchange.cpp +++ b/qpid/cpp/src/qpid/broker/FanOutExchange.cpp @@ -106,36 +106,12 @@ bool FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*key*/, cons return true; } -void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/){ +void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/) +{ PreRoute pr(msg, this); - uint32_t count(0); - - BindingsArray::ConstPtr p = bindings.snapshot(); - if (p.get()){ - for(std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i, count++){ - msg.deliverTo((*i)->queue); - if ((*i)->mgmtBinding != 0) - (*i)->mgmtBinding->inc_msgMatched (); - } - } - - if (mgmtExchange != 0) - { - mgmtExchange->inc_msgReceives (); - mgmtExchange->inc_byteReceives (msg.contentSize ()); - if (count == 0) - { - mgmtExchange->inc_msgDrops (); - mgmtExchange->inc_byteDrops (msg.contentSize ()); - } - else - { - mgmtExchange->inc_msgRoutes (count); - mgmtExchange->inc_byteRoutes (count * msg.contentSize ()); - } - } + doRoute(msg, bindings.snapshot()); } - + bool FanOutExchange::isBound(Queue::shared_ptr queue, const string* const, const FieldTable* const) { BindingsArray::ConstPtr ptr = bindings.snapshot(); diff --git a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp index c628c44909..a7c90156e1 100644 --- a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp +++ b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp @@ -104,7 +104,8 @@ bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey, } -void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args){ +void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args) +{ if (!args) { //can't match if there were no headers passed in if (mgmtExchange != 0) { @@ -118,31 +119,17 @@ void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, cons PreRoute pr(msg, this); - uint32_t count(0); - - Bindings::ConstPtr p = bindings.snapshot(); - if (p.get()){ + ConstBindingList p = bindings.snapshot(); + BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >); + if (p.get()) + { for (std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i) { if (match((*i)->args, *args)) { - msg.deliverTo((*i)->queue); - count++; - if ((*i)->mgmtBinding != 0) - (*i)->mgmtBinding->inc_msgMatched(); + b->push_back(*i); } } } - - if (mgmtExchange != 0) { - mgmtExchange->inc_msgReceives(); - mgmtExchange->inc_byteReceives(msg.contentSize()); - if (count == 0) { - mgmtExchange->inc_msgDrops(); - mgmtExchange->inc_byteDrops(msg.contentSize()); - } else { - mgmtExchange->inc_msgRoutes(count); - mgmtExchange->inc_byteRoutes(count * msg.contentSize()); - } - } + doRoute(msg, b); } diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp index 7360010192..e2799b0bff 100644 --- a/qpid/cpp/src/qpid/broker/Message.cpp +++ b/qpid/cpp/src/qpid/broker/Message.cpp @@ -49,7 +49,7 @@ TransferAdapter Message::TRANSFER; Message::Message(const framing::SequenceNumber& id) : frames(id), persistenceId(0), redelivered(false), loaded(false), staged(false), forcePersistentPolicy(false), publisher(0), adapter(0), - expiration(FAR_FUTURE), enqueueCallback(0), dequeueCallback(0) {} + expiration(FAR_FUTURE), enqueueCallback(0), dequeueCallback(0), requiredCredit(0) {} Message::~Message() { @@ -98,7 +98,7 @@ const FieldTable* Message::getApplicationHeaders() const return getAdapter().getApplicationHeaders(frames); } -bool Message::isPersistent() +bool Message::isPersistent() const { return (getAdapter().isPersistent(frames) || forcePersistentPolicy); } @@ -108,12 +108,16 @@ bool Message::requiresAccept() return getAdapter().requiresAccept(frames); } -uint32_t Message::getRequiredCredit() const +uint32_t Message::getRequiredCredit() { - //add up payload for all header and content frames in the frameset - SumBodySize sum; - frames.map_if(sum, TypeFilter2<HEADER_BODY, CONTENT_BODY>()); - return sum.getSize(); + sys::Mutex::ScopedLock l(lock); + if (!requiredCredit) { + //add up payload for all header and content frames in the frameset + SumBodySize sum; + frames.map_if(sum, TypeFilter2<HEADER_BODY, CONTENT_BODY>()); + requiredCredit = sum.getSize(); + } + return requiredCredit; } void Message::encode(framing::Buffer& buffer) const @@ -181,17 +185,31 @@ void Message::decodeContent(framing::Buffer& buffer) loaded = true; } -void Message::releaseContent(MessageStore* _store) +void Message::tryReleaseContent() { - if (!store) { - store = _store; + if (checkContentReleasable()) { + releaseContent(); } +} + +void Message::releaseContent(MessageStore* s) +{ + //deprecated, use setStore(store); releaseContent(); instead + if (!store) setStore(s); + releaseContent(); +} + +void Message::releaseContent() +{ + sys::Mutex::ScopedLock l(lock); if (store) { if (!getPersistenceId()) { intrusive_ptr<PersistableMessage> pmsg(this); store->stage(pmsg); staged = true; } + //ensure required credit is cached before content frames are released + getRequiredCredit(); //remove any content frames from the frameset frames.remove(TypeFilter<CONTENT_BODY>()); setContentReleased(); @@ -211,31 +229,29 @@ void Message::destroy() bool Message::getContentFrame(const Queue& queue, AMQFrame& frame, uint16_t maxContentSize, uint64_t offset) const { - if (isContentReleased()) { - intrusive_ptr<const PersistableMessage> pmsg(this); - - bool done = false; - string& data = frame.castBody<AMQContentBody>()->getData(); - store->loadContent(queue, pmsg, data, offset, maxContentSize); - done = data.size() < maxContentSize; - frame.setBof(false); - frame.setEof(true); - QPID_LOG(debug, "loaded frame" << frame); - if (offset > 0) { - frame.setBos(false); - } - if (!done) { - frame.setEos(false); - } else return false; - return true; + intrusive_ptr<const PersistableMessage> pmsg(this); + + bool done = false; + string& data = frame.castBody<AMQContentBody>()->getData(); + store->loadContent(queue, pmsg, data, offset, maxContentSize); + done = data.size() < maxContentSize; + frame.setBof(false); + frame.setEof(true); + QPID_LOG(debug, "loaded frame" << frame); + if (offset > 0) { + frame.setBos(false); } - else return false; + if (!done) { + frame.setEos(false); + } else return false; + return true; } void Message::sendContent(const Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const { + sys::Mutex::ScopedLock l(lock); if (isContentReleased() && !frames.isComplete()) { - + sys::Mutex::ScopedUnlock u(lock); uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead(); bool morecontent = true; for (uint64_t offset = 0; morecontent; offset += maxContentSize) @@ -373,28 +389,36 @@ void Message::setReplacementMessage(boost::intrusive_ptr<Message> msg, const Que } void Message::allEnqueuesComplete() { - MessageCallback* cb = 0; - { - sys::Mutex::ScopedLock l(lock); - std::swap(cb, enqueueCallback); - } + sys::Mutex::ScopedLock l(callbackLock); + MessageCallback* cb = enqueueCallback; if (cb && *cb) (*cb)(intrusive_ptr<Message>(this)); } void Message::allDequeuesComplete() { - MessageCallback* cb = 0; - { - sys::Mutex::ScopedLock l(lock); - std::swap(cb, dequeueCallback); - } + sys::Mutex::ScopedLock l(callbackLock); + MessageCallback* cb = dequeueCallback; if (cb && *cb) (*cb)(intrusive_ptr<Message>(this)); } -void Message::setEnqueueCompleteCallback(MessageCallback& cb) { enqueueCallback = &cb; } -void Message::resetEnqueueCompleteCallback() { enqueueCallback = 0; } +void Message::setEnqueueCompleteCallback(MessageCallback& cb) { + sys::Mutex::ScopedLock l(callbackLock); + enqueueCallback = &cb; +} + +void Message::resetEnqueueCompleteCallback() { + sys::Mutex::ScopedLock l(callbackLock); + enqueueCallback = 0; +} -void Message::setDequeueCompleteCallback(MessageCallback& cb) { dequeueCallback = &cb; } -void Message::resetDequeueCompleteCallback() { dequeueCallback = 0; } +void Message::setDequeueCompleteCallback(MessageCallback& cb) { + sys::Mutex::ScopedLock l(callbackLock); + dequeueCallback = &cb; +} + +void Message::resetDequeueCompleteCallback() { + sys::Mutex::ScopedLock l(callbackLock); + dequeueCallback = 0; +} framing::FieldTable& Message::getOrInsertHeaders() { diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h index e4d09b1042..3894960c95 100644 --- a/qpid/cpp/src/qpid/broker/Message.h +++ b/qpid/cpp/src/qpid/broker/Message.h @@ -74,7 +74,7 @@ public: bool isImmediate() const; QPID_BROKER_EXTERN const framing::FieldTable* getApplicationHeaders() const; framing::FieldTable& getOrInsertHeaders(); - QPID_BROKER_EXTERN bool isPersistent(); + QPID_BROKER_EXTERN bool isPersistent() const; bool requiresAccept(); QPID_BROKER_EXTERN void setTimestamp(const boost::intrusive_ptr<ExpiryPolicy>& e); @@ -108,7 +108,7 @@ public: return frames.isA<T>(); } - uint32_t getRequiredCredit() const; + uint32_t getRequiredCredit(); void encode(framing::Buffer& buffer) const; void encodeContent(framing::Buffer& buffer) const; @@ -129,12 +129,9 @@ public: QPID_BROKER_EXTERN void decodeHeader(framing::Buffer& buffer); QPID_BROKER_EXTERN void decodeContent(framing::Buffer& buffer); - /** - * Releases the in-memory content data held by this - * message. Must pass in a store from which the data can - * be reloaded. - */ - void releaseContent(MessageStore* store); + void QPID_BROKER_EXTERN tryReleaseContent(); + void releaseContent(); + void releaseContent(MessageStore* s);//deprecated, use 'setStore(store); releaseContent();' instead void destroy(); bool getContentFrame(const Queue& queue, framing::AMQFrame& frame, uint16_t maxContentSize, uint64_t offset) const; @@ -187,8 +184,12 @@ public: mutable Replacement replacement; mutable boost::intrusive_ptr<Message> empty; + + sys::Mutex callbackLock; MessageCallback* enqueueCallback; MessageCallback* dequeueCallback; + + uint32_t requiredCredit; static std::string updateDestination; }; diff --git a/qpid/cpp/src/qpid/broker/MessageBuilder.cpp b/qpid/cpp/src/qpid/broker/MessageBuilder.cpp index 14b233fd6c..b1a2b77b05 100644 --- a/qpid/cpp/src/qpid/broker/MessageBuilder.cpp +++ b/qpid/cpp/src/qpid/broker/MessageBuilder.cpp @@ -80,7 +80,7 @@ void MessageBuilder::handle(AMQFrame& frame) && !NullMessageStore::isNullStore(store) && message->getExchangeName() != QPID_MANAGEMENT /* don't stage mgnt messages */) { - message->releaseContent(store); + message->releaseContent(); staging = true; } } @@ -96,6 +96,7 @@ void MessageBuilder::end() void MessageBuilder::start(const SequenceNumber& id) { message = intrusive_ptr<Message>(new Message(id)); + message->setStore(store); state = METHOD; staging = false; } diff --git a/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp b/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp index 0b8a5db1c7..5f7cceebd3 100644 --- a/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp +++ b/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp @@ -32,11 +32,11 @@ using qpid::framing::FieldTable; namespace qpid { namespace broker { -MessageStoreModule::MessageStoreModule(MessageStore* _store) : store(_store) {} +MessageStoreModule::MessageStoreModule(boost::shared_ptr<MessageStore>& _store) + : store(_store) {} MessageStoreModule::~MessageStoreModule() { - delete store; } bool MessageStoreModule::init(const Options*) { return true; } @@ -173,7 +173,7 @@ void MessageStoreModule::collectPreparedXids(std::set<std::string>& xids) bool MessageStoreModule::isNull() const { - return NullMessageStore::isNullStore(store); + return NullMessageStore::isNullStore(store.get()); } }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/broker/MessageStoreModule.h b/qpid/cpp/src/qpid/broker/MessageStoreModule.h index 02cbd13cf1..56b5a3c1ae 100644 --- a/qpid/cpp/src/qpid/broker/MessageStoreModule.h +++ b/qpid/cpp/src/qpid/broker/MessageStoreModule.h @@ -26,6 +26,7 @@ #include "qpid/broker/RecoveryManager.h" #include <boost/intrusive_ptr.hpp> +#include <boost/shared_ptr.hpp> namespace qpid { namespace broker { @@ -35,9 +36,9 @@ namespace broker { */ class MessageStoreModule : public MessageStore { - MessageStore* store; + boost::shared_ptr<MessageStore> store; public: - MessageStoreModule(MessageStore* store); + MessageStoreModule(boost::shared_ptr<MessageStore>& store); bool init(const Options* options); void truncateInit(const bool pushDownStoreFiles = false); diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.cpp b/qpid/cpp/src/qpid/broker/PersistableMessage.cpp index 2ef223aa81..303a0501f4 100644 --- a/qpid/cpp/src/qpid/broker/PersistableMessage.cpp +++ b/qpid/cpp/src/qpid/broker/PersistableMessage.cpp @@ -36,7 +36,6 @@ PersistableMessage::~PersistableMessage() {} PersistableMessage::PersistableMessage() : asyncEnqueueCounter(0), asyncDequeueCounter(0), - contentReleased(false), store(0) {} @@ -59,9 +58,15 @@ void PersistableMessage::flush() } } -void PersistableMessage::setContentReleased() {contentReleased = true; } +void PersistableMessage::setContentReleased() +{ + contentReleaseState.released = true; +} -bool PersistableMessage::isContentReleased()const { return contentReleased; } +bool PersistableMessage::isContentReleased() const +{ + return contentReleaseState.released; +} bool PersistableMessage::isEnqueueComplete() { sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock); @@ -153,6 +158,26 @@ void PersistableMessage::dequeueAsync() { asyncDequeueCounter++; } +PersistableMessage::ContentReleaseState::ContentReleaseState() : blocked(false), requested(false), released(false) {} + +void PersistableMessage::setStore(MessageStore* s) +{ + store = s; +} + +void PersistableMessage::requestContentRelease() +{ + contentReleaseState.requested = true; +} +void PersistableMessage::blockContentRelease() +{ + contentReleaseState.blocked = true; +} +bool PersistableMessage::checkContentReleasable() +{ + return contentReleaseState.requested && !contentReleaseState.blocked; +} + }} diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.h b/qpid/cpp/src/qpid/broker/PersistableMessage.h index 0274b41375..2576e266d2 100644 --- a/qpid/cpp/src/qpid/broker/PersistableMessage.h +++ b/qpid/cpp/src/qpid/broker/PersistableMessage.h @@ -68,8 +68,16 @@ class PersistableMessage : public Persistable void enqueueAsync(); void dequeueAsync(); - bool contentReleased; syncList synclist; + struct ContentReleaseState + { + bool blocked; + bool requested; + bool released; + + ContentReleaseState(); + }; + ContentReleaseState contentReleaseState; protected: /** Called when all enqueues are complete for this message. */ @@ -96,8 +104,15 @@ class PersistableMessage : public Persistable void flush(); - bool isContentReleased() const; - + bool QPID_BROKER_EXTERN isContentReleased() const; + + void QPID_BROKER_EXTERN setStore(MessageStore*); + void requestContentRelease(); + void blockContentRelease(); + bool checkContentReleasable(); + + virtual QPID_BROKER_EXTERN bool isPersistent() const = 0; + QPID_BROKER_EXTERN bool isEnqueueComplete(); QPID_BROKER_EXTERN void enqueueComplete(); diff --git a/qpid/cpp/src/qpid/broker/Queue.cpp b/qpid/cpp/src/qpid/broker/Queue.cpp index b2a8e223c5..86de96468d 100644 --- a/qpid/cpp/src/qpid/broker/Queue.cpp +++ b/qpid/cpp/src/qpid/broker/Queue.cpp @@ -181,6 +181,8 @@ void Queue::deliver(boost::intrusive_ptr<Message>& msg){ void Queue::recover(boost::intrusive_ptr<Message>& msg){ + if (policy.get()) policy->recoverEnqueued(msg); + push(msg, true); if (store){ // setup synclist for recovered messages, so they don't get re-stored on lastNodeFailure @@ -206,11 +208,10 @@ void Queue::process(boost::intrusive_ptr<Message>& msg){ } void Queue::requeue(const QueuedMessage& msg){ - if (!isEnqueued(msg)) return; - QueueListeners::NotificationSet copy; { Mutex::ScopedLock locker(messageLock); + if (!isEnqueued(msg)) return; msg.payload->enqueueComplete(); // mark the message as enqueued messages.push_front(msg); listeners.populate(copy); @@ -563,16 +564,10 @@ void Queue::popMsg(QueuedMessage& qmsg) } void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){ - Messages dequeues; QueueListeners::NotificationSet copy; { Mutex::ScopedLock locker(messageLock); QueuedMessage qm(this, msg, ++sequence); - if (policy.get()) { - policy->tryEnqueue(qm); - //depending on policy, may have some dequeues - if (!isRecovery) pendingDequeues.swap(dequeues); - } if (insertSeqNo) msg->getOrInsertHeaders().setInt64(seqNoKey, sequence); LVQ::iterator i; @@ -606,12 +601,11 @@ void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){ if (eventMgr) eventMgr->enqueued(qm); else QPID_LOG(warning, "Enqueue manager not set, events not generated for " << getName()); } + if (policy.get()) { + policy->enqueued(qm); + } } copy.notify(); - if (!dequeues.empty()) { - //depending on policy, may have some dequeues - for_each(dequeues.begin(), dequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1)); - } } QueuedMessage Queue::getFront() @@ -697,8 +691,19 @@ void Queue::setLastNodeFailure() } // return true if store exists, -bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg) +bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg, bool suppressPolicyCheck) { + if (policy.get() && !suppressPolicyCheck) { + Messages dequeues; + { + Mutex::ScopedLock locker(messageLock); + policy->tryEnqueue(msg); + policy->getPendingDequeues(dequeues); + } + //depending on policy, may have some dequeues that need to performed without holding the lock + for_each(dequeues.begin(), dequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1)); + } + if (inLastNodeFailure && persistLastNode){ msg->forcePersistent(); } @@ -707,15 +712,27 @@ bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg) msg->addTraceId(traceId); } - if (msg->isPersistent() && store) { + if ((msg->isPersistent() || msg->checkContentReleasable()) && store) { msg->enqueueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg); store->enqueue(ctxt, pmsg, *this); return true; } + if (!store) { + //Messages enqueued on a transient queue should be prevented + //from having their content released as it may not be + //recoverable by these queue for delivery + msg->blockContentRelease(); + } return false; } +void Queue::enqueueAborted(boost::intrusive_ptr<Message> msg) +{ + Mutex::ScopedLock locker(messageLock); + if (policy.get()) policy->enqueueAborted(msg); +} + // return true if store exists, bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg) { @@ -726,7 +743,7 @@ bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg) dequeued(msg); } } - if (msg.payload->isPersistent() && store) { + if ((msg.payload->isPersistent() || msg.payload->checkContentReleasable()) && store) { msg.payload->dequeueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg.payload); store->dequeue(ctxt, pmsg, *this); @@ -781,22 +798,37 @@ void Queue::create(const FieldTable& _settings) void Queue::configure(const FieldTable& _settings, bool recovering) { - setPolicy(QueuePolicy::createQueuePolicy(_settings)); + + eventMode = _settings.getAsInt(qpidQueueEventGeneration); + + if (QueuePolicy::getType(_settings) == QueuePolicy::FLOW_TO_DISK && + (!store || NullMessageStore::isNullStore(store) || (eventMode && eventMgr && !eventMgr->isSync()) )) { + if ( NullMessageStore::isNullStore(store)) { + QPID_LOG(warning, "Flow to disk not valid for non-persisted queue:" << getName()); + } else if (eventMgr && !eventMgr->isSync() ) { + QPID_LOG(warning, "Flow to disk not valid with async Queue Events:" << getName()); + } + FieldTable copy(_settings); + copy.erase(QueuePolicy::typeKey); + setPolicy(QueuePolicy::createQueuePolicy(getName(), copy)); + } else { + setPolicy(QueuePolicy::createQueuePolicy(getName(), _settings)); + } //set this regardless of owner to allow use of no-local with exclusive consumers also noLocal = _settings.get(qpidNoLocal); - QPID_LOG(debug, "Configured queue with no-local=" << noLocal); + QPID_LOG(debug, "Configured queue " << getName() << " with no-local=" << noLocal); lastValueQueue= _settings.get(qpidLastValueQueue); - if (lastValueQueue) QPID_LOG(debug, "Configured queue as Last Value Queue"); + if (lastValueQueue) QPID_LOG(debug, "Configured queue as Last Value Queue for: " << getName()); lastValueQueueNoBrowse = _settings.get(qpidLastValueQueueNoBrowse); if (lastValueQueueNoBrowse){ - QPID_LOG(debug, "Configured queue as Last Value Queue No Browse"); + QPID_LOG(debug, "Configured queue as Last Value Queue No Browse for: " << getName()); lastValueQueue = lastValueQueueNoBrowse; } persistLastNode= _settings.get(qpidPersistLastNode); - if (persistLastNode) QPID_LOG(debug, "Configured queue to Persist data if cluster fails to one node"); + if (persistLastNode) QPID_LOG(debug, "Configured queue to Persist data if cluster fails to one node for: " << getName()); traceId = _settings.getAsString(qpidTraceIdentity); std::string excludeList = _settings.getAsString(qpidTraceExclude); @@ -806,8 +838,6 @@ void Queue::configure(const FieldTable& _settings, bool recovering) QPID_LOG(debug, "Configured queue " << getName() << " with qpid.trace.id='" << traceId << "' and qpid.trace.exclude='"<< excludeList << "' i.e. " << traceExclude.size() << " elements"); - eventMode = _settings.getAsInt(qpidQueueEventGeneration); - FieldTable::ValuePtr p =_settings.get(qpidInsertSequenceNumbers); if (p && p->convertsTo<std::string>()) insertSequenceNumbers(p->get<std::string>()); @@ -975,19 +1005,6 @@ void Queue::setExternalQueueStore(ExternalQueueStore* inst) { } } -bool Queue::releaseMessageContent(const QueuedMessage& m) -{ - if (store && !NullMessageStore::isNullStore(store)) { - QPID_LOG(debug, "Message " << m.position << " on " << name << " released from memory"); - m.payload->releaseContent(store); - return true; - } else { - QPID_LOG(warning, "Message " << m.position << " on " << name - << " cannot be released from memory as the queue is not durable"); - return false; - } -} - ManagementObject* Queue::GetManagementObject (void) const { return (ManagementObject*) mgmtObject; @@ -1044,11 +1061,12 @@ void Queue::insertSequenceNumbers(const std::string& key) void Queue::enqueued(const QueuedMessage& m) { if (m.payload) { - if (policy.get()) policy->tryEnqueue(m); - mgntEnqStats(m.payload); - if (m.payload->isPersistent()) { - enqueue ( 0, m.payload ); + if (policy.get()) { + policy->recoverEnqueued(m.payload); + policy->enqueued(m); } + mgntEnqStats(m.payload); + enqueue ( 0, m.payload, true ); } else { QPID_LOG(warning, "Queue informed of enqueued message that has no payload"); } @@ -1059,10 +1077,4 @@ bool Queue::isEnqueued(const QueuedMessage& msg) return !policy.get() || policy->isEnqueued(msg); } -void Queue::addPendingDequeue(const QueuedMessage& msg) -{ - //assumes lock is held - true at present but rather nasty as this is a public method - pendingDequeues.push_back(msg); -} - QueueListeners& Queue::getListeners() { return listeners; } diff --git a/qpid/cpp/src/qpid/broker/Queue.h b/qpid/cpp/src/qpid/broker/Queue.h index 77799fd967..661e46f619 100644 --- a/qpid/cpp/src/qpid/broker/Queue.h +++ b/qpid/cpp/src/qpid/broker/Queue.h @@ -239,7 +239,8 @@ namespace qpid { QPID_BROKER_EXTERN void setLastNodeFailure(); QPID_BROKER_EXTERN void clearLastNodeFailure(); - bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg); + bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg, bool suppressPolicyCheck = false); + void enqueueAborted(boost::intrusive_ptr<Message> msg); /** * dequeue from store (only done once messages is acknowledged) */ @@ -315,8 +316,6 @@ namespace qpid { bindings.eachBinding(f); } - bool releaseMessageContent(const QueuedMessage&); - void popMsg(QueuedMessage& qmsg); /** Set the position sequence number for the next message on the queue. @@ -335,18 +334,6 @@ namespace qpid { */ void recoveryComplete(); - /** - * This is a hack to avoid deadlocks in durable ring - * queues. It is used for dequeueing messages in response - * to an enqueue while avoid holding lock over call to - * store. - * - * Assumes messageLock is held - true for curent use case - * (QueuePolicy::tryEnqueue()) but rather nasty as this is a public - * method - **/ - void addPendingDequeue(const QueuedMessage &msg); - // For cluster update QueueListeners& getListeners(); }; diff --git a/qpid/cpp/src/qpid/broker/QueueEvents.cpp b/qpid/cpp/src/qpid/broker/QueueEvents.cpp index 6df869673d..bba054b0b8 100644 --- a/qpid/cpp/src/qpid/broker/QueueEvents.cpp +++ b/qpid/cpp/src/qpid/broker/QueueEvents.cpp @@ -25,25 +25,41 @@ namespace qpid { namespace broker { -QueueEvents::QueueEvents(const boost::shared_ptr<sys::Poller>& poller) : - eventQueue(boost::bind(&QueueEvents::handle, this, _1), poller), enabled(true) +QueueEvents::QueueEvents(const boost::shared_ptr<sys::Poller>& poller, bool isSync) : + eventQueue(boost::bind(&QueueEvents::handle, this, _1), poller), enabled(true), sync(isSync) { - eventQueue.start(); + if (!sync) eventQueue.start(); } QueueEvents::~QueueEvents() { - eventQueue.stop(); + if (!sync) eventQueue.stop(); } void QueueEvents::enqueued(const QueuedMessage& m) { - if (enabled) eventQueue.push(Event(ENQUEUE, m)); + if (enabled) { + Event enq(ENQUEUE, m); + if (sync) { + for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++) + j->second(enq); + } else { + eventQueue.push(enq); + } + } } void QueueEvents::dequeued(const QueuedMessage& m) { - if (enabled) eventQueue.push(Event(DEQUEUE, m)); + if (enabled) { + Event deq(DEQUEUE, m); + if (sync) { + for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++) + j->second(deq); + } else { + eventQueue.push(Event(DEQUEUE, m)); + } + } } void QueueEvents::registerListener(const std::string& id, const EventListener& listener) @@ -70,15 +86,16 @@ QueueEvents::EventQueue::Batch::const_iterator QueueEvents::handle(const EventQueue::Batch& events) { qpid::sys::Mutex::ScopedLock l(lock); for (EventQueue::Batch::const_iterator i = events.begin(); i != events.end(); ++i) { - for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++) - j->second(*i); + for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++) { + j->second(*i); + } } return events.end(); } void QueueEvents::shutdown() { - if (!eventQueue.empty() && !listeners.empty()) eventQueue.shutdown(); + if (!sync && !eventQueue.empty() && !listeners.empty()) eventQueue.shutdown(); } void QueueEvents::enable() @@ -93,6 +110,12 @@ void QueueEvents::disable() QPID_LOG(debug, "Queue events disabled"); } +bool QueueEvents::isSync() +{ + return sync; +} + + QueueEvents::Event::Event(EventType t, const QueuedMessage& m) : type(t), msg(m) {} diff --git a/qpid/cpp/src/qpid/broker/QueueEvents.h b/qpid/cpp/src/qpid/broker/QueueEvents.h index 6826c6e79a..c42752133e 100644 --- a/qpid/cpp/src/qpid/broker/QueueEvents.h +++ b/qpid/cpp/src/qpid/broker/QueueEvents.h @@ -54,7 +54,7 @@ class QueueEvents typedef boost::function<void (Event)> EventListener; - QPID_BROKER_EXTERN QueueEvents(const boost::shared_ptr<sys::Poller>& poller); + QPID_BROKER_EXTERN QueueEvents(const boost::shared_ptr<sys::Poller>& poller, bool isSync = false); QPID_BROKER_EXTERN ~QueueEvents(); QPID_BROKER_EXTERN void enqueued(const QueuedMessage&); QPID_BROKER_EXTERN void dequeued(const QueuedMessage&); @@ -65,6 +65,7 @@ class QueueEvents void disable(); //process all outstanding events QPID_BROKER_EXTERN void shutdown(); + QPID_BROKER_EXTERN bool isSync(); private: typedef qpid::sys::PollableQueue<Event> EventQueue; typedef std::map<std::string, EventListener> Listeners; @@ -73,6 +74,7 @@ class QueueEvents Listeners listeners; volatile bool enabled; qpid::sys::Mutex lock;//protect listeners from concurrent access + bool sync; EventQueue::Batch::const_iterator handle(const EventQueue::Batch& e); diff --git a/qpid/cpp/src/qpid/broker/QueuePolicy.cpp b/qpid/cpp/src/qpid/broker/QueuePolicy.cpp index 39afe90134..a8aa674c53 100644 --- a/qpid/cpp/src/qpid/broker/QueuePolicy.cpp +++ b/qpid/cpp/src/qpid/broker/QueuePolicy.cpp @@ -28,8 +28,8 @@ using namespace qpid::broker; using namespace qpid::framing; -QueuePolicy::QueuePolicy(uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) : - maxCount(_maxCount), maxSize(_maxSize), type(_type), count(0), size(0), policyExceeded(false) {} +QueuePolicy::QueuePolicy(const std::string& _name, uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) : + maxCount(_maxCount), maxSize(_maxSize), type(_type), count(0), size(0), policyExceeded(false), name(_name) {} void QueuePolicy::enqueued(uint64_t _size) { @@ -39,18 +39,15 @@ void QueuePolicy::enqueued(uint64_t _size) void QueuePolicy::dequeued(uint64_t _size) { - //Note: underflow detection is not reliable in the face of - //concurrent updates (at present locking in Queue.cpp prevents - //these anyway); updates are atomic and are safe regardless. if (maxCount) { - if (count.get() > 0) { + if (count > 0) { --count; } else { throw Exception(QPID_MSG("Attempted count underflow on dequeue(" << _size << "): " << *this)); } } if (maxSize) { - if (_size > size.get()) { + if (_size > size) { throw Exception(QPID_MSG("Attempted size underflow on dequeue(" << _size << "): " << *this)); } else { size -= _size; @@ -58,47 +55,47 @@ void QueuePolicy::dequeued(uint64_t _size) } } -bool QueuePolicy::checkLimit(const QueuedMessage& m) +bool QueuePolicy::checkLimit(boost::intrusive_ptr<Message> m) { - bool sizeExceeded = maxSize && (size.get() + m.payload->contentSize()) > maxSize; - bool countExceeded = maxCount && (count.get() + 1) > maxCount; + bool sizeExceeded = maxSize && (size + m->contentSize()) > maxSize; + bool countExceeded = maxCount && (count + 1) > maxCount; bool exceeded = sizeExceeded || countExceeded; if (exceeded) { if (!policyExceeded) { - policyExceeded = true; - if (m.queue) { - if (sizeExceeded) QPID_LOG(info, "Queue cumulative message size exceeded policy for " << m.queue->getName()); - if (countExceeded) QPID_LOG(info, "Queue message count exceeded policy for " << m.queue->getName()); - } + policyExceeded = true; + if (sizeExceeded) QPID_LOG(info, "Queue cumulative message size exceeded policy for " << name); + if (countExceeded) QPID_LOG(info, "Queue message count exceeded policy for " << name); } } else { if (policyExceeded) { policyExceeded = false; - if (m.queue) { - QPID_LOG(info, "Queue cumulative message size and message count within policy for " << m.queue->getName()); - } + QPID_LOG(info, "Queue cumulative message size and message count within policy for " << name); } } return !exceeded; } -void QueuePolicy::tryEnqueue(const QueuedMessage& m) +void QueuePolicy::tryEnqueue(boost::intrusive_ptr<Message> m) { if (checkLimit(m)) { - enqueued(m); + enqueued(m->contentSize()); } else { - std::string queue = m.queue ? m.queue->getName() : std::string("unknown queue"); - throw ResourceLimitExceededException( - QPID_MSG("Policy exceeded on " << queue << " by message " << m.position - << " of size " << m.payload->contentSize() << " , policy: " << *this)); + throw ResourceLimitExceededException(QPID_MSG("Policy exceeded on " << name << ", policy: " << *this)); } } -void QueuePolicy::enqueued(const QueuedMessage& m) +void QueuePolicy::recoverEnqueued(boost::intrusive_ptr<Message> m) { - enqueued(m.payload->contentSize()); + enqueued(m->contentSize()); } +void QueuePolicy::enqueueAborted(boost::intrusive_ptr<Message> m) +{ + dequeued(m->contentSize()); +} + +void QueuePolicy::enqueued(const QueuedMessage&) {} + void QueuePolicy::dequeued(const QueuedMessage& m) { dequeued(m.payload->contentSize()); @@ -132,7 +129,7 @@ std::string QueuePolicy::getType(const FieldTable& settings) std::transform(t.begin(), t.end(), t.begin(), tolower); if (t == REJECT || t == FLOW_TO_DISK || t == RING || t == RING_STRICT) return t; } - return FLOW_TO_DISK; + return REJECT; } void QueuePolicy::setDefaultMaxSize(uint64_t s) @@ -140,6 +137,7 @@ void QueuePolicy::setDefaultMaxSize(uint64_t s) defaultMaxSize = s; } +void QueuePolicy::getPendingDequeues(Messages&) {} @@ -148,8 +146,8 @@ void QueuePolicy::encode(Buffer& buffer) const { buffer.putLong(maxCount); buffer.putLongLong(maxSize); - buffer.putLong(count.get()); - buffer.putLongLong(size.get()); + buffer.putLong(count); + buffer.putLongLong(size); } void QueuePolicy::decode ( Buffer& buffer ) @@ -179,16 +177,18 @@ const std::string QueuePolicy::RING("ring"); const std::string QueuePolicy::RING_STRICT("ring_strict"); uint64_t QueuePolicy::defaultMaxSize(0); -FlowToDiskPolicy::FlowToDiskPolicy(uint32_t _maxCount, uint64_t _maxSize) : - QueuePolicy(_maxCount, _maxSize, FLOW_TO_DISK) {} +FlowToDiskPolicy::FlowToDiskPolicy(const std::string& _name, uint32_t _maxCount, uint64_t _maxSize) : + QueuePolicy(_name, _maxCount, _maxSize, FLOW_TO_DISK) {} -bool FlowToDiskPolicy::checkLimit(const QueuedMessage& m) +bool FlowToDiskPolicy::checkLimit(boost::intrusive_ptr<Message> m) { - return QueuePolicy::checkLimit(m) || m.queue->releaseMessageContent(m); + if (!QueuePolicy::checkLimit(m)) m->requestContentRelease(); + return true; } -RingQueuePolicy::RingQueuePolicy(uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) : - QueuePolicy(_maxCount, _maxSize, _type), strict(_type == RING_STRICT) {} +RingQueuePolicy::RingQueuePolicy(const std::string& _name, + uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) : + QueuePolicy(_name, _maxCount, _maxSize, _type), strict(_type == RING_STRICT) {} bool before(const QueuedMessage& a, const QueuedMessage& b) { @@ -197,15 +197,12 @@ bool before(const QueuedMessage& a, const QueuedMessage& b) void RingQueuePolicy::enqueued(const QueuedMessage& m) { - QueuePolicy::enqueued(m); - qpid::sys::Mutex::ScopedLock l(lock); //need to insert in correct location based on position queue.insert(lower_bound(queue.begin(), queue.end(), m, before), m); } void RingQueuePolicy::dequeued(const QueuedMessage& m) { - qpid::sys::Mutex::ScopedLock l(lock); //find and remove m from queue if (find(m, pendingDequeues, true) || find(m, queue, true)) { //now update count and size @@ -215,49 +212,32 @@ void RingQueuePolicy::dequeued(const QueuedMessage& m) bool RingQueuePolicy::isEnqueued(const QueuedMessage& m) { - qpid::sys::Mutex::ScopedLock l(lock); //for non-strict ring policy, a message can be replaced (and //therefore dequeued) before it is accepted or released by //subscriber; need to detect this return find(m, pendingDequeues, false) || find(m, queue, false); } -bool RingQueuePolicy::checkLimit(const QueuedMessage& m) +bool RingQueuePolicy::checkLimit(boost::intrusive_ptr<Message> m) { if (QueuePolicy::checkLimit(m)) return true;//if haven't hit limit, ok to accept QueuedMessage oldest; - { - qpid::sys::Mutex::ScopedLock l(lock); - if (queue.empty()) { - QPID_LOG(debug, "Message too large for ring queue " - << (m.queue ? m.queue->getName() : std::string("unknown queue")) - << " [" << *this << "] " - << ": message size = " << m.payload->contentSize() << " bytes"); - return false; - } - oldest = queue.front(); + if (queue.empty()) { + QPID_LOG(debug, "Message too large for ring queue " << name + << " [" << *this << "] " + << ": message size = " << m->contentSize() << " bytes"); + return false; } + oldest = queue.front(); if (oldest.queue->acquire(oldest) || !strict) { - { - //TODO: fix this! In the current code, this method is - //only ever called with the Queue lock already taken. This - //should not be relied upon going forward however and - //clearly the locking in this class is insufficient as - //there is no guarantee that the message previously atthe - //front is still there. - qpid::sys::Mutex::ScopedLock l(lock); - queue.pop_front(); - pendingDequeues.push_back(oldest); - } - oldest.queue->addPendingDequeue(oldest); - QPID_LOG(debug, "Ring policy triggered in queue " - << (m.queue ? m.queue->getName() : std::string("unknown queue")) - << ": removed message " << oldest.position << " to make way for " << m.position); + queue.pop_front(); + pendingDequeues.push_back(oldest); + QPID_LOG(debug, "Ring policy triggered in " << name + << ": removed message " << oldest.position << " to make way for new message"); return true; } else { - QPID_LOG(debug, "Ring policy could not be triggered in queue " - << (m.queue ? m.queue->getName() : std::string("unknown queue")) + QPID_LOG(debug, "Ring policy could not be triggered in " << name << ": oldest message (seq-no=" << oldest.position << ") has been delivered but not yet acknowledged or requeued"); //in strict mode, if oldest message has been delivered (hence //cannot be acquired) but not yet acked, it should not be @@ -266,6 +246,11 @@ bool RingQueuePolicy::checkLimit(const QueuedMessage& m) } } +void RingQueuePolicy::getPendingDequeues(Messages& result) +{ + result = pendingDequeues; +} + bool RingQueuePolicy::find(const QueuedMessage& m, Messages& q, bool remove) { for (Messages::iterator i = q.begin(); i != q.end(); i++) { @@ -277,25 +262,36 @@ bool RingQueuePolicy::find(const QueuedMessage& m, Messages& q, bool remove) return false; } +std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type) +{ + return createQueuePolicy("<unspecified>", maxCount, maxSize, type); +} + std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const qpid::framing::FieldTable& settings) { + return createQueuePolicy("<unspecified>", settings); +} + +std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const std::string& name, const qpid::framing::FieldTable& settings) +{ uint32_t maxCount = getInt(settings, maxCountKey, 0); uint32_t maxSize = getInt(settings, maxSizeKey, defaultMaxSize); if (maxCount || maxSize) { - return createQueuePolicy(maxCount, maxSize, getType(settings)); + return createQueuePolicy(name, maxCount, maxSize, getType(settings)); } else { return std::auto_ptr<QueuePolicy>(); } } -std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type) +std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const std::string& name, + uint32_t maxCount, uint64_t maxSize, const std::string& type) { if (type == RING || type == RING_STRICT) { - return std::auto_ptr<QueuePolicy>(new RingQueuePolicy(maxCount, maxSize, type)); + return std::auto_ptr<QueuePolicy>(new RingQueuePolicy(name, maxCount, maxSize, type)); } else if (type == FLOW_TO_DISK) { - return std::auto_ptr<QueuePolicy>(new FlowToDiskPolicy(maxCount, maxSize)); + return std::auto_ptr<QueuePolicy>(new FlowToDiskPolicy(name, maxCount, maxSize)); } else { - return std::auto_ptr<QueuePolicy>(new QueuePolicy(maxCount, maxSize, type)); + return std::auto_ptr<QueuePolicy>(new QueuePolicy(name, maxCount, maxSize, type)); } } @@ -305,10 +301,10 @@ namespace qpid { std::ostream& operator<<(std::ostream& out, const QueuePolicy& p) { - if (p.maxSize) out << "size: max=" << p.maxSize << ", current=" << p.size.get(); + if (p.maxSize) out << "size: max=" << p.maxSize << ", current=" << p.size; else out << "size: unlimited"; out << "; "; - if (p.maxCount) out << "count: max=" << p.maxCount << ", current=" << p.count.get(); + if (p.maxCount) out << "count: max=" << p.maxCount << ", current=" << p.count; else out << "count: unlimited"; out << "; type=" << p.type; return out; diff --git a/qpid/cpp/src/qpid/broker/QueuePolicy.h b/qpid/cpp/src/qpid/broker/QueuePolicy.h index 54745876d5..b2937e94c7 100644 --- a/qpid/cpp/src/qpid/broker/QueuePolicy.h +++ b/qpid/cpp/src/qpid/broker/QueuePolicy.h @@ -40,14 +40,14 @@ class QueuePolicy uint32_t maxCount; uint64_t maxSize; const std::string type; - qpid::sys::AtomicValue<uint32_t> count; - qpid::sys::AtomicValue<uint64_t> size; + uint32_t count; + uint64_t size; bool policyExceeded; static int getInt(const qpid::framing::FieldTable& settings, const std::string& key, int defaultValue); - static std::string getType(const qpid::framing::FieldTable& settings); public: + typedef std::deque<QueuedMessage> Messages; static QPID_BROKER_EXTERN const std::string maxCountKey; static QPID_BROKER_EXTERN const std::string maxSizeKey; static QPID_BROKER_EXTERN const std::string typeKey; @@ -57,27 +57,34 @@ class QueuePolicy static QPID_BROKER_EXTERN const std::string RING_STRICT; virtual ~QueuePolicy() {} - QPID_BROKER_EXTERN void tryEnqueue(const QueuedMessage&); + QPID_BROKER_EXTERN void tryEnqueue(boost::intrusive_ptr<Message> msg); + QPID_BROKER_EXTERN void recoverEnqueued(boost::intrusive_ptr<Message> msg); + QPID_BROKER_EXTERN void enqueueAborted(boost::intrusive_ptr<Message> msg); + virtual void enqueued(const QueuedMessage&); virtual void dequeued(const QueuedMessage&); virtual bool isEnqueued(const QueuedMessage&); - virtual bool checkLimit(const QueuedMessage&); QPID_BROKER_EXTERN void update(qpid::framing::FieldTable& settings); uint32_t getMaxCount() const { return maxCount; } uint64_t getMaxSize() const { return maxSize; } void encode(framing::Buffer& buffer) const; void decode ( framing::Buffer& buffer ); uint32_t encodedSize() const; + virtual void getPendingDequeues(Messages& result); - + static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const std::string& name, const qpid::framing::FieldTable& settings); + static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT); static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const qpid::framing::FieldTable& settings); static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT); + static std::string getType(const qpid::framing::FieldTable& settings); static void setDefaultMaxSize(uint64_t); friend QPID_BROKER_EXTERN std::ostream& operator<<(std::ostream&, const QueuePolicy&); protected: - QueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT); + const std::string name; - virtual void enqueued(const QueuedMessage&); + QueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT); + + virtual bool checkLimit(boost::intrusive_ptr<Message> msg); void enqueued(uint64_t size); void dequeued(uint64_t size); }; @@ -86,21 +93,20 @@ class QueuePolicy class FlowToDiskPolicy : public QueuePolicy { public: - FlowToDiskPolicy(uint32_t maxCount, uint64_t maxSize); - bool checkLimit(const QueuedMessage&); + FlowToDiskPolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize); + bool checkLimit(boost::intrusive_ptr<Message> msg); }; class RingQueuePolicy : public QueuePolicy { public: - RingQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = RING); + RingQueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = RING); void enqueued(const QueuedMessage&); void dequeued(const QueuedMessage&); bool isEnqueued(const QueuedMessage&); - bool checkLimit(const QueuedMessage&); + bool checkLimit(boost::intrusive_ptr<Message> msg); + void getPendingDequeues(Messages& result); private: - typedef std::deque<QueuedMessage> Messages; - qpid::sys::Mutex lock; Messages pendingDequeues; Messages queue; const bool strict; diff --git a/qpid/cpp/src/qpid/broker/SemanticState.cpp b/qpid/cpp/src/qpid/broker/SemanticState.cpp index bdd5f33601..7e3090bf17 100644 --- a/qpid/cpp/src/qpid/broker/SemanticState.cpp +++ b/qpid/cpp/src/qpid/broker/SemanticState.cpp @@ -65,7 +65,7 @@ SemanticState::SemanticState(DeliveryAdapter& da, SessionContext& ss) tagGenerator("sgen"), dtxSelected(false), authMsg(getSession().getBroker().getOptions().auth && !getSession().getConnection().isFederationLink()), - userID(getSession().getConnection().getUserId().substr(0,getSession().getConnection().getUserId().find('@'))) + userID(getSession().getConnection().getUserId()) { acl = getSession().getBroker().getAcl(); } @@ -302,6 +302,18 @@ bool SemanticState::ConsumerImpl::accept(intrusive_ptr<Message> msg) return !blocked; } +namespace { +struct ConsumerName { + const SemanticState::ConsumerImpl& consumer; + ConsumerName(const SemanticState::ConsumerImpl& ci) : consumer(ci) {} +}; + +ostream& operator<<(ostream& o, const ConsumerName& pc) { + return o << pc.consumer.getName() << " on " + << pc.consumer.getParent().getSession().getSessionId(); +} +} + void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg) { uint32_t originalMsgCredit = msgCredit; @@ -312,7 +324,7 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg) if (byteCredit != 0xFFFFFFFF) { byteCredit -= msg->getRequiredCredit(); } - QPID_LOG(debug, "Credit allocated for '" << name << "' on " << parent + QPID_LOG(debug, "Credit allocated for " << ConsumerName(*this) << ", was " << " bytes: " << originalByteCredit << " msgs: " << originalMsgCredit << " now bytes: " << byteCredit << " msgs: " << msgCredit); @@ -320,15 +332,13 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg) bool SemanticState::ConsumerImpl::checkCredit(intrusive_ptr<Message>& msg) { - if (msgCredit == 0 || (byteCredit != 0xFFFFFFFF && byteCredit < msg->getRequiredCredit())) { - QPID_LOG(debug, "Not enough credit for '" << name << "' on " << parent - << ", bytes: " << byteCredit << " msgs: " << msgCredit); - return false; - } else { - QPID_LOG(debug, "Credit available for '" << name << "' on " << parent - << " bytes: " << byteCredit << " msgs: " << msgCredit); - return true; - } + bool enoughCredit = msgCredit > 0 && + (byteCredit == 0xFFFFFFFF || byteCredit >= msg->getRequiredCredit()); + QPID_LOG(debug, (enoughCredit ? "Sufficient credit for " : "Insufficient credit for ") + << ConsumerName(*this) + << ", have bytes: " << byteCredit << " msgs: " << msgCredit + << ", need " << msg->getRequiredCredit() << " bytes"); + return enoughCredit; } SemanticState::ConsumerImpl::~ConsumerImpl() {} @@ -356,6 +366,9 @@ void SemanticState::handle(intrusive_ptr<Message> msg) { } else { DeliverableMessage deliverable(msg); route(msg, deliverable); + if (msg->checkContentReleasable()) { + msg->releaseContent(); + } } } diff --git a/qpid/cpp/src/qpid/broker/SemanticState.h b/qpid/cpp/src/qpid/broker/SemanticState.h index da8383fc12..89fe7b83dd 100644 --- a/qpid/cpp/src/qpid/broker/SemanticState.h +++ b/qpid/cpp/src/qpid/broker/SemanticState.h @@ -129,6 +129,7 @@ class SemanticState : private boost::noncopyable { const framing::FieldTable& getArguments() const { return arguments; } SemanticState& getParent() { return *parent; } + const SemanticState& getParent() const { return *parent; } }; private: @@ -163,6 +164,7 @@ class SemanticState : private boost::noncopyable { ~SemanticState(); SessionContext& getSession() { return session; } + const SessionContext& getSession() const { return session; } ConsumerImpl& find(const std::string& destination); diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp index a1ad5a0a30..2ac6d66e62 100644 --- a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp +++ b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp @@ -337,6 +337,10 @@ void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string& params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? _TRUE : _FALSE))); params.insert(make_pair(acl::PROP_EXCLUSIVE, std::string(exclusive ? _TRUE : _FALSE))); params.insert(make_pair(acl::PROP_AUTODELETE, std::string(autoDelete ? _TRUE : _FALSE))); + params.insert(make_pair(acl::PROP_POLICYTYPE, arguments.getAsString("qpid.policy_type"))); + params.insert(make_pair(acl::PROP_MAXQUEUECOUNT, boost::lexical_cast<string>(arguments.getAsInt("qpid.max_count")))); + params.insert(make_pair(acl::PROP_MAXQUEUESIZE, boost::lexical_cast<string>(arguments.getAsInt64("qpid.max_size")))); + if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_QUEUE,name,¶ms) ) throw NotAllowedException(QPID_MSG("ACL denied queue create request from " << getConnection().getUserId())); } @@ -472,8 +476,7 @@ SessionAdapter::MessageHandlerImpl::subscribe(const string& queueName, AclModule* acl = getBroker().getAcl(); if (acl) - { - // add flags as needed + { if (!acl->authorise(getConnection().getUserId(),acl::ACT_CONSUME,acl::OBJ_QUEUE,queueName,NULL) ) throw NotAllowedException(QPID_MSG("ACL denied Queue subscribe request from " << getConnection().getUserId())); } diff --git a/qpid/cpp/src/qpid/broker/SessionContext.h b/qpid/cpp/src/qpid/broker/SessionContext.h index cfdbd100c3..afbbb2cc22 100644 --- a/qpid/cpp/src/qpid/broker/SessionContext.h +++ b/qpid/cpp/src/qpid/broker/SessionContext.h @@ -28,7 +28,7 @@ #include "qpid/sys/OutputControl.h" #include "qpid/broker/ConnectionState.h" #include "qpid/broker/OwnershipToken.h" - +#include "qpid/SessionId.h" #include <boost/noncopyable.hpp> @@ -45,6 +45,7 @@ class SessionContext : public OwnershipToken, public sys::OutputControl virtual framing::AMQP_ClientProxy& getProxy() = 0; virtual Broker& getBroker() = 0; virtual uint16_t getChannel() const = 0; + virtual const SessionId& getSessionId() const = 0; }; }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/broker/SessionState.h b/qpid/cpp/src/qpid/broker/SessionState.h index 67fd4f4f38..eade93ddaa 100644 --- a/qpid/cpp/src/qpid/broker/SessionState.h +++ b/qpid/cpp/src/qpid/broker/SessionState.h @@ -118,6 +118,8 @@ class SessionState : public qpid::SessionState, bool processSendCredit(uint32_t msgs); + const SessionId& getSessionId() const { return getId(); } + private: void handleCommand(framing::AMQMethodBody* method, const framing::SequenceNumber& id); diff --git a/qpid/cpp/src/qpid/broker/SignalHandler.cpp b/qpid/cpp/src/qpid/broker/SignalHandler.cpp index f4a3822554..b565cfd419 100644 --- a/qpid/cpp/src/qpid/broker/SignalHandler.cpp +++ b/qpid/cpp/src/qpid/broker/SignalHandler.cpp @@ -38,6 +38,8 @@ void SignalHandler::setBroker(const boost::intrusive_ptr<Broker>& b) { signal(SIGCHLD,SIG_IGN); } +void SignalHandler::shutdown() { shutdownHandler(0); } + void SignalHandler::shutdownHandler(int) { if (broker.get()) { broker->shutdown(); diff --git a/qpid/cpp/src/qpid/broker/SignalHandler.h b/qpid/cpp/src/qpid/broker/SignalHandler.h index d2cdfae07c..bbe831b61d 100644 --- a/qpid/cpp/src/qpid/broker/SignalHandler.h +++ b/qpid/cpp/src/qpid/broker/SignalHandler.h @@ -38,6 +38,9 @@ class SignalHandler /** Set the broker to be shutdown on signals */ static void setBroker(const boost::intrusive_ptr<Broker>& broker); + /** Initiate shut-down of broker */ + static void shutdown(); + private: static void shutdownHandler(int); static boost::intrusive_ptr<Broker> broker; diff --git a/qpid/cpp/src/qpid/broker/TopicExchange.cpp b/qpid/cpp/src/qpid/broker/TopicExchange.cpp index 6bf0b104ea..cb04742677 100644 --- a/qpid/cpp/src/qpid/broker/TopicExchange.cpp +++ b/qpid/cpp/src/qpid/broker/TopicExchange.cpp @@ -293,44 +293,23 @@ bool TopicExchange::isBound(Queue::shared_ptr queue, const string& pattern) return q != qv.end(); } -void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/){ +void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/) +{ Binding::vector mb; + BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >); PreRoute pr(msg, this); - uint32_t count(0); - { - RWlock::ScopedRlock l(lock); - for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) { - if (match(i->first, routingKey)) { - Binding::vector& qv(i->second.bindingVector); - for(Binding::vector::iterator j = qv.begin(); j != qv.end(); j++, count++){ - mb.push_back(*j); + RWlock::ScopedRlock l(lock); + for (BindingMap::iterator i = bindings.begin(); i != bindings.end(); ++i) { + if (match(i->first, routingKey)) { + Binding::vector& qv(i->second.bindingVector); + for(Binding::vector::iterator j = qv.begin(); j != qv.end(); j++){ + b->push_back(*j); + } } } } - } - - for (Binding::vector::iterator j = mb.begin(); j != mb.end(); ++j) { - msg.deliverTo((*j)->queue); - if ((*j)->mgmtBinding != 0) - (*j)->mgmtBinding->inc_msgMatched (); - } - - if (mgmtExchange != 0) - { - mgmtExchange->inc_msgReceives (); - mgmtExchange->inc_byteReceives (msg.contentSize ()); - if (count == 0) - { - mgmtExchange->inc_msgDrops (); - mgmtExchange->inc_byteDrops (msg.contentSize ()); - } - else - { - mgmtExchange->inc_msgRoutes (count); - mgmtExchange->inc_byteRoutes (count * msg.contentSize ()); - } - } + doRoute(msg, b); } bool TopicExchange::isBound(Queue::shared_ptr queue, const string* const routingKey, const FieldTable* const) diff --git a/qpid/cpp/src/qpid/broker/TxAccept.cpp b/qpid/cpp/src/qpid/broker/TxAccept.cpp index e47ac84990..928ac12c10 100644 --- a/qpid/cpp/src/qpid/broker/TxAccept.cpp +++ b/qpid/cpp/src/qpid/broker/TxAccept.cpp @@ -88,7 +88,13 @@ bool TxAccept::prepare(TransactionContext* ctxt) throw() void TxAccept::commit() throw() { - ops.commit(); + try { + ops.commit(); + } catch (const std::exception& e) { + QPID_LOG(error, "Failed to commit: " << e.what()); + } catch(...) { + QPID_LOG(error, "Failed to commit (unknown error)"); + } } void TxAccept::rollback() throw() {} diff --git a/qpid/cpp/src/qpid/broker/TxPublish.cpp b/qpid/cpp/src/qpid/broker/TxPublish.cpp index 17b99fd883..4b083033ea 100644 --- a/qpid/cpp/src/qpid/broker/TxPublish.cpp +++ b/qpid/cpp/src/qpid/broker/TxPublish.cpp @@ -26,9 +26,14 @@ using namespace qpid::broker; TxPublish::TxPublish(intrusive_ptr<Message> _msg) : msg(_msg) {} -bool TxPublish::prepare(TransactionContext* ctxt) throw(){ +bool TxPublish::prepare(TransactionContext* ctxt) throw() +{ try{ - for_each(queues.begin(), queues.end(), Prepare(ctxt, msg)); + while (!queues.empty()) { + prepare(ctxt, queues.front()); + prepared.push_back(queues.front()); + queues.pop_front(); + } return true; }catch(const std::exception& e){ QPID_LOG(error, "Failed to prepare: " << e.what()); @@ -38,11 +43,30 @@ bool TxPublish::prepare(TransactionContext* ctxt) throw(){ return false; } -void TxPublish::commit() throw(){ - for_each(queues.begin(), queues.end(), Commit(msg)); +void TxPublish::commit() throw() +{ + try { + for_each(prepared.begin(), prepared.end(), Commit(msg)); + if (msg->checkContentReleasable()) { + msg->releaseContent(); + } + } catch (const std::exception& e) { + QPID_LOG(error, "Failed to commit: " << e.what()); + } catch(...) { + QPID_LOG(error, "Failed to commit (unknown error)"); + } } -void TxPublish::rollback() throw(){ +void TxPublish::rollback() throw() +{ + try { + for_each(prepared.begin(), prepared.end(), Rollback(msg)); + } catch (const std::exception& e) { + QPID_LOG(error, "Failed to complete rollback: " << e.what()); + } catch(...) { + QPID_LOG(error, "Failed to complete rollback (unknown error)"); + } + } void TxPublish::deliverTo(const boost::shared_ptr<Queue>& queue){ @@ -54,16 +78,14 @@ void TxPublish::deliverTo(const boost::shared_ptr<Queue>& queue){ } } -TxPublish::Prepare::Prepare(TransactionContext* _ctxt, intrusive_ptr<Message>& _msg) - : ctxt(_ctxt), msg(_msg){} - -void TxPublish::Prepare::operator()(const boost::shared_ptr<Queue>& queue){ +void TxPublish::prepare(TransactionContext* ctxt, const boost::shared_ptr<Queue> queue) +{ if (!queue->enqueue(ctxt, msg)){ /** - * if not store then mark message for ack and deleivery once - * commit happens, as async IO will never set it when no store - * exists - */ + * if not store then mark message for ack and deleivery once + * commit happens, as async IO will never set it when no store + * exists + */ msg->enqueueComplete(); } } @@ -74,6 +96,12 @@ void TxPublish::Commit::operator()(const boost::shared_ptr<Queue>& queue){ queue->process(msg); } +TxPublish::Rollback::Rollback(intrusive_ptr<Message>& _msg) : msg(_msg){} + +void TxPublish::Rollback::operator()(const boost::shared_ptr<Queue>& queue){ + queue->enqueueAborted(msg); +} + uint64_t TxPublish::contentSize () { return msg->contentSize (); diff --git a/qpid/cpp/src/qpid/broker/TxPublish.h b/qpid/cpp/src/qpid/broker/TxPublish.h index d5cf5639c4..b6ab9767ab 100644 --- a/qpid/cpp/src/qpid/broker/TxPublish.h +++ b/qpid/cpp/src/qpid/broker/TxPublish.h @@ -47,23 +47,25 @@ namespace qpid { * dispatch or to be added to the in-memory queue. */ class TxPublish : public TxOp, public Deliverable{ - class Prepare{ - TransactionContext* ctxt; + + class Commit{ boost::intrusive_ptr<Message>& msg; public: - Prepare(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg); + Commit(boost::intrusive_ptr<Message>& msg); void operator()(const boost::shared_ptr<Queue>& queue); }; - - class Commit{ + class Rollback{ boost::intrusive_ptr<Message>& msg; public: - Commit(boost::intrusive_ptr<Message>& msg); + Rollback(boost::intrusive_ptr<Message>& msg); void operator()(const boost::shared_ptr<Queue>& queue); }; boost::intrusive_ptr<Message> msg; std::list<Queue::shared_ptr> queues; + std::list<Queue::shared_ptr> prepared; + + void prepare(TransactionContext* ctxt, boost::shared_ptr<Queue>); public: QPID_BROKER_EXTERN TxPublish(boost::intrusive_ptr<Message> msg); diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp index 9b2f662c8e..bb348675c6 100644 --- a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp +++ b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp @@ -257,6 +257,7 @@ void ConnectionHandler::openOk ( const Array& knownBrokers ) knownBrokersUrls.push_back(Url((*i)->get<std::string>())); if (sasl.get()) { securityLayer = sasl->getSecurityLayer(maxFrameSize); + operUserId = sasl->getUserId(); } setState(OPEN); QPID_LOG(debug, "Known-brokers for connection: " << log::formatList(knownBrokersUrls)); diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.h b/qpid/cpp/src/qpid/client/ConnectionHandler.h index b1fd5be7c3..e9cc5194ae 100644 --- a/qpid/cpp/src/qpid/client/ConnectionHandler.h +++ b/qpid/cpp/src/qpid/client/ConnectionHandler.h @@ -71,6 +71,7 @@ class ConnectionHandler : private StateManager, std::auto_ptr<Sasl> sasl; std::auto_ptr<qpid::sys::SecurityLayer> securityLayer; boost::intrusive_ptr<qpid::sys::TimerTask> rcvTimeoutTask; + std::string operUserId; void checkState(STATES s, const std::string& msg); @@ -120,6 +121,7 @@ public: std::vector<Url> knownBrokersUrls; static framing::connection::CloseCode convert(uint16_t replyCode); + const std::string& getUserId() const { return operUserId; } }; }} diff --git a/qpid/cpp/src/qpid/client/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp index 45ad819ebd..c56d6a6807 100644 --- a/qpid/cpp/src/qpid/client/ConnectionImpl.cpp +++ b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp @@ -151,6 +151,12 @@ void ConnectionImpl::open() handler.waitForOpen(); + // If the SASL layer has provided an "operational" userId for the connection, + // put it in the negotiated settings. + const std::string& userId(handler.getUserId()); + if (!userId.empty()) + handler.username = userId; + //enable security layer if one has been negotiated: std::auto_ptr<SecurityLayer> securityLayer = handler.getSecurityLayer(); if (securityLayer.get()) { diff --git a/qpid/cpp/src/qpid/client/Connector.cpp b/qpid/cpp/src/qpid/client/Connector.cpp index f69032b26d..fbb571d40a 100644 --- a/qpid/cpp/src/qpid/client/Connector.cpp +++ b/qpid/cpp/src/qpid/client/Connector.cpp @@ -51,10 +51,10 @@ using boost::str; // Stuff for the registry of protocol connectors (maybe should be moved to its own file) namespace { typedef std::map<std::string, Connector::Factory*> ProtocolRegistry; - + ProtocolRegistry& theProtocolRegistry() { static ProtocolRegistry protocolRegistry; - + return protocolRegistry; } } @@ -93,7 +93,7 @@ class TCPConnector : public Connector, public sys::Codec, private sys::Runnable size_t lastEof; // Position after last EOF in frames uint64_t currentSize; Bounds* bounds; - + framing::ProtocolVersion version; bool initiated; bool closed; @@ -118,16 +118,17 @@ class TCPConnector : public Connector, public sys::Codec, private sys::Runnable void run(); void handleClosed(); bool closeInternal(); - + + void connected(const Socket&); + void connectFailed(const std::string& msg); bool readbuff(qpid::sys::AsynchIO&, qpid::sys::AsynchIOBufferBase*); void writebuff(qpid::sys::AsynchIO&); void writeDataBlock(const framing::AMQDataBlock& data); void eof(qpid::sys::AsynchIO&); boost::weak_ptr<ConnectionImpl> impl; - + void connect(const std::string& host, int port); - void init(); void close(); void send(framing::AMQFrame& frame); void abort(); @@ -142,7 +143,6 @@ class TCPConnector : public Connector, public sys::Codec, private sys::Runnable size_t decode(const char* buffer, size_t size); size_t encode(const char* buffer, size_t size); bool canEncode(); - public: TCPConnector(framing::ProtocolVersion pVersion, @@ -163,6 +163,11 @@ namespace { } init; } +struct TCPConnector::Buff : public AsynchIO::BufferBase { + Buff(size_t size) : AsynchIO::BufferBase(new char[size], size) {} + ~Buff() { delete [] bytes;} +}; + TCPConnector::TCPConnector(ProtocolVersion ver, const ConnectionSettings& settings, ConnectionImpl* cimpl) @@ -189,15 +194,19 @@ TCPConnector::~TCPConnector() { void TCPConnector::connect(const std::string& host, int port){ Mutex::ScopedLock l(lock); assert(closed); - try { - socket.connect(host, port); - } catch (const std::exception& /*e*/) { - socket.close(); - throw; - } - - identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress()); + assert(joined); poller = Poller::shared_ptr(new Poller); + AsynchConnector::create(socket, + poller, + host, port, + boost::bind(&TCPConnector::connected, this, _1), + boost::bind(&TCPConnector::connectFailed, this, _3)); + closed = false; + joined = false; + receiver = Thread(this); +} + +void TCPConnector::connected(const Socket&) { aio = AsynchIO::create(socket, boost::bind(&TCPConnector::readbuff, this, _1, _2), boost::bind(&TCPConnector::eof, this, _1), @@ -205,16 +214,23 @@ void TCPConnector::connect(const std::string& host, int port){ 0, // closed 0, // nobuffs boost::bind(&TCPConnector::writebuff, this, _1)); - closed = false; -} + for (int i = 0; i < 32; i++) { + aio->queueReadBuffer(new Buff(maxFrameSize)); + } + aio->start(poller); -void TCPConnector::init(){ - Mutex::ScopedLock l(lock); - assert(joined); + identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress()); ProtocolInitiation init(version); writeDataBlock(init); - joined = false; - receiver = Thread(this); +} + +void TCPConnector::connectFailed(const std::string& msg) { + QPID_LOG(warning, "Connecting failed: " << msg); + closed = true; + poller->shutdown(); + closeInternal(); + if (shutdownHandler) + shutdownHandler->shutdown(); } bool TCPConnector::closeInternal() { @@ -235,7 +251,7 @@ bool TCPConnector::closeInternal() { receiver.join(); return ret; } - + void TCPConnector::close() { closeInternal(); } @@ -243,7 +259,13 @@ void TCPConnector::close() { void TCPConnector::abort() { // Can't abort a closed connection if (!closed) { - aio->requestCallback(boost::bind(&TCPConnector::eof, this, _1)); + if (aio) { + // Established connection + aio->requestCallback(boost::bind(&TCPConnector::eof, this, _1)); + } else { + // We're still connecting + connectFailed("Connection timedout"); + } } } @@ -288,18 +310,13 @@ void TCPConnector::handleClosed() { shutdownHandler->shutdown(); } -struct TCPConnector::Buff : public AsynchIO::BufferBase { - Buff(size_t size) : AsynchIO::BufferBase(new char[size], size) {} - ~Buff() { delete [] bytes;} -}; - void TCPConnector::writebuff(AsynchIO& /*aio*/) { Codec* codec = securityLayer.get() ? (Codec*) securityLayer.get() : (Codec*) this; if (codec->canEncode()) { std::auto_ptr<AsynchIO::BufferBase> buffer = std::auto_ptr<AsynchIO::BufferBase>(aio->getQueuedBuffer()); if (!buffer.get()) buffer = std::auto_ptr<AsynchIO::BufferBase>(new Buff(maxFrameSize)); - + size_t encoded = codec->encode(buffer->bytes, buffer->byteCount); buffer->dataStart = 0; @@ -395,11 +412,6 @@ void TCPConnector::run() { try { Dispatcher d(poller); - for (int i = 0; i < 32; i++) { - aio->queueReadBuffer(new Buff(maxFrameSize)); - } - - aio->start(poller); d.run(); } catch (const std::exception& e) { QPID_LOG(error, QPID_MSG("FAIL " << identifier << ": " << e.what())); diff --git a/qpid/cpp/src/qpid/client/RdmaConnector.cpp b/qpid/cpp/src/qpid/client/RdmaConnector.cpp index 0aefcc04cf..0692c3d85c 100644 --- a/qpid/cpp/src/qpid/client/RdmaConnector.cpp +++ b/qpid/cpp/src/qpid/client/RdmaConnector.cpp @@ -167,20 +167,9 @@ void RdmaConnector::connect(const std::string& host, int port){ assert(joined); poller = Poller::shared_ptr(new Poller); - // This stuff needs to abstracted out of here to a platform specific file - ::addrinfo *res; - ::addrinfo hints; - hints.ai_flags = 0; - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - int n = ::getaddrinfo(host.c_str(), boost::lexical_cast<std::string>(port).c_str(), &hints, &res); - if (n<0) { - throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n))); - } - + SocketAddress sa(host, boost::lexical_cast<std::string>(port)); Rdma::Connector* c = new Rdma::Connector( - *res->ai_addr, + sa, Rdma::ConnectionParams(maxFrameSize, Rdma::DEFAULT_WR_ENTRIES), boost::bind(&RdmaConnector::connected, this, poller, _1, _2), boost::bind(&RdmaConnector::connectionError, this, poller, _1, _2), diff --git a/qpid/cpp/src/qpid/client/Sasl.h b/qpid/cpp/src/qpid/client/Sasl.h index 9dc5817f3d..d773609655 100644 --- a/qpid/cpp/src/qpid/client/Sasl.h +++ b/qpid/cpp/src/qpid/client/Sasl.h @@ -45,6 +45,7 @@ class Sasl virtual std::string start(const std::string& mechanisms) = 0; virtual std::string step(const std::string& challenge) = 0; virtual std::string getMechanism() = 0; + virtual std::string getUserId() = 0; virtual std::auto_ptr<qpid::sys::SecurityLayer> getSecurityLayer(uint16_t maxFrameSize) = 0; virtual ~Sasl() {} }; diff --git a/qpid/cpp/src/qpid/client/SaslFactory.cpp b/qpid/cpp/src/qpid/client/SaslFactory.cpp index 884f527f01..2258163ec8 100644 --- a/qpid/cpp/src/qpid/client/SaslFactory.cpp +++ b/qpid/cpp/src/qpid/client/SaslFactory.cpp @@ -82,6 +82,7 @@ class CyrusSasl : public Sasl std::string start(const std::string& mechanisms); std::string step(const std::string& challenge); std::string getMechanism(); + std::string getUserId(); std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize); private: sasl_conn_t* conn; @@ -266,6 +267,18 @@ std::string CyrusSasl::getMechanism() return mechanism; } +std::string CyrusSasl::getUserId() +{ + int propResult; + const void* operName; + + propResult = sasl_getprop(conn, SASL_USERNAME, &operName); + if (propResult == SASL_OK) + return std::string((const char*) operName); + + return std::string(); +} + void CyrusSasl::interact(sasl_interact_t* client_interact) { diff --git a/qpid/cpp/src/qpid/client/SessionImpl.cpp b/qpid/cpp/src/qpid/client/SessionImpl.cpp index 8ead44a172..32541dceac 100644 --- a/qpid/cpp/src/qpid/client/SessionImpl.cpp +++ b/qpid/cpp/src/qpid/client/SessionImpl.cpp @@ -64,7 +64,8 @@ SessionImpl::SessionImpl(const std::string& name, boost::shared_ptr<ConnectionIm proxy(ioHandler), nextIn(0), nextOut(0), - sendMsgCredit(0) + sendMsgCredit(0), + doClearDeliveryPropertiesExchange(true) { channel.next = connectionShared.get(); } @@ -396,11 +397,16 @@ void SessionImpl::sendContent(const MethodContent& content) { AMQFrame header(content.getHeader()); - // Client is not allowed to set the delivery-properties.exchange. - AMQHeaderBody* headerp = static_cast<AMQHeaderBody*>(header.getBody()); - if (headerp && headerp->get<DeliveryProperties>()) - headerp->get<DeliveryProperties>(true)->clearExchangeFlag(); - + // doClearDeliveryPropertiesExchange is set by cluster update client so + // it can send messages with delivery-properties.exchange set. + // + if (doClearDeliveryPropertiesExchange) { + // Normal client is not allowed to set the delivery-properties.exchange + // so clear it here. + AMQHeaderBody* headerp = static_cast<AMQHeaderBody*>(header.getBody()); + if (headerp && headerp->get<DeliveryProperties>()) + headerp->get<DeliveryProperties>(true)->clearExchangeFlag(); + } header.setFirstSegment(false); uint64_t data_length = content.getData().length(); if(data_length > 0){ diff --git a/qpid/cpp/src/qpid/client/SessionImpl.h b/qpid/cpp/src/qpid/client/SessionImpl.h index 49d268c44d..0624bb8b3c 100644 --- a/qpid/cpp/src/qpid/client/SessionImpl.h +++ b/qpid/cpp/src/qpid/client/SessionImpl.h @@ -130,6 +130,8 @@ public: */ boost::shared_ptr<ConnectionImpl> getConnection(); + void setDoClearDeliveryPropertiesExchange(bool b=true) { doClearDeliveryPropertiesExchange = b; } + private: enum State { INACTIVE, @@ -243,6 +245,8 @@ private: // Only keep track of message credit sys::Semaphore* sendMsgCredit; + bool doClearDeliveryPropertiesExchange; + friend class client::SessionHandler; }; diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp index 9b9f06ec57..f51a96efd9 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp +++ b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp @@ -362,21 +362,12 @@ void QueueSink::send(qpid::client::AsyncSession& session, const std::string&, Ou 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.setData(from.getContent()); to.getDeliveryProperties().setRoutingKey(from.getSubject()); //TODO: set other delivery properties to.getMessageProperties().setContentType(from.getContentType()); diff --git a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp index d22208368b..8e060c62d7 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp +++ b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp @@ -269,18 +269,9 @@ void populate(qpid::messaging::Message& message, FrameSet& command) //e.g. for rejecting. MessageImplAccess::get(message).setInternalId(command.getId()); - command.getContent(message.getBytes()); + command.getContent(message.getContent()); 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); - } } diff --git a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp index 716f955f98..cbc95b44fb 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp +++ b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp @@ -33,24 +33,11 @@ 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()); - } + message.setData(from.getContent()); + message.getMessageProperties().setContentType(from.getContentType()); const Address& address = from.getReplyTo(); if (!address.value.empty()) { message.getMessageProperties().setReplyTo(AddressResolution::convert(address)); diff --git a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp index 58956609a4..3a662463c1 100644 --- a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp +++ b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp @@ -43,6 +43,7 @@ class WindowsSasl : public Sasl std::string start(const std::string& mechanisms); std::string step(const std::string& challenge); std::string getMechanism(); + std::string getUserId(); std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize); private: ConnectionSettings settings; @@ -131,6 +132,11 @@ std::string WindowsSasl::getMechanism() return mechanism; } +std::string WindowsSasl::getUserId() +{ + return std::string(); // TODO - when GSSAPI is supported, return userId for connection. +} + std::auto_ptr<SecurityLayer> WindowsSasl::getSecurityLayer(uint16_t maxFrameSize) { return std::auto_ptr<SecurityLayer>(0); diff --git a/qpid/cpp/src/qpid/cluster/Cluster.cpp b/qpid/cpp/src/qpid/cluster/Cluster.cpp index e35d3e4175..0706fc72e8 100644 --- a/qpid/cpp/src/qpid/cluster/Cluster.cpp +++ b/qpid/cpp/src/qpid/cluster/Cluster.cpp @@ -99,6 +99,7 @@ #include "qpid/broker/Connection.h" #include "qpid/broker/QueueRegistry.h" #include "qpid/broker/SessionState.h" +#include "qpid/broker/SignalHandler.h" #include "qpid/framing/AMQFrame.h" #include "qpid/framing/AMQP_AllOperations.h" #include "qpid/framing/AllInvoker.h" @@ -120,7 +121,6 @@ #include "qpid/management/ManagementAgent.h" #include "qpid/memory.h" #include "qpid/sys/Thread.h" -#include "qpid/sys/LatencyTracker.h" #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> @@ -144,12 +144,16 @@ using qpid::management::Manageable; using qpid::management::Args; namespace _qmf = ::qmf::org::apache::qpid::cluster; -/** NOTE: increment this number whenever any incompatible changes in +/** + * NOTE: must increment this number whenever any incompatible changes in * cluster protocol/behavior are made. It allows early detection and * sensible reporting of an attempt to mix different versions in a * cluster. + * + * Currently use SVN revision to avoid clashes with versions from + * different branches. */ -const uint32_t Cluster::CLUSTER_VERSION = 2; +const uint32_t Cluster::CLUSTER_VERSION = 820783; struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler { qpid::cluster::Cluster& cluster; @@ -308,7 +312,7 @@ void Cluster::leave(Lock&) { // Finalize connections now now to avoid problems later in destructor. LEAVE_TRY(localConnections.clear()); LEAVE_TRY(connections.clear()); - LEAVE_TRY(broker.shutdown()); + LEAVE_TRY(broker::SignalHandler::shutdown()); } } @@ -324,20 +328,14 @@ void Cluster::deliver( MemberId from(nodeid, pid); framing::Buffer buf(static_cast<char*>(msg), msg_len); Event e(Event::decodeCopy(from, buf)); - LATENCY_TRACK(if (e.getConnectionId().getMember() == self) mcast.cpgLatency.finish()); deliverEvent(e); } -LATENCY_TRACK(sys::LatencyTracker<const char*> eventQueueLatencyTracker("EventQueue");) - LATENCY_TRACK(sys::LatencyTracker<const AMQBody*> frameQueueLatencyTracker("FrameQueue");) - - void Cluster::deliverEvent(const Event& e) { - LATENCY_TRACK(eventQueueLatencyTracker.start(e.getData());) - deliverEventQueue.push(e); +void Cluster::deliverEvent(const Event& e) { + deliverEventQueue.push(e); } void Cluster::deliverFrame(const EventFrame& e) { - LATENCY_TRACK(frameQueueLatencyTracker.start(e.frame.getBody())); deliverFrameQueue.push(e); } @@ -350,7 +348,6 @@ const ClusterUpdateOfferBody* castUpdateOffer(const framing::AMQBody* body) { // Handler for deliverEventQueue. // This thread decodes frames from events. void Cluster::deliveredEvent(const Event& e) { - LATENCY_TRACK(eventQueueLatencyTracker.finish(e.getData())); if (e.isCluster()) { QPID_LOG(trace, *this << " DLVR: " << e); EventFrame ef(e, e.getFrame()); @@ -396,13 +393,9 @@ void Cluster::flagError( error.error(connection, type, map.getFrameSeq(), map.getMembers(), msg); } -LATENCY_TRACK(sys::LatencyTracker<const AMQBody*> doOutputTracker("DoOutput");) - // Handler for deliverFrameQueue. // This thread executes the main logic. - void Cluster::deliveredFrame(const EventFrame& efConst) { - LATENCY_TRACK(frameQueueLatencyTracker.finish(e.frame.getBody())); - LATENCY_TRACK(if (e.frame.getBody()->type() == CONTENT_BODY) doOutputTracker.start(e.frame.getBody())); +void Cluster::deliveredFrame(const EventFrame& efConst) { Mutex::ScopedLock l(lock); if (state == LEFT) return; EventFrame e(efConst); @@ -434,7 +427,6 @@ void Cluster::processFrame(const EventFrame& e, Lock& l) { throw Exception(QPID_MSG("Invalid cluster control")); } else if (state >= CATCHUP) { - LATENCY_TRACK(LatencyScope ls(processLatency)); map.incrementFrameSeq(); ConnectionPtr connection = getConnection(e, l); if (connection) { diff --git a/qpid/cpp/src/qpid/cluster/ErrorCheck.cpp b/qpid/cpp/src/qpid/cluster/ErrorCheck.cpp index 35be055d06..5b7011047b 100644 --- a/qpid/cpp/src/qpid/cluster/ErrorCheck.cpp +++ b/qpid/cpp/src/qpid/cluster/ErrorCheck.cpp @@ -45,7 +45,8 @@ ostream& operator<<(ostream& o, const ErrorCheck::MemberSet& ms) { } void ErrorCheck::error( - Connection& c, ErrorType t, framing::SequenceNumber seq, const MemberSet& ms, const std::string& msg) + Connection& c, ErrorType t, framing::SequenceNumber seq, const MemberSet& ms, + const std::string& msg) { // Detected a local error, inform cluster and set error state. assert(t != ERROR_TYPE_NONE); // Must be an error. @@ -54,10 +55,11 @@ void ErrorCheck::error( unresolved = ms; frameSeq = seq; connection = &c; - QPID_LOG(error, cluster - << (type == ERROR_TYPE_SESSION ? " channel" : " connection") - << " error " << frameSeq << " on " << c << ": " << msg - << " must be resolved with: " << unresolved); + message = msg; + QPID_LOG(debug, cluster<< (type == ERROR_TYPE_SESSION ? " channel" : " connection") + << " error " << frameSeq << " on " << c + << " must be resolved with: " << unresolved + << ": " << message); mcast.mcastControl( ClusterErrorCheckBody(ProtocolVersion(), type, frameSeq), cluster.getId()); // If there are already frames queued up by a previous error, review @@ -84,13 +86,15 @@ ErrorCheck::FrameQueue::iterator ErrorCheck::review(const FrameQueue::iterator& if (errorCheck->getFrameSeq() == frameSeq) { // Addresses current error next = frames.erase(i); // Drop matching error check controls if (errorCheck->getType() < type) { // my error is worse than his - QPID_LOG(critical, cluster << " error " << frameSeq - << " did not occur on " << i->getMemberId()); - throw Exception(QPID_MSG("Error " << frameSeq - << " did not occur on all members")); + QPID_LOG(critical, cluster + << " local error " << frameSeq << " did not occur on member " + << i->getMemberId() + << ": " << message); + throw Exception( + QPID_MSG("local error did not occur on all cluster members " << ": " << message)); } else { // his error is worse/same as mine. - QPID_LOG(info, cluster << " error " << frameSeq + QPID_LOG(debug, cluster << " error " << frameSeq << " resolved with " << i->getMemberId()); unresolved.erase(i->getMemberId()); checkResolved(); @@ -128,10 +132,10 @@ ErrorCheck::FrameQueue::iterator ErrorCheck::review(const FrameQueue::iterator& void ErrorCheck::checkResolved() { if (unresolved.empty()) { // No more potentially conflicted members, we're clear. type = ERROR_TYPE_NONE; - QPID_LOG(info, cluster << " error " << frameSeq << " resolved."); + QPID_LOG(debug, cluster << " error " << frameSeq << " resolved."); } else - QPID_LOG(info, cluster << " error " << frameSeq + QPID_LOG(debug, cluster << " error " << frameSeq << " must be resolved with " << unresolved); } @@ -146,7 +150,7 @@ void ErrorCheck::respondNone(const MemberId& from, uint8_t type, framing::Sequen // Don't respond to non-errors or to my own errors. if (type == ERROR_TYPE_NONE || from == cluster.getId()) return; - QPID_LOG(info, cluster << " error " << frameSeq << " did not occur locally."); + QPID_LOG(debug, cluster << " error " << frameSeq << " did not occur locally."); mcast.mcastControl( ClusterErrorCheckBody(ProtocolVersion(), ERROR_TYPE_NONE, frameSeq), cluster.getId() diff --git a/qpid/cpp/src/qpid/cluster/ErrorCheck.h b/qpid/cpp/src/qpid/cluster/ErrorCheck.h index 09028391ac..c975b9af64 100644 --- a/qpid/cpp/src/qpid/cluster/ErrorCheck.h +++ b/qpid/cpp/src/qpid/cluster/ErrorCheck.h @@ -84,6 +84,7 @@ class ErrorCheck SequenceNumber frameSeq; ErrorType type; Connection* connection; + std::string message; }; }} // namespace qpid::cluster diff --git a/qpid/cpp/src/qpid/cluster/Event.cpp b/qpid/cpp/src/qpid/cluster/Event.cpp index 30866d3154..4831e7eabe 100644 --- a/qpid/cpp/src/qpid/cluster/Event.cpp +++ b/qpid/cpp/src/qpid/cluster/Event.cpp @@ -38,9 +38,6 @@ const size_t EventHeader::HEADER_SIZE = sizeof(uint8_t) + // type sizeof(uint64_t) + // connection pointer only, CPG provides member ID. sizeof(uint32_t) // payload size -#ifdef QPID_LATENCY_METRIC - + sizeof(int64_t) // timestamp -#endif ; EventHeader::EventHeader(EventType t, const ConnectionId& c, size_t s) @@ -61,9 +58,6 @@ void EventHeader::decode(const MemberId& m, framing::Buffer& buf) { throw Exception("Invalid multicast event type"); connectionId = ConnectionId(m, buf.getLongLong()); size = buf.getLong(); -#ifdef QPID_LATENCY_METRIC - latency_metric_timestamp = buf.getLongLong(); -#endif } Event Event::decodeCopy(const MemberId& m, framing::Buffer& buf) { @@ -97,9 +91,6 @@ void EventHeader::encode(Buffer& b) const { b.putOctet(type); b.putLongLong(connectionId.getNumber()); b.putLong(size); -#ifdef QPID_LATENCY_METRIC - b.putLongLong(latency_metric_timestamp); -#endif } // Encode my header in my buffer. diff --git a/qpid/cpp/src/qpid/cluster/Multicaster.cpp b/qpid/cpp/src/qpid/cluster/Multicaster.cpp index 7e97963318..72fc1533f8 100644 --- a/qpid/cpp/src/qpid/cluster/Multicaster.cpp +++ b/qpid/cpp/src/qpid/cluster/Multicaster.cpp @@ -31,9 +31,6 @@ namespace cluster { Multicaster::Multicaster(Cpg& cpg_, const boost::shared_ptr<sys::Poller>& poller, boost::function<void()> onError_) : -#if defined (QPID_LATENCY_TRACKER) - cpgLatency("CPG"), -#endif onError(onError_), cpg(cpg_), queue(boost::bind(&Multicaster::sendMcast, this, _1), poller), holding(true) @@ -61,7 +58,6 @@ void Multicaster::mcastBuffer(const char* data, size_t size, const ConnectionId& void Multicaster::mcast(const Event& e) { { sys::Mutex::ScopedLock l(lock); - LATENCY_TRACK(cpgLatency.start()); if (e.isConnection() && holding) { holdingQueue.push_back(e); return; diff --git a/qpid/cpp/src/qpid/cluster/Multicaster.h b/qpid/cpp/src/qpid/cluster/Multicaster.h index f2ee5099bb..c1a0ddffc6 100644 --- a/qpid/cpp/src/qpid/cluster/Multicaster.h +++ b/qpid/cpp/src/qpid/cluster/Multicaster.h @@ -26,7 +26,6 @@ #include "qpid/cluster/Event.h" #include "qpid/sys/PollableQueue.h" #include "qpid/sys/Mutex.h" -#include "qpid/sys/LatencyTracker.h" #include <boost/shared_ptr.hpp> #include <deque> @@ -58,8 +57,6 @@ class Multicaster /** End holding mode, held events are mcast */ void release(); - LATENCY_TRACK(sys::LatencyCounter cpgLatency;) - private: typedef sys::PollableQueue<Event> PollableEventQueue; typedef std::deque<Event> PlainEventQueue; diff --git a/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp b/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp index cb8f01386c..cb75fe5561 100644 --- a/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp +++ b/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp @@ -24,7 +24,6 @@ #include "qpid/framing/ClusterConnectionDeliverDoOutputBody.h" #include "qpid/framing/AMQFrame.h" #include "qpid/log/Statement.h" -#include "qpid/sys/LatencyTracker.h" #include <boost/current_function.hpp> @@ -40,16 +39,9 @@ OutputInterceptor::OutputInterceptor(Connection& p, sys::ConnectionOutputHandler : parent(p), closing(false), next(&h), sendMax(1), sent(0), sentDoOutput(false) {} -#if defined QPID_LATENCY_TRACKER -extern sys::LatencyTracker<const AMQBody*> doOutputTracker; -#endif - void OutputInterceptor::send(framing::AMQFrame& f) { - LATENCY_TRACK(doOutputTracker.finish(f.getBody())); - { - sys::Mutex::ScopedLock l(lock); - next->send(f); - } + sys::Mutex::ScopedLock l(lock); + next->send(f); } void OutputInterceptor::activateOutput() { diff --git a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp index 2e557f2ab6..d6df8bd5ac 100644 --- a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp +++ b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp @@ -209,9 +209,16 @@ class MessageUpdater { ClusterConnectionProxy(session).expiryId(*expiryId); } + // We can't send a broker::Message via the normal client API, + // and it would be expensive to copy it into a client::Message + // so we go a bit under the client API covers here. + // SessionBase_0_10Access sb(session); + // Disable client code that clears the delivery-properties.exchange + sb.get()->setDoClearDeliveryPropertiesExchange(false); framing::MessageTransferBody transfer( - framing::ProtocolVersion(), UpdateClient::UPDATE, message::ACCEPT_MODE_NONE, message::ACQUIRE_MODE_PRE_ACQUIRED); + framing::ProtocolVersion(), UpdateClient::UPDATE, message::ACCEPT_MODE_NONE, + message::ACQUIRE_MODE_PRE_ACQUIRED); sb.get()->send(transfer, message.payload->getFrames(), !message.payload->isContentReleased()); if (message.payload->isContentReleased()){ diff --git a/qpid/cpp/src/qpid/cluster/UpdateExchange.h b/qpid/cpp/src/qpid/cluster/UpdateExchange.h index 194a3d386d..00a92c7f1e 100644 --- a/qpid/cpp/src/qpid/cluster/UpdateExchange.h +++ b/qpid/cpp/src/qpid/cluster/UpdateExchange.h @@ -30,7 +30,7 @@ namespace qpid { namespace cluster { /** - * A keyless exchange (like fanout exchange) that does not modify deliver-properties.exchange + * A keyless exchange (like fanout exchange) that does not modify delivery-properties.exchange * on messages. */ class UpdateExchange : public broker::FanOutExchange diff --git a/qpid/cpp/src/qpid/messaging/ListContent.cpp b/qpid/cpp/src/qpid/messaging/ListContent.cpp new file mode 100644 index 0000000000..0c3ca5fc62 --- /dev/null +++ b/qpid/cpp/src/qpid/messaging/ListContent.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 "qpid/messaging/ListContent.h" +#include "qpid/messaging/Message.h" +#include "qpid/client/amqp0_10/Codecs.h" + +namespace qpid { +namespace messaging { + +class ListContentImpl : public Variant +{ + Message* msg; + public: + ListContentImpl(Message& m) : Variant(Variant::List()), msg(&m) + { + if (msg->getContent().size()) { + qpid::client::amqp0_10::ListCodec codec; + codec.decode(msg->getContent(), *this); + } + } + + void encode() + { + qpid::client::amqp0_10::ListCodec codec; + codec.encode(*this, msg->getContent()); + } +}; + +ListContent::ListContent(Message& m) : impl(new ListContentImpl(m)) {} +ListContent::~ListContent() { delete impl; } +ListContent& ListContent::operator=(const ListContent& l) { *impl = *l.impl; return *this; } + +ListContent::const_iterator ListContent::begin() const { return impl->asList().begin(); } +ListContent::const_iterator ListContent::end() const { return impl->asList().end(); } +ListContent::const_reverse_iterator ListContent::rbegin() const { return impl->asList().rbegin(); } +ListContent::const_reverse_iterator ListContent::rend() const { return impl->asList().rend(); } + +ListContent::iterator ListContent::begin() { return impl->asList().begin(); } +ListContent::iterator ListContent::end() { return impl->asList().end(); } +ListContent::reverse_iterator ListContent::rbegin() { return impl->asList().rbegin(); } +ListContent::reverse_iterator ListContent::rend() { return impl->asList().rend(); } + +bool ListContent::empty() const { return impl->asList().empty(); } +size_t ListContent::size() const { return impl->asList().size(); } + +const Variant& ListContent::front() const { return impl->asList().front(); } +Variant& ListContent::front() { return impl->asList().front(); } +const Variant& ListContent::back() const { return impl->asList().back(); } +Variant& ListContent::back() { return impl->asList().back(); } + +void ListContent::push_front(const Variant& v) { impl->asList().push_front(v); } +void ListContent::push_back(const Variant& v) { impl->asList().push_back(v); } + +void ListContent::pop_front() { impl->asList().pop_front(); } +void ListContent::pop_back() { impl->asList().pop_back(); } + +ListContent::iterator ListContent::insert(iterator position, const Variant& v) +{ + return impl->asList().insert(position, v); +} +void ListContent::insert(iterator position, size_t n, const Variant& v) +{ + impl->asList().insert(position, n, v); +} +ListContent::iterator ListContent::erase(iterator position) { return impl->asList().erase(position); } +ListContent::iterator ListContent::erase(iterator first, iterator last) { return impl->asList().erase(first, last); } +void ListContent::clear() { impl->asList().clear(); } + +void ListContent::encode() { impl->encode(); } + +const Variant::List& ListContent::asList() const { return impl->asList(); } +Variant::List& ListContent::asList() { return impl->asList(); } + +std::ostream& operator<<(std::ostream& out, const ListContent& m) +{ + out << m.asList(); + return out; +} + +}} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/ListView.cpp b/qpid/cpp/src/qpid/messaging/ListView.cpp new file mode 100644 index 0000000000..b717d157fa --- /dev/null +++ b/qpid/cpp/src/qpid/messaging/ListView.cpp @@ -0,0 +1,63 @@ +/* + * + * 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/ListView.h" +#include "qpid/messaging/Message.h" +#include "qpid/client/amqp0_10/Codecs.h" + +namespace qpid { +namespace messaging { + +class ListViewImpl : public Variant +{ + public: + ListViewImpl(const Message& msg) : Variant(Variant::List()) + { + if (msg.getContent().size()) { + qpid::client::amqp0_10::ListCodec codec; + codec.decode(msg.getContent(), *this); + } + } +}; + +ListView::ListView(const Message& m) :impl(new ListViewImpl(m)) {} +ListView::~ListView() { delete impl; } +ListView& ListView::operator=(const ListView& l) { *impl = *l.impl; return *this; } + +ListView::const_iterator ListView::begin() const { return impl->asList().begin(); } +ListView::const_iterator ListView::end() const { return impl->asList().end(); } +ListView::const_reverse_iterator ListView::rbegin() const { return impl->asList().rbegin(); } +ListView::const_reverse_iterator ListView::rend() const { return impl->asList().rend(); } + +bool ListView::empty() const { return impl->asList().empty(); } +size_t ListView::size() const { return impl->asList().size(); } + +const Variant& ListView::front() const { return impl->asList().front(); } +const Variant& ListView::back() const { return impl->asList().back(); } + +const Variant::List& ListView::asList() const { return impl->asList(); } + +std::ostream& operator<<(std::ostream& out, const ListView& m) +{ + out << m.asList(); + return out; +} + +}} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/MapContent.cpp b/qpid/cpp/src/qpid/messaging/MapContent.cpp new file mode 100644 index 0000000000..c653561fc9 --- /dev/null +++ b/qpid/cpp/src/qpid/messaging/MapContent.cpp @@ -0,0 +1,87 @@ +/* + * + * 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/MapContent.h" +#include "qpid/messaging/Message.h" +#include "qpid/client/amqp0_10/Codecs.h" + +namespace qpid { +namespace messaging { + +class MapContentImpl : public Variant +{ + Message* msg; + public: + MapContentImpl(Message& m) : Variant(Variant::Map()), msg(&m) + { + if (msg->getContent().size()) { + qpid::client::amqp0_10::MapCodec codec; + codec.decode(msg->getContent(), *this); + } + } + + void encode() + { + qpid::client::amqp0_10::MapCodec codec; + codec.encode(*this, msg->getContent()); + } +}; + +MapContent::MapContent(Message& m) : impl(new MapContentImpl(m)) {} +MapContent::~MapContent() { delete impl; } +MapContent& MapContent::operator=(const MapContent& m) { *impl = *m.impl; return *this; } + +MapContent::const_iterator MapContent::begin() const { return impl->asMap().begin(); } +MapContent::const_iterator MapContent::end() const { return impl->asMap().end(); } +MapContent::const_reverse_iterator MapContent::rbegin() const { return impl->asMap().rbegin(); } +MapContent::const_reverse_iterator MapContent::rend() const { return impl->asMap().rend(); } +MapContent::iterator MapContent::begin() { return impl->asMap().begin(); } +MapContent::iterator MapContent::end() { return impl->asMap().end(); } +MapContent::reverse_iterator MapContent::rbegin() { return impl->asMap().rbegin(); } +MapContent::reverse_iterator MapContent::rend() { return impl->asMap().rend(); } + +bool MapContent::empty() const { return impl->asMap().empty(); } +size_t MapContent::size() const { return impl->asMap().size(); } + +MapContent::const_iterator MapContent::find(const key_type& key) const { return impl->asMap().find(key); } +MapContent::iterator MapContent::find(const key_type& key) { return impl->asMap().find(key); } +const Variant& MapContent::operator[](const key_type& key) const { return impl->asMap()[key]; } +Variant& MapContent::operator[](const key_type& key) { return impl->asMap()[key]; } + +std::pair<MapContent::iterator,bool> MapContent::insert(const value_type& item) { return impl->asMap().insert(item); } +MapContent::iterator MapContent::insert(iterator position, const value_type& item) { return impl->asMap().insert(position, item); } +void MapContent::erase(iterator position) { impl->asMap().erase(position); } +void MapContent::erase(iterator first, iterator last) { impl->asMap().erase(first, last); } +size_t MapContent::erase(const key_type& key) { return impl->asMap().erase(key); } +void MapContent::clear() { impl->asMap().clear(); } + +void MapContent::encode() { impl->encode(); } + +const std::map<MapContent::key_type, Variant>& MapContent::asMap() const { return impl->asMap(); } +std::map<MapContent::key_type, Variant>& MapContent::asMap() { return impl->asMap(); } + + +std::ostream& operator<<(std::ostream& out, const MapContent& m) +{ + out << m.asMap(); + return out; +} + +}} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/MapView.cpp b/qpid/cpp/src/qpid/messaging/MapView.cpp new file mode 100644 index 0000000000..ffa6e91a16 --- /dev/null +++ b/qpid/cpp/src/qpid/messaging/MapView.cpp @@ -0,0 +1,63 @@ +/* + * + * 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/MapView.h" +#include "qpid/messaging/Message.h" +#include "qpid/client/amqp0_10/Codecs.h" + +namespace qpid { +namespace messaging { + +class MapViewImpl : public Variant +{ + public: + MapViewImpl(const Message& msg) : Variant(Variant::Map()) + { + if (msg.getContent().size()) { + qpid::client::amqp0_10::MapCodec codec; + codec.decode(msg.getContent(), *this); + } + } +}; + +MapView::MapView(const Message& m) : impl(new MapViewImpl(m)) {} +MapView::~MapView() { delete impl; } +MapView& MapView::operator=(const MapView& m) { *impl = *m.impl; return *this; } + +MapView::const_iterator MapView::begin() const { return impl->asMap().begin(); } +MapView::const_iterator MapView::end() const { return impl->asMap().end(); } +MapView::const_reverse_iterator MapView::rbegin() const { return impl->asMap().rbegin(); } +MapView::const_reverse_iterator MapView::rend() const { return impl->asMap().rend(); } + +bool MapView::empty() const { return impl->asMap().empty(); } +size_t MapView::size() const { return impl->asMap().size(); } + +MapView::const_iterator MapView::find(const key_type& key) const { return impl->asMap().find(key); } +const Variant& MapView::operator[](const key_type& key) const { return impl->asMap()[key]; } + +const std::map<MapView::key_type, Variant>& MapView::asMap() const { return impl->asMap(); } + +std::ostream& operator<<(std::ostream& out, const MapView& m) +{ + out << m.asMap(); + return out; +} + +}} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/Message.cpp b/qpid/cpp/src/qpid/messaging/Message.cpp index 1d844b3027..fb4e800eaa 100644 --- a/qpid/cpp/src/qpid/messaging/Message.cpp +++ b/qpid/cpp/src/qpid/messaging/Message.cpp @@ -27,7 +27,7 @@ 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(const Message& m) : impl(new MessageImpl(m.getContent())) {} Message::~Message() { delete impl; } Message& Message::operator=(const Message& m) { *impl = *m.impl; return *this; } @@ -44,27 +44,15 @@ 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(); } +void Message::setContent(const std::string& c) { impl->setBytes(c); } +void Message::setContent(const char* chars, size_t count) { impl->setBytes(chars, count); } +const std::string& Message::getContent() const { return impl->getBytes(); } +std::string& Message::getContent() { 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) +void Message::getContent(std::pair<const char*, size_t>& content) const { - return content.print(out); + content.first = impl->getBytes().data(); + content.second = impl->getBytes().size(); } }} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.cpp b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp index 5df9218e03..e17fccd64f 100644 --- a/qpid/cpp/src/qpid/messaging/MessageImpl.cpp +++ b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp @@ -28,8 +28,8 @@ 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) {} +MessageImpl::MessageImpl(const std::string& c) : bytes(c), internalId(0) {} +MessageImpl::MessageImpl(const char* chars, size_t count) : bytes(chars, count), internalId(0) {} void MessageImpl::setReplyTo(const Address& d) { replyTo = d; } const Address& MessageImpl::getReplyTo() const { return replyTo; } @@ -44,155 +44,14 @@ 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); } +void MessageImpl::setBytes(const std::string& c) { bytes = c; } +void MessageImpl::setBytes(const char* chars, size_t count) { 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; diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.h b/qpid/cpp/src/qpid/messaging/MessageImpl.h index 1173e7570a..4939cdc5cc 100644 --- a/qpid/cpp/src/qpid/messaging/MessageImpl.h +++ b/qpid/cpp/src/qpid/messaging/MessageImpl.h @@ -22,15 +22,13 @@ * */ #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 +struct MessageImpl { Address replyTo; std::string subject; @@ -38,8 +36,6 @@ struct MessageImpl : MessageContent 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; @@ -66,54 +62,6 @@ struct MessageImpl : MessageContent 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; diff --git a/qpid/cpp/src/qpid/sys/AsynchIO.h b/qpid/cpp/src/qpid/sys/AsynchIO.h index fb02183359..419770568a 100644 --- a/qpid/cpp/src/qpid/sys/AsynchIO.h +++ b/qpid/cpp/src/qpid/sys/AsynchIO.h @@ -57,7 +57,7 @@ public: class AsynchConnector { public: typedef boost::function1<void, const Socket&> ConnectedCallback; - typedef boost::function2<void, int, std::string> FailedCallback; + typedef boost::function3<void, const Socket&, int, const std::string&> FailedCallback; // Call create() to allocate a new AsynchConnector object with the // specified poller, addressing, and callbacks. @@ -70,7 +70,7 @@ public: std::string hostname, uint16_t port, ConnectedCallback connCb, - FailedCallback failCb = 0); + FailedCallback failCb); protected: AsynchConnector() {} @@ -108,7 +108,7 @@ class AsynchIO { public: typedef AsynchIOBufferBase BufferBase; - typedef boost::function2<bool, AsynchIO&, BufferBase*> ReadCallback; + typedef boost::function2<void, AsynchIO&, BufferBase*> ReadCallback; typedef boost::function1<void, AsynchIO&> EofCallback; typedef boost::function1<void, AsynchIO&> DisconnectCallback; typedef boost::function2<void, AsynchIO&, const Socket&> ClosedCallback; diff --git a/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp b/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp index 8094abd43d..eb0f213547 100644 --- a/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp +++ b/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp @@ -103,10 +103,31 @@ void AsynchIOHandler::giveReadCredit(int32_t credit) { aio->startReading(); } -bool AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) { +void AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) { if (readError) { - return false; + return; + } + + // Check here for read credit + if (readCredit.get() != InfiniteCredit) { + if (readCredit.get() == 0) { + // FIXME aconway 2009-10-01: Workaround to avoid "false wakeups". + // readbuff is sometimes called with no credit. + // This should be fixed somewhere else to avoid such calls. + aio->unread(buff); + return; + } + // TODO In theory should be able to use an atomic operation before taking the lock + // but in practice there seems to be an unexplained race in that case + ScopedLock<Mutex> l(creditLock); + if (--readCredit == 0) { + assert(readCredit.get() >= 0); + if (readCredit.get() == 0) { + aio->stopReading(); + } + } } + size_t decoded = 0; if (codec) { // Already initiated try { @@ -149,20 +170,6 @@ bool AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) { // Give whole buffer back to aio subsystem aio->queueReadBuffer(buff); } - // Check here for read credit - if (readCredit.get() != InfiniteCredit) { - // TODO In theory should be able to use an atomic operation before taking the lock - // but in practice there seems to be an unexplained race in that case - ScopedLock<Mutex> l(creditLock); - if (--readCredit == 0) { - assert(readCredit.get() >= 0); - if (readCredit.get() == 0) { - aio->stopReading(); - return false; - } - } - } - return true; } void AsynchIOHandler::eof(AsynchIO&) { diff --git a/qpid/cpp/src/qpid/sys/AsynchIOHandler.h b/qpid/cpp/src/qpid/sys/AsynchIOHandler.h index 9785f445a4..e1885bac79 100644 --- a/qpid/cpp/src/qpid/sys/AsynchIOHandler.h +++ b/qpid/cpp/src/qpid/sys/AsynchIOHandler.h @@ -65,7 +65,7 @@ class AsynchIOHandler : public OutputControl { QPID_COMMON_EXTERN void giveReadCredit(int32_t credit); // Input side - QPID_COMMON_EXTERN bool readbuff(AsynchIO& aio, AsynchIOBufferBase* buff); + QPID_COMMON_EXTERN void readbuff(AsynchIO& aio, AsynchIOBufferBase* buff); QPID_COMMON_EXTERN void eof(AsynchIO& aio); QPID_COMMON_EXTERN void disconnect(AsynchIO& aio); diff --git a/qpid/cpp/src/qpid/sys/LatencyTracker.h b/qpid/cpp/src/qpid/sys/LatencyTracker.h deleted file mode 100644 index 3294528ff6..0000000000 --- a/qpid/cpp/src/qpid/sys/LatencyTracker.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef QPID_SYS_LATENCYTRACKER_H -#define QPID_SYS_LATENCYTRACKER_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/sys/Time.h" -#include <string> -#include <limits> -#include <map> - -namespace qpid { -namespace sys { - -/**@file Tools for measuring latency. NOT SUITABLE FOR PROUDCTION BUILDS. - * Uses should be compiled only if QPID_LATENCY_TRACKER is defined. - * See the convenience macros at the end of this file. - */ - -/** Used by LatencyCounter and LatencyTracker below */ -class LatencyStatistic { - public: - LatencyStatistic(std::string name_) : name(name_), count(0), total(0), min(std::numeric_limits<int64_t>::max()), max(0) {} - ~LatencyStatistic() { print(); } - - void record(Duration d) { - total += d; - ++count; - if (d > max) max=d; - if (d < min) min=d; - } - - void print() { - if (count) { - double meanMsec = (double(total)/count)/TIME_MSEC; - printf("\n==== Latency metric %s: samples=%lu mean=%fms (%f-%f)\n", name.c_str(), count, meanMsec, double(min)/TIME_MSEC, double(max)/TIME_MSEC); - } - else - printf("\n==== Latency metric %s: no samples.\n", name.c_str()); - } - - private: - std::string name; - unsigned long count; - int64_t total, min, max; -}; - -/** Measure delay between seeing the same value at start and finish. */ -template <class T> class LatencyTracker { - public: - LatencyTracker(std::string name) : measuring(false), stat(name) {} - - void start(T value) { - sys::Mutex::ScopedLock l(lock); - if (!measuring) { - measureAt = value; - measuring = true; - startTime = AbsTime::now(); - } - } - - void finish(T value) { - sys::Mutex::ScopedLock l(lock); - if(measuring && measureAt == value) { - stat.record(Duration(startTime, AbsTime::now())); - measuring = false; - } - } - - private: - sys::Mutex lock; - bool measuring; - T measureAt; - AbsTime startTime; - LatencyStatistic stat; -}; - - -/** Measures delay between the nth call to start and the nth call to finish. - * E.g. to measure latency between sending & receiving an ordered stream of messages. - */ -class LatencyCounter { - public: - LatencyCounter(std::string name) : measuring(false), startCount(0), finishCount(0), stat(name) {} - - void start() { - sys::Mutex::ScopedLock l(lock); - if (!measuring) { - measureAt = startCount; - measuring = true; - startTime = AbsTime::now(); - } - ++startCount; - } - - void finish() { - sys::Mutex::ScopedLock l(lock); - if (measuring && measureAt == finishCount) { - stat.record(Duration(startTime, AbsTime::now())); - measuring = false; - } - ++finishCount; - } - - private: - sys::Mutex lock; - bool measuring; - uint64_t startCount, finishCount, measureAt; - AbsTime startTime; - LatencyStatistic stat; -}; - -/** Measures time spent in a scope. */ -class LatencyScope { - public: - LatencyScope(LatencyStatistic& s) : stat(s), startTime(AbsTime::now()) {} - - ~LatencyScope() { - sys::Mutex::ScopedLock l(lock); - stat.record(Duration(startTime, AbsTime::now())); - } - - private: - sys::Mutex lock; - LatencyStatistic& stat; - AbsTime startTime; -}; - - -/** Macros to wrap latency tracking so disabled unless QPID_LATENCY_TRACKER is defined */ - -#if defined(QPID_LATENCY_TRACKER) -#define LATENCY_TRACK(X) X -#else -#define LATENCY_TRACK(X) -#endif -}} // namespace qpid::sys - -#endif /*!QPID_SYS_LATENCYTRACKER_H*/ diff --git a/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp b/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp index 6eafb6cf0b..28ff140237 100644 --- a/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp +++ b/qpid/cpp/src/qpid/sys/RdmaIOPlugin.cpp @@ -29,6 +29,7 @@ #include "qpid/sys/OutputControl.h" #include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> #include <memory> #include <netdb.h> @@ -304,8 +305,9 @@ void RdmaIOProtocolFactory::accept(Poller::shared_ptr poller, ConnectionCodec::F sin.sin_port = htons(listeningPort); sin.sin_addr.s_addr = INADDR_ANY; + SocketAddress sa("",boost::lexical_cast<std::string>(listeningPort)); listener.reset( - new Rdma::Listener((const sockaddr&)(sin), + new Rdma::Listener(sa, Rdma::ConnectionParams(65536, Rdma::DEFAULT_WR_ENTRIES), boost::bind(&RdmaIOProtocolFactory::established, this, poller, _1), boost::bind(&RdmaIOProtocolFactory::connectionError, this, _1, _2), @@ -331,24 +333,14 @@ void RdmaIOProtocolFactory::connected(Poller::shared_ptr poller, Rdma::Connectio void RdmaIOProtocolFactory::connect( Poller::shared_ptr poller, - const std::string& host, int16_t p, + const std::string& host, int16_t port, ConnectionCodec::Factory* f, ConnectFailedCallback failed) { - ::addrinfo *res; - ::addrinfo hints = {}; - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - stringstream ss; ss << p; - string port = ss.str(); - int n = ::getaddrinfo(host.c_str(), port.c_str(), &hints, &res); - if (n<0) { - throw Exception(QPID_MSG("Rdma: Cannot resolve " << host << ": " << ::gai_strerror(n))); - } - + SocketAddress sa(host, boost::lexical_cast<std::string>(port)); Rdma::Connector* c = new Rdma::Connector( - *res->ai_addr, + sa, Rdma::ConnectionParams(8000, Rdma::DEFAULT_WR_ENTRIES), boost::bind(&RdmaIOProtocolFactory::connected, this, poller, _1, _2, f), boost::bind(&RdmaIOProtocolFactory::connectionError, this, _1, _2), diff --git a/qpid/cpp/src/qpid/sys/Socket.h b/qpid/cpp/src/qpid/sys/Socket.h index f389e99cb8..d108402682 100644 --- a/qpid/cpp/src/qpid/sys/Socket.h +++ b/qpid/cpp/src/qpid/sys/Socket.h @@ -31,6 +31,7 @@ namespace qpid { namespace sys { class Duration; +class SocketAddress; class Socket : public IOHandle { @@ -48,6 +49,7 @@ public: void setNonblocking() const; QPID_COMMON_EXTERN void connect(const std::string& host, uint16_t port) const; + QPID_COMMON_EXTERN void connect(const SocketAddress&) const; QPID_COMMON_EXTERN void close() const; diff --git a/qpid/cpp/src/qpid/sys/SocketAddress.h b/qpid/cpp/src/qpid/sys/SocketAddress.h new file mode 100644 index 0000000000..fcb9c81d43 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/SocketAddress.h @@ -0,0 +1,51 @@ +#ifndef _sys_SocketAddress_h +#define _sys_SocketAddress_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/sys/IntegerTypes.h" +#include "qpid/CommonImportExport.h" +#include <string> + +struct addrinfo; + +namespace qpid { +namespace sys { + +class SocketAddress { + friend const ::addrinfo& getAddrInfo(const SocketAddress&); + +public: + /** Create a SocketAddress from hostname and port*/ + QPID_COMMON_EXTERN SocketAddress(const std::string& host, const std::string& port); + QPID_COMMON_EXTERN ~SocketAddress(); + + std::string asString() const; + +private: + std::string host; + std::string port; + ::addrinfo* addrInfo; +}; + +}} +#endif /*!_sys_SocketAddress_h*/ diff --git a/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp b/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp index b456beb098..3377be98f1 100644 --- a/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp +++ b/qpid/cpp/src/qpid/sys/TCPIOPlugin.cpp @@ -46,7 +46,7 @@ class AsynchIOProtocolFactory : public ProtocolFactory { void accept(Poller::shared_ptr, ConnectionCodec::Factory*); void connect(Poller::shared_ptr, const std::string& host, int16_t port, ConnectionCodec::Factory*, - boost::function2<void, int, std::string> failed); + ConnectFailedCallback); uint16_t getPort() const; std::string getHost() const; @@ -54,6 +54,7 @@ class AsynchIOProtocolFactory : public ProtocolFactory { private: void established(Poller::shared_ptr, const Socket&, ConnectionCodec::Factory*, bool isClient); + void connectFailed(const Socket&, int, const std::string&, ConnectFailedCallback); }; // Static instance to initialise plugin @@ -118,6 +119,15 @@ void AsynchIOProtocolFactory::accept(Poller::shared_ptr poller, acceptor->start(poller); } +void AsynchIOProtocolFactory::connectFailed( + const Socket& s, int ec, const std::string& emsg, + ConnectFailedCallback failedCb) +{ + failedCb(ec, emsg); + s.close(); + delete &s; +} + void AsynchIOProtocolFactory::connect( Poller::shared_ptr poller, const std::string& host, int16_t port, @@ -131,13 +141,14 @@ void AsynchIOProtocolFactory::connect( // is no longer needed. Socket* socket = new Socket(); - AsynchConnector::create (*socket, - poller, - host, - port, - boost::bind(&AsynchIOProtocolFactory::established, - this, poller, _1, fact, true), - failed); + AsynchConnector::create(*socket, + poller, + host, + port, + boost::bind(&AsynchIOProtocolFactory::established, + this, poller, _1, fact, true), + boost::bind(&AsynchIOProtocolFactory::connectFailed, + this, _1, _2, _3, failed)); } }} // namespace qpid::sys diff --git a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp index 8545ebd9cb..c042dcef01 100644 --- a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp +++ b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp @@ -21,6 +21,7 @@ #include "qpid/sys/AsynchIO.h" #include "qpid/sys/Socket.h" +#include "qpid/sys/SocketAddress.h" #include "qpid/sys/Poller.h" #include "qpid/sys/DispatchHandle.h" #include "qpid/sys/Time.h" @@ -37,6 +38,7 @@ #include <string.h> #include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> using namespace qpid::sys; @@ -161,11 +163,12 @@ class AsynchConnector : public qpid::sys::AsynchConnector, private: void connComplete(DispatchHandle& handle); - void failure(int, std::string); + void failure(int, const std::string&); private: ConnectedCallback connCallback; FailedCallback failCallback; + std::string errMsg; const Socket& socket; public: @@ -174,7 +177,7 @@ public: std::string hostname, uint16_t port, ConnectedCallback connCb, - FailedCallback failCb = 0); + FailedCallback failCb); }; AsynchConnector::AsynchConnector(const Socket& s, @@ -192,12 +195,17 @@ AsynchConnector::AsynchConnector(const Socket& s, socket(s) { socket.setNonblocking(); + SocketAddress sa(hostname, boost::lexical_cast<std::string>(port)); try { - socket.connect(hostname, port); - startWatch(poller); + socket.connect(sa); } catch(std::exception& e) { - failure(-1, std::string(e.what())); + // Defer reporting failure + startWatch(poller); + errMsg = e.what(); + DispatchHandle::call(boost::bind(&AsynchConnector::failure, this, -1, errMsg)); + return; } + startWatch(poller); } void AsynchConnector::connComplete(DispatchHandle& h) @@ -209,17 +217,13 @@ void AsynchConnector::connComplete(DispatchHandle& h) connCallback(socket); DispatchHandle::doDelete(); } else { - failure(errCode, std::string(strError(errCode))); + failure(errCode, strError(errCode)); } } -void AsynchConnector::failure(int errCode, std::string message) +void AsynchConnector::failure(int errCode, const std::string& message) { - if (failCallback) - failCallback(errCode, message); - - socket.close(); - delete &socket; + failCallback(socket, errCode, message); DispatchHandle::doDelete(); } @@ -467,7 +471,8 @@ void AsynchIO::readable(DispatchHandle& h) { threadReadTotal += rc; readTotal += rc; - if (!readCallback(*this, buff)) { + readCallback(*this, buff); + if (readingStopped) { // We have been flow controlled. break; } diff --git a/qpid/cpp/src/qpid/sys/posix/Socket.cpp b/qpid/cpp/src/qpid/sys/posix/Socket.cpp index 31044be9ca..02004b1999 100644 --- a/qpid/cpp/src/qpid/sys/posix/Socket.cpp +++ b/qpid/cpp/src/qpid/sys/posix/Socket.cpp @@ -21,6 +21,7 @@ #include "qpid/sys/Socket.h" +#include "qpid/sys/SocketAddress.h" #include "qpid/sys/posix/check.h" #include "qpid/sys/posix/PrivatePosix.h" @@ -36,6 +37,7 @@ #include <iostream> #include <boost/format.hpp> +#include <boost/lexical_cast.hpp> namespace qpid { namespace sys { @@ -126,42 +128,23 @@ void Socket::setNonblocking() const { QPID_POSIX_CHECK(::fcntl(impl->fd, F_SETFL, O_NONBLOCK)); } -namespace { -const char* h_errstr(int e) { - switch (e) { - case HOST_NOT_FOUND: return "Host not found"; - case NO_ADDRESS: return "Name does not have an IP address"; - case TRY_AGAIN: return "A temporary error occurred on an authoritative name server."; - case NO_RECOVERY: return "Non-recoverable name server error"; - default: return "Unknown error"; - } -} +void Socket::connect(const std::string& host, uint16_t port) const +{ + SocketAddress sa(host, boost::lexical_cast<std::string>(port)); + connect(sa); } -void Socket::connect(const std::string& host, uint16_t p) const +void Socket::connect(const SocketAddress& addr) const { - std::stringstream portstream; - portstream << p; - std::string port = portstream.str(); - connectname = host + ":" + port; + connectname = addr.asString(); const int& socket = impl->fd; - ::addrinfo *res; - ::addrinfo hints; - ::memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; // In order to allow AF_INET6 we'd have to change createTcp() as well - hints.ai_socktype = SOCK_STREAM; - int n = ::getaddrinfo(host.c_str(), port.c_str(), &hints, &res); - if (n != 0) - throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n))); // TODO the correct thing to do here is loop on failure until you've used all the returned addresses - if ((::connect(socket, res->ai_addr, res->ai_addrlen) < 0) && + if ((::connect(socket, getAddrInfo(addr).ai_addr, getAddrInfo(addr).ai_addrlen) < 0) && (errno != EINPROGRESS)) { - ::freeaddrinfo(res); - throw qpid::Exception(QPID_MSG(strError(errno) << ": " << host << ":" << port)); + throw Exception(QPID_MSG(strError(errno) << ": " << connectname)); } - ::freeaddrinfo(res); } void @@ -178,15 +161,14 @@ int Socket::listen(uint16_t port, int backlog) const const int& socket = impl->fd; int yes=1; QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes))); - struct sockaddr_in name; - name.sin_family = AF_INET; - name.sin_port = htons(port); - name.sin_addr.s_addr = 0; - if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0) + + SocketAddress sa("", boost::lexical_cast<std::string>(port)); + if (::bind(socket, getAddrInfo(sa).ai_addr, getAddrInfo(sa).ai_addrlen) < 0) throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno))); if (::listen(socket, backlog) < 0) throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno))); - + + struct sockaddr_in name; socklen_t namelen = sizeof(name); if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0) throw QPID_POSIX_ERROR(errno); @@ -226,9 +208,10 @@ std::string Socket::getPeername() const std::string Socket::getPeerAddress() const { - if (!connectname.empty()) - return std::string (connectname); - return getName(impl->fd, false, true); + if (connectname.empty()) { + connectname = getName(impl->fd, false, true); + } + return connectname; } std::string Socket::getLocalAddress() const diff --git a/qpid/cpp/src/qpid/sys/posix/SocketAddress.cpp b/qpid/cpp/src/qpid/sys/posix/SocketAddress.cpp new file mode 100644 index 0000000000..fe8812299c --- /dev/null +++ b/qpid/cpp/src/qpid/sys/posix/SocketAddress.cpp @@ -0,0 +1,71 @@ +/* + * + * 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/SocketAddress.h" + +#include "qpid/sys/posix/check.h" + +#include <sys/socket.h> +#include <string.h> +#include <netdb.h> + +namespace qpid { +namespace sys { + +SocketAddress::SocketAddress(const std::string& host0, const std::string& port0) : + host(host0), + port(port0), + addrInfo(0) +{ + ::addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; // In order to allow AF_INET6 we'd have to change createTcp() as well + hints.ai_socktype = SOCK_STREAM; + + const char* node = 0; + if (host.empty()) { + hints.ai_flags |= AI_PASSIVE; + } else { + node = host.c_str(); + } + const char* service = port.empty() ? "0" : port.c_str(); + + int n = ::getaddrinfo(node, service, &hints, &addrInfo); + if (n != 0) + throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n))); +} + +SocketAddress::~SocketAddress() +{ + ::freeaddrinfo(addrInfo); +} + +std::string SocketAddress::asString() const +{ + return host + ":" + port; +} + +const ::addrinfo& getAddrInfo(const SocketAddress& sa) +{ + return *sa.addrInfo; +} + +}} diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp b/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp index 9da6c835ce..d39f7885a5 100644 --- a/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp +++ b/qpid/cpp/src/qpid/sys/rdma/RdmaClient.cpp @@ -40,6 +40,7 @@ using std::rand; using qpid::sys::Poller; using qpid::sys::Dispatcher; +using qpid::sys::SocketAddress; using qpid::sys::AbsTime; using qpid::sys::Duration; using qpid::sys::TIME_SEC; @@ -154,18 +155,8 @@ using namespace qpid::tests; int main(int argc, char* argv[]) { vector<string> args(&argv[0], &argv[argc]); - ::addrinfo *res; - ::addrinfo hints = {}; - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; + string host = args[1]; string port = (args.size() < 3) ? "20079" : args[2]; - int n = ::getaddrinfo(args[1].c_str(), port.c_str(), &hints, &res); - if (n<0) { - cerr << "Can't find information for: " << args[1] << "\n"; - return 1; - } else { - cout << "Connecting to: " << args[1] << ":" << port <<"\n"; - } if (args.size() > 3) msgsize = atoi(args[3].c_str()); @@ -181,8 +172,10 @@ int main(int argc, char* argv[]) { boost::shared_ptr<Poller> p(new Poller()); Dispatcher d(p); + SocketAddress sa(host, port); + cout << "Connecting to: " << sa.asString() <<"\n"; Rdma::Connector c( - *res->ai_addr, + sa, Rdma::ConnectionParams(msgsize, Rdma::DEFAULT_WR_ENTRIES), boost::bind(&connected, p, _1, _2), boost::bind(&connectionError, p, _1, _2), diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp b/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp index 491c1612fd..8d06fccba1 100644 --- a/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp +++ b/qpid/cpp/src/qpid/sys/rdma/RdmaIO.cpp @@ -26,6 +26,7 @@ #include <iostream> #include <boost/bind.hpp> +using qpid::sys::SocketAddress; using qpid::sys::DispatchHandle; using qpid::sys::Poller; @@ -461,7 +462,7 @@ namespace Rdma { } Listener::Listener( - const sockaddr& src, + const SocketAddress& src, const ConnectionParams& cp, EstablishedCallback ec, ErrorCallback errc, @@ -541,7 +542,7 @@ namespace Rdma { } Connector::Connector( - const sockaddr& dst, + const SocketAddress& dst, const ConnectionParams& cp, ConnectedCallback cc, ErrorCallback errc, diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h b/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h index 697d9387ce..12a1b98d24 100644 --- a/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h +++ b/qpid/cpp/src/qpid/sys/rdma/RdmaIO.h @@ -27,6 +27,7 @@ #include "qpid/sys/Dispatcher.h" #include "qpid/sys/DispatchHandle.h" #include "qpid/sys/Mutex.h" +#include "qpid/sys/SocketAddress.h" #include <netinet/in.h> @@ -173,14 +174,14 @@ namespace Rdma { class Listener : public ConnectionManager { - sockaddr src_addr; + qpid::sys::SocketAddress src_addr; ConnectionParams checkConnectionParams; ConnectionRequestCallback connectionRequestCallback; EstablishedCallback establishedCallback; public: Listener( - const sockaddr& src, + const qpid::sys::SocketAddress& src, const ConnectionParams& cp, EstablishedCallback ec, ErrorCallback errc, @@ -198,14 +199,14 @@ namespace Rdma { class Connector : public ConnectionManager { - sockaddr dst_addr; + qpid::sys::SocketAddress dst_addr; ConnectionParams connectionParams; RejectedCallback rejectedCallback; ConnectedCallback connectedCallback; public: Connector( - const sockaddr& dst, + const qpid::sys::SocketAddress& dst, const ConnectionParams& cp, ConnectedCallback cc, ErrorCallback errc, diff --git a/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp b/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp index 07d6379362..4c11ba23eb 100644 --- a/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp +++ b/qpid/cpp/src/qpid/sys/rdma/RdmaServer.cpp @@ -35,6 +35,7 @@ using std::string; using std::cout; using std::cerr; +using qpid::sys::SocketAddress; using qpid::sys::Poller; using qpid::sys::Dispatcher; @@ -144,20 +145,15 @@ using namespace qpid::tests; int main(int argc, char* argv[]) { vector<string> args(&argv[0], &argv[argc]); - ::sockaddr_in sin; - - int port = (args.size() < 2) ? 20079 : atoi(args[1].c_str()); + std::string port = (args.size() < 2) ? "20079" : args[1]; cout << "Listening on port: " << port << "\n"; - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = INADDR_ANY; - try { boost::shared_ptr<Poller> p(new Poller()); Dispatcher d(p); - Rdma::Listener a((const sockaddr&)(sin), + SocketAddress sa("", port); + Rdma::Listener a(sa, Rdma::ConnectionParams(16384, Rdma::DEFAULT_WR_ENTRIES), boost::bind(connected, p, _1), connectionError, diff --git a/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h b/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h index aa2e516e6b..e11497dc02 100644 --- a/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h +++ b/qpid/cpp/src/qpid/sys/rdma/rdma_wrap.h @@ -350,9 +350,9 @@ namespace Rdma { return ConnectionEvent(e); } - void bind(sockaddr& src_addr) const { + void bind(qpid::sys::SocketAddress& src_addr) const { assert(id.get()); - CHECK(::rdma_bind_addr(id.get(), &src_addr)); + CHECK(::rdma_bind_addr(id.get(), getAddrInfo(src_addr).ai_addr)); } void listen(int backlog = DEFAULT_BACKLOG) const { @@ -361,12 +361,11 @@ namespace Rdma { } void resolve_addr( - sockaddr& dst_addr, - sockaddr* src_addr = 0, + qpid::sys::SocketAddress& dst_addr, int timeout_ms = DEFAULT_TIMEOUT) const { assert(id.get()); - CHECK(::rdma_resolve_addr(id.get(), src_addr, &dst_addr, timeout_ms)); + CHECK(::rdma_resolve_addr(id.get(), 0, getAddrInfo(dst_addr).ai_addr, timeout_ms)); } void resolve_route(int timeout_ms = DEFAULT_TIMEOUT) const { diff --git a/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp b/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp index 8905b87838..475b18600d 100644 --- a/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp +++ b/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp @@ -634,7 +634,7 @@ void AsynchIO::readComplete(AsynchReadResult *result) { if (status == 0 && bytes > 0) { bool restartRead = true; // May not if receiver doesn't want more if (readCallback) - restartRead = readCallback(*this, result->getBuff()); + readCallback(*this, result->getBuff()); if (restartRead) startReading(); } diff --git a/qpid/cpp/src/qpid/xml/XmlExchange.cpp b/qpid/cpp/src/qpid/xml/XmlExchange.cpp index 8a1ef6149e..472ca28954 100644 --- a/qpid/cpp/src/qpid/xml/XmlExchange.cpp +++ b/qpid/cpp/src/qpid/xml/XmlExchange.cpp @@ -206,45 +206,22 @@ void XmlExchange::route(Deliverable& msg, const string& routingKey, const FieldT PreRoute pr(msg, this); try { XmlBinding::vector::ConstPtr p; - { + BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >); + { RWlock::ScopedRlock l(lock); - p = bindingsMap[routingKey].snapshot(); - if (!p) return; - } - int count(0); + p = bindingsMap[routingKey].snapshot(); + if (!p.get()) return; + } for (std::vector<XmlBinding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++) { if (matches((*i)->xquery, msg, args, (*i)->parse_message_content)) { - msg.deliverTo((*i)->queue); - count++; - QPID_LOG(trace, "Delivered to queue" ); - - if ((*i)->mgmtBinding != 0) - (*i)->mgmtBinding->inc_msgMatched (); + b->push_back(*i); } - } - if (!count) { - QPID_LOG(warning, "XMLExchange " << getName() << ": could not route message with query " << routingKey); - if (mgmtExchange != 0) { - mgmtExchange->inc_msgDrops (); - mgmtExchange->inc_byteDrops (msg.contentSize ()); - } - } else { - if (mgmtExchange != 0) { - mgmtExchange->inc_msgRoutes (count); - mgmtExchange->inc_byteRoutes (count * msg.contentSize ()); - } - } - - if (mgmtExchange != 0) { - mgmtExchange->inc_msgReceives (); - mgmtExchange->inc_byteReceives (msg.contentSize ()); - } + } + doRoute(msg, b); } catch (...) { QPID_LOG(warning, "XMLExchange " << getName() << ": exception routing message with query " << routingKey); } - - } diff --git a/qpid/cpp/src/qpidd.cpp b/qpid/cpp/src/qpidd.cpp index 1839a62205..f2b46942fb 100644 --- a/qpid/cpp/src/qpidd.cpp +++ b/qpid/cpp/src/qpidd.cpp @@ -36,25 +36,29 @@ int main(int argc, char* argv[]) { try { - { - BootstrapOptions bootOptions(argv[0]); - string defaultPath (bootOptions.module.loadDir); - // Parse only the common, load, and log options to see which - // modules need to be loaded. Once the modules are loaded, - // the command line will be re-parsed with all of the - // module-supplied options. + BootstrapOptions bootOptions(argv[0]); + string defaultPath (bootOptions.module.loadDir); + // Parse only the common, load, and log options to see which + // modules need to be loaded. Once the modules are loaded, + // the command line will be re-parsed with all of the + // module-supplied options. + try { bootOptions.parse (argc, argv, bootOptions.common.config, true); qpid::log::Logger::instance().configure(bootOptions.log); + } catch (const std::exception& e) { + // Couldn't configure logging so write the message direct to stderr. + cerr << "Unexpected error: " << e.what() << endl; + return 1; + } - for (vector<string>::iterator iter = bootOptions.module.load.begin(); - iter != bootOptions.module.load.end(); - iter++) - qpid::tryShlib (iter->data(), false); + for (vector<string>::iterator iter = bootOptions.module.load.begin(); + iter != bootOptions.module.load.end(); + iter++) + qpid::tryShlib (iter->data(), false); - if (!bootOptions.module.noLoad) { - bool isDefault = defaultPath == bootOptions.module.loadDir; - qpid::loadModuleDir (bootOptions.module.loadDir, isDefault); - } + if (!bootOptions.module.noLoad) { + bool isDefault = defaultPath == bootOptions.module.loadDir; + qpid::loadModuleDir (bootOptions.module.loadDir, isDefault); } // Parse options diff --git a/qpid/cpp/src/tests/AsyncCompletion.cpp b/qpid/cpp/src/tests/AsyncCompletion.cpp index 4492e6b6bc..e32097106f 100644 --- a/qpid/cpp/src/tests/AsyncCompletion.cpp +++ b/qpid/cpp/src/tests/AsyncCompletion.cpp @@ -70,9 +70,11 @@ class AsyncCompletionMessageStore : public NullMessageStore { QPID_AUTO_TEST_SUITE(AsyncCompletionTestSuite) QPID_AUTO_TEST_CASE(testWaitTillComplete) { - AsyncCompletionMessageStore* store = new AsyncCompletionMessageStore; SessionFixture fix; - fix.broker->setStore(store); // Broker will delete store. + AsyncCompletionMessageStore* store = new AsyncCompletionMessageStore; + boost::shared_ptr<qpid::broker::MessageStore> p; + p.reset(store); + fix.broker->setStore(p); AsyncSession s = fix.session; static const int count = 3; diff --git a/qpid/cpp/src/tests/ClusterFixture.h b/qpid/cpp/src/tests/ClusterFixture.h index 5952cc1736..1eee32b9a4 100644 --- a/qpid/cpp/src/tests/ClusterFixture.h +++ b/qpid/cpp/src/tests/ClusterFixture.h @@ -75,10 +75,10 @@ class ClusterFixture : public vector<uint16_t> { /** @param localIndex can be -1 meaning don't automatically start a local broker. * A local broker can be started with addLocal(). */ - ClusterFixture(size_t n, const Args& args, int localIndex=0); + ClusterFixture(size_t n, const Args& args, int localIndex=-1); /**@param updateArgs function is passed the index of the cluster member and can update the arguments. */ - ClusterFixture(size_t n, boost::function<void (Args&, size_t)> updateArgs, int localIndex); + ClusterFixture(size_t n, boost::function<void (Args&, size_t)> updateArgs, int localIndex=-1); void add(size_t n) { for (size_t i=0; i < n; ++i) add(); } void add(); // Add a broker. diff --git a/qpid/cpp/src/tests/ExchangeTest.cpp b/qpid/cpp/src/tests/ExchangeTest.cpp index 44835c6184..88a1cd99c2 100644 --- a/qpid/cpp/src/tests/ExchangeTest.cpp +++ b/qpid/cpp/src/tests/ExchangeTest.cpp @@ -60,7 +60,7 @@ QPID_AUTO_TEST_CASE(testMe) queue.reset(); queue2.reset(); - intrusive_ptr<Message> msgPtr(MessageUtils::createMessage("exchange", "key", "id")); + intrusive_ptr<Message> msgPtr(MessageUtils::createMessage("exchange", "key", false, "id")); DeliverableMessage msg(msgPtr); topic.route(msg, "abc", 0); direct.route(msg, "abc", 0); diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am index a15ba3578c..15133505a3 100644 --- a/qpid/cpp/src/tests/Makefile.am +++ b/qpid/cpp/src/tests/Makefile.am @@ -22,6 +22,7 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src PUBLIC_INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include # Use public API only abs_builddir=@abs_builddir@ +abs_srcdir=@abs_srcdir@ extra_libs = lib_client = $(abs_builddir)/../libqpidclient.la lib_common = $(abs_builddir)/../libqpidcommon.la @@ -275,7 +276,6 @@ qpid_stream_INCLUDES=$(PUBLIC_INCLUDES) qpid_stream_SOURCES=qpid_stream.cpp qpid_stream_LDADD=$(lib_client) - TESTS_ENVIRONMENT = \ VALGRIND=$(VALGRIND) \ srcdir=$(srcdir) \ @@ -311,7 +311,7 @@ EXTRA_DIST += \ TxMocks.h \ replication_test \ run_perftest \ - ring_queue_test \ + ring_queue_test \ run_ring_queue_test check_LTLIBRARIES += libdlclose_noop.la @@ -327,25 +327,47 @@ LONG_TESTS+=start_broker fanout_perftest shared_perftest multiq_perftest topic_p run_failover_soak reliable_replication_test \ federated_cluster_test_with_node_failure -EXTRA_DIST+=fanout_perftest shared_perftest multiq_perftest topic_perftest run_failover_soak reliable_replication_test \ - federated_cluster_test_with_node_failure \ - tests.sln \ - client_test.vcproj \ - consume.vcproj \ - echotest.vcproj \ - header_test.vcproj \ - latencytest.vcproj \ - perftest.vcproj \ - publish.vcproj \ - receiver.vcproj \ - sender.vcproj \ - shlibtest.vcproj \ - topic_listener.vcproj \ - topic_publisher.vcproj \ - txjob.vcproj \ - txshift.vcproj \ - txtest.vcproj \ - unit_test.vcproj +EXTRA_DIST+= \ + python_env.sh \ + fanout_perftest \ + shared_perftest \ + multiq_perftest \ + topic_perftest \ + run_failover_soak \ + reliable_replication_test \ + federated_cluster_test_with_node_failure \ + tests.sln \ + client_test.vcproj \ + consume.vcproj \ + echotest.vcproj \ + header_test.vcproj \ + latencytest.vcproj \ + perftest.vcproj \ + publish.vcproj \ + receiver.vcproj \ + sender.vcproj \ + shlibtest.vcproj \ + topic_listener.vcproj \ + topic_publisher.vcproj \ + txjob.vcproj \ + txshift.vcproj \ + txtest.vcproj \ + unit_test.vcproj check-long: $(MAKE) check TESTS="$(LONG_TESTS)" VALGRIND= + +check: python_prep + +PYTHON_SRC_DIR=$(abs_srcdir)/../../../python +PYTHON_BLD_DIR=$(abs_builddir)/python +AMQP_SPEC_DIR=$(abs_srcdir)/../../../specs + +# Generate python client as part of the all-am target so it gets built before tests. +all-am: python_prep + +python_prep: + if test -d $(PYTHON_SRC_DIR) -a -d $(AMQP_SPEC_DIR); \ + then $(MAKE) -C $(PYTHON_SRC_DIR) install PREFIX=$(PYTHON_BLD_DIR) PYTHON_LIB=$(PYTHON_BLD_DIR) EXEC_PREFIX=$(PYTHON_BLD_DIR)/commands AMQP_SPEC_DIR=$(AMQP_SPEC_DIR); \ + else echo "WARNING: python client not built, missing one of $(PYTHON_SRC_DIR) $(AMQP_SPEC_DIR)"; fi + diff --git a/qpid/cpp/src/tests/MessageUtils.h b/qpid/cpp/src/tests/MessageUtils.h index dae74cce7d..a1b140d484 100644 --- a/qpid/cpp/src/tests/MessageUtils.h +++ b/qpid/cpp/src/tests/MessageUtils.h @@ -34,7 +34,8 @@ namespace tests { struct MessageUtils { static boost::intrusive_ptr<Message> createMessage(const string& exchange="", const string& routingKey="", - const Uuid& messageId=Uuid(true), uint64_t contentSize = 0) + const bool durable = false, const Uuid& messageId=Uuid(true), + uint64_t contentSize = 0) { boost::intrusive_ptr<broker::Message> msg(new broker::Message()); @@ -47,6 +48,8 @@ struct MessageUtils props->setContentLength(contentSize); props->setMessageId(messageId); msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey); + if (durable) + msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setDeliveryMode(2); return msg; } diff --git a/qpid/cpp/src/tests/MessagingSessionTests.cpp b/qpid/cpp/src/tests/MessagingSessionTests.cpp index f5a5420d3a..206f5ba691 100644 --- a/qpid/cpp/src/tests/MessagingSessionTests.cpp +++ b/qpid/cpp/src/tests/MessagingSessionTests.cpp @@ -22,6 +22,10 @@ #include "test_tools.h" #include "BrokerFixture.h" #include "qpid/messaging/Connection.h" +#include "qpid/messaging/ListContent.h" +#include "qpid/messaging/ListView.h" +#include "qpid/messaging/MapContent.h" +#include "qpid/messaging/MapView.h" #include "qpid/messaging/Message.h" #include "qpid/messaging/MessageListener.h" #include "qpid/messaging/Receiver.h" @@ -160,7 +164,7 @@ struct MessageDataCollector : MessageListener std::vector<std::string> messageData; void received(Message& message) { - messageData.push_back(message.getBytes()); + messageData.push_back(message.getContent()); } }; @@ -169,7 +173,7 @@ std::vector<std::string> fetch(Receiver& receiver, int count, qpid::sys::Duratio std::vector<std::string> data; Message message; for (int i = 0; i < count && receiver.fetch(message, timeout); i++) { - data.push_back(message.getBytes()); + data.push_back(message.getContent()); } return data; } @@ -183,7 +187,7 @@ QPID_AUTO_TEST_CASE(testSimpleSendReceive) 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()); + BOOST_CHECK_EQUAL(in.getContent(), out.getContent()); } QPID_AUTO_TEST_CASE(testSendReceiveHeaders) @@ -199,7 +203,7 @@ QPID_AUTO_TEST_CASE(testSendReceiveHeaders) Message in; for (uint i = 0; i < 10; ++i) { BOOST_CHECK(receiver.fetch(in, 5 * qpid::sys::TIME_SEC)); - BOOST_CHECK_EQUAL(in.getBytes(), out.getBytes()); + BOOST_CHECK_EQUAL(in.getContent(), out.getContent()); BOOST_CHECK_EQUAL(in.getHeaders()["a"].asUint32(), i); fix.session.acknowledge(); } @@ -229,22 +233,22 @@ QPID_AUTO_TEST_CASE(testSimpleTopic) Receiver sub1 = fix.session.createReceiver(fix.topic); sub1.setCapacity(10u); sub1.start(); - msg.setBytes("two"); + msg.setContent("two"); sender.send(msg); Receiver sub2 = fix.session.createReceiver(fix.topic); sub2.setCapacity(10u); sub2.start(); - msg.setBytes("three"); + msg.setContent("three"); sender.send(msg); Receiver sub3 = fix.session.createReceiver(fix.topic); sub3.setCapacity(10u); sub3.start(); - msg.setBytes("four"); + msg.setContent("four"); sender.send(msg); BOOST_CHECK_EQUAL(fetch(sub2, 2), boost::assign::list_of<std::string>("three")("four")); sub2.cancel(); - msg.setBytes("five"); + msg.setContent("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")); @@ -274,7 +278,7 @@ QPID_AUTO_TEST_CASE(testSessionFetch) 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()); + BOOST_CHECK_EQUAL(msg.getContent(), (boost::format("Message_%1%") % (i+1)).str()); } } @@ -307,13 +311,16 @@ 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; + MapContent content(out); + content["abc"] = "def"; + content["pi"] = 3.14f; + content.encode(); 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); + MapView view(in); + BOOST_CHECK_EQUAL(view["abc"].asString(), "def"); + BOOST_CHECK_EQUAL(view["pi"].asFloat(), 3.14f); fix.session.acknowledge(); } @@ -322,23 +329,31 @@ 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; + ListContent content(out); + content.push_back(Variant("abc")); + content.push_back(Variant(1234)); + content.push_back(Variant("def")); + content.push_back(Variant(56.789)); + content.encode(); 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); + ListView view(in); + BOOST_CHECK_EQUAL(view.size(), content.size()); + BOOST_CHECK_EQUAL(view.front().asString(), "abc"); + BOOST_CHECK_EQUAL(view.back().asDouble(), 56.789); + + ListView::const_iterator i = view.begin(); + BOOST_CHECK(i != view.end()); + BOOST_CHECK_EQUAL(i->asString(), "abc"); + BOOST_CHECK(++i != view.end()); + BOOST_CHECK_EQUAL(i->asInt64(), 1234); + BOOST_CHECK(++i != view.end()); + BOOST_CHECK_EQUAL(i->asString(), "def"); + BOOST_CHECK(++i != view.end()); + BOOST_CHECK_EQUAL(i->asDouble(), 56.789); + BOOST_CHECK(++i == view.end()); + fix.session.acknowledge(); } @@ -352,10 +367,10 @@ QPID_AUTO_TEST_CASE(testReject) 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()); + BOOST_CHECK_EQUAL(in.getContent(), m1.getContent()); fix.session.reject(in); in = receiver.fetch(5 * qpid::sys::TIME_SEC); - BOOST_CHECK_EQUAL(in.getBytes(), m2.getBytes()); + BOOST_CHECK_EQUAL(in.getContent(), m2.getContent()); fix.session.acknowledge(); } @@ -384,15 +399,15 @@ QPID_AUTO_TEST_CASE(testAvailable) for (uint i = 0; i < 5; ++i) { BOOST_CHECK_EQUAL(fix.session.available(), 15u - 2*i); BOOST_CHECK_EQUAL(r1.available(), 10u - i); - BOOST_CHECK_EQUAL(r1.fetch().getBytes(), (boost::format("A_%1%") % (i+1)).str()); + BOOST_CHECK_EQUAL(r1.fetch().getContent(), (boost::format("A_%1%") % (i+1)).str()); BOOST_CHECK_EQUAL(r2.available(), 5u - i); - BOOST_CHECK_EQUAL(r2.fetch().getBytes(), (boost::format("B_%1%") % (i+1)).str()); + BOOST_CHECK_EQUAL(r2.fetch().getContent(), (boost::format("B_%1%") % (i+1)).str()); fix.session.acknowledge(); } for (uint i = 5; i < 10; ++i) { BOOST_CHECK_EQUAL(fix.session.available(), 10u - i); BOOST_CHECK_EQUAL(r1.available(), 10u - i); - BOOST_CHECK_EQUAL(r1.fetch().getBytes(), (boost::format("A_%1%") % (i+1)).str()); + BOOST_CHECK_EQUAL(r1.fetch().getContent(), (boost::format("A_%1%") % (i+1)).str()); } } @@ -405,7 +420,7 @@ QPID_AUTO_TEST_CASE(testPendingAck) } Receiver receiver = fix.session.createReceiver(fix.queue); for (uint i = 0; i < 10; ++i) { - BOOST_CHECK_EQUAL(receiver.fetch().getBytes(), (boost::format("Message_%1%") % (i+1)).str()); + BOOST_CHECK_EQUAL(receiver.fetch().getContent(), (boost::format("Message_%1%") % (i+1)).str()); } BOOST_CHECK_EQUAL(fix.session.pendingAck(), 0u); fix.session.acknowledge(); @@ -431,7 +446,7 @@ QPID_AUTO_TEST_CASE(testPendingSend) Receiver receiver = fix.session.createReceiver(fix.queue); for (uint i = 0; i < 10; ++i) { - BOOST_CHECK_EQUAL(receiver.fetch().getBytes(), (boost::format("Message_%1%") % (i+1)).str()); + BOOST_CHECK_EQUAL(receiver.fetch().getContent(), (boost::format("Message_%1%") % (i+1)).str()); } fix.session.acknowledge(); } diff --git a/qpid/cpp/src/tests/PartialFailure.cpp b/qpid/cpp/src/tests/PartialFailure.cpp index 8d9970f909..5de8ecb189 100644 --- a/qpid/cpp/src/tests/PartialFailure.cpp +++ b/qpid/cpp/src/tests/PartialFailure.cpp @@ -105,7 +105,6 @@ QPID_AUTO_TEST_CASE(testCoincidentErrors) { } } -#if 0 // FIXME aconway 2009-07-30: // Verify normal cluster-wide errors. QPID_AUTO_TEST_CASE(testNormalErrors) { // FIXME aconway 2009-04-10: Would like to put a scope just around @@ -120,7 +119,7 @@ QPID_AUTO_TEST_CASE(testNormalErrors) { { ScopedSuppressLogging allQuiet; - queueAndsub(c0); + queueAndSub(c0); c0.session.messageTransfer(content=Message("x", "c0")); BOOST_CHECK_EQUAL(c0.lq.get(TIMEOUT).getData(), "x"); @@ -258,7 +257,7 @@ QPID_AUTO_TEST_CASE(testPartialFailureMemberLeaves) { } } #endif -#endif // FIXME aconway 2009-07-30: + QPID_AUTO_TEST_SUITE_END() }} // namespace qpid::tests diff --git a/qpid/cpp/src/tests/QueuePolicyTest.cpp b/qpid/cpp/src/tests/QueuePolicyTest.cpp index f40d30b588..875976db85 100644 --- a/qpid/cpp/src/tests/QueuePolicyTest.cpp +++ b/qpid/cpp/src/tests/QueuePolicyTest.cpp @@ -48,56 +48,56 @@ QueuedMessage createMessage(uint32_t size) QPID_AUTO_TEST_CASE(testCount) { - std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(5, 0)); + std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 5, 0)); BOOST_CHECK_EQUAL((uint64_t) 0, policy->getMaxSize()); BOOST_CHECK_EQUAL((uint32_t) 5, policy->getMaxCount()); QueuedMessage msg = createMessage(10); for (size_t i = 0; i < 5; i++) { - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); } try { - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); BOOST_FAIL("Policy did not fail on enqueuing sixth message"); } catch (const ResourceLimitExceededException&) {} policy->dequeued(msg); - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); try { - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); BOOST_FAIL("Policy did not fail on enqueuing sixth message (after dequeue)"); } catch (const ResourceLimitExceededException&) {} } QPID_AUTO_TEST_CASE(testSize) { - std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(0, 50)); + std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 0, 50)); QueuedMessage msg = createMessage(10); for (size_t i = 0; i < 5; i++) { - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); } try { - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy); } catch (const ResourceLimitExceededException&) {} policy->dequeued(msg); - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); try { - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); BOOST_FAIL("Policy did not fail on aggregate size exceeding 50 (after dequeue). " << *policy); } catch (const ResourceLimitExceededException&) {} } QPID_AUTO_TEST_CASE(testBoth) { - std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(5, 50)); + std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 5, 50)); try { QueuedMessage msg = createMessage(51); - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); BOOST_FAIL("Policy did not fail on single message exceeding 50. " << *policy); } catch (const ResourceLimitExceededException&) {} @@ -108,17 +108,17 @@ QPID_AUTO_TEST_CASE(testBoth) messages.push_back(createMessage(2)); messages.push_back(createMessage(7)); for (size_t i = 0; i < messages.size(); i++) { - policy->tryEnqueue(messages[i]); + policy->tryEnqueue(messages[i].payload); } //size = 45 at this point, count = 5 try { QueuedMessage msg = createMessage(5); - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); BOOST_FAIL("Policy did not fail on count exceeding 6. " << *policy); } catch (const ResourceLimitExceededException&) {} try { QueuedMessage msg = createMessage(10); - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy); } catch (const ResourceLimitExceededException&) {} @@ -126,7 +126,7 @@ QPID_AUTO_TEST_CASE(testBoth) policy->dequeued(messages[0]); try { QueuedMessage msg = createMessage(20); - policy->tryEnqueue(msg); + policy->tryEnqueue(msg.payload); } catch (const ResourceLimitExceededException&) { BOOST_FAIL("Policy failed incorrectly after dequeue. " << *policy); } @@ -135,10 +135,10 @@ QPID_AUTO_TEST_CASE(testBoth) QPID_AUTO_TEST_CASE(testSettings) { //test reading and writing the policy from/to field table - std::auto_ptr<QueuePolicy> a(QueuePolicy::createQueuePolicy(101, 303)); + std::auto_ptr<QueuePolicy> a(QueuePolicy::createQueuePolicy("test", 101, 303)); FieldTable settings; a->update(settings); - std::auto_ptr<QueuePolicy> b(QueuePolicy::createQueuePolicy(settings)); + std::auto_ptr<QueuePolicy> b(QueuePolicy::createQueuePolicy("test", settings)); BOOST_CHECK_EQUAL(a->getMaxCount(), b->getMaxCount()); BOOST_CHECK_EQUAL(a->getMaxSize(), b->getMaxSize()); } @@ -146,7 +146,7 @@ QPID_AUTO_TEST_CASE(testSettings) QPID_AUTO_TEST_CASE(testRingPolicy) { FieldTable args; - std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING); + std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING); policy->update(args); ProxySessionFixture f; @@ -175,7 +175,7 @@ QPID_AUTO_TEST_CASE(testRingPolicy) QPID_AUTO_TEST_CASE(testStrictRingPolicy) { FieldTable args; - std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING_STRICT); + std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING_STRICT); policy->update(args); ProxySessionFixture f; @@ -201,7 +201,7 @@ QPID_AUTO_TEST_CASE(testStrictRingPolicy) QPID_AUTO_TEST_CASE(testPolicyWithDtx) { FieldTable args; - std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::REJECT); + std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT); policy->update(args); ProxySessionFixture f; @@ -282,6 +282,22 @@ QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore) } catch (const ResourceLimitExceededException&) {} } +QPID_AUTO_TEST_CASE(testPolicyFailureOnCommit) +{ + FieldTable args; + std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT); + policy->update(args); + + ProxySessionFixture f; + std::string q("q"); + f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args); + f.session.txSelect(); + for (int i = 0; i < 10; i++) { + f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q)); + } + ScopedSuppressLogging sl; // Suppress messages for expected errors. + BOOST_CHECK_THROW(f.session.txCommit(), InternalErrorException); +} QPID_AUTO_TEST_SUITE_END() diff --git a/qpid/cpp/src/tests/QueueTest.cpp b/qpid/cpp/src/tests/QueueTest.cpp index 841a19f7c1..3cfaa763ca 100644 --- a/qpid/cpp/src/tests/QueueTest.cpp +++ b/qpid/cpp/src/tests/QueueTest.cpp @@ -18,10 +18,13 @@ * under the License. * */ +#include "MessageUtils.h" #include "unit_test.h" #include "test_tools.h" #include "qpid/Exception.h" #include "qpid/broker/Broker.h" +#include "qpid/broker/DeliverableMessage.h" +#include "qpid/broker/FanOutExchange.h" #include "qpid/broker/Queue.h" #include "qpid/broker/Deliverable.h" #include "qpid/broker/ExchangeRegistry.h" @@ -30,12 +33,16 @@ #include "qpid/broker/ExpiryPolicy.h" #include "qpid/framing/MessageTransferBody.h" #include "qpid/client/QueueOptions.h" +#include "qpid/framing/AMQFrame.h" +#include "qpid/framing/MessageTransferBody.h" +#include "qpid/framing/reply_exceptions.h" #include <iostream> #include "boost/format.hpp" using boost::intrusive_ptr; using namespace qpid; using namespace qpid::broker; +using namespace qpid::client; using namespace qpid::framing; using namespace qpid::sys; @@ -61,13 +68,14 @@ public: class FailOnDeliver : public Deliverable { - Message msg; + boost::intrusive_ptr<Message> msg; public: + FailOnDeliver() : msg(MessageUtils::createMessage()) {} void deliverTo(const boost::shared_ptr<Queue>& queue) { throw Exception(QPID_MSG("Invalid delivery to " << queue->getName())); } - Message& getMessage() { return msg; } + Message& getMessage() { return *(msg.get()); } }; intrusive_ptr<Message> create_message(std::string exchange, std::string routingKey) { @@ -210,8 +218,7 @@ QPID_AUTO_TEST_CASE(testDequeue){ } -QPID_AUTO_TEST_CASE(testBound) -{ +QPID_AUTO_TEST_CASE(testBound){ //test the recording of bindings, and use of those to allow a queue to be unbound string key("my-key"); FieldTable args; @@ -245,7 +252,6 @@ QPID_AUTO_TEST_CASE(testBound) } QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){ - client::QueueOptions args; args.setPersistLastNode(); @@ -273,14 +279,35 @@ QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){ } -class TestMessageStoreOC : public NullMessageStore +const std::string nullxid = ""; + +class SimpleDummyCtxt : public TransactionContext {}; + +class DummyCtxt : public TPCTransactionContext +{ + const std::string xid; + public: + DummyCtxt(const std::string& _xid) : xid(_xid) {} + static std::string getXid(TransactionContext& ctxt) + { + DummyCtxt* c(dynamic_cast<DummyCtxt*>(&ctxt)); + return c ? c->xid : nullxid; + } +}; + +class TestMessageStoreOC : public MessageStore { + std::set<std::string> prepared; + uint64_t nextPersistenceId; public: uint enqCnt; uint deqCnt; bool error; + TestMessageStoreOC() : MessageStore(),nextPersistenceId(1),enqCnt(0),deqCnt(0),error(false) {} + ~TestMessageStoreOC(){} + virtual void dequeue(TransactionContext*, const boost::intrusive_ptr<PersistableMessage>& /*msg*/, const PersistableQueue& /*queue*/) @@ -290,11 +317,12 @@ class TestMessageStoreOC : public NullMessageStore } virtual void enqueue(TransactionContext*, - const boost::intrusive_ptr<PersistableMessage>& /*msg*/, + const boost::intrusive_ptr<PersistableMessage>& msg, const PersistableQueue& /* queue */) { if (error) throw Exception("Enqueue error test"); enqCnt++; + msg->enqueueComplete(); } void createError() @@ -302,8 +330,32 @@ class TestMessageStoreOC : public NullMessageStore error=true; } - TestMessageStoreOC() : NullMessageStore(),enqCnt(0),deqCnt(0),error(false) {} - ~TestMessageStoreOC(){} + bool init(const Options*) { return true; } + void truncateInit(const bool) {} + void create(PersistableQueue& queue, const framing::FieldTable&) { queue.setPersistenceId(nextPersistenceId++); } + void destroy(PersistableQueue&) {} + void create(const PersistableExchange& exchange, const framing::FieldTable&) { exchange.setPersistenceId(nextPersistenceId++); } + void destroy(const PersistableExchange&) {} + void bind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&) {} + void unbind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&) {} + void create(const PersistableConfig& config) { config.setPersistenceId(nextPersistenceId++); } + void destroy(const PersistableConfig&) {} + void stage(const boost::intrusive_ptr<PersistableMessage>&) {} + void destroy(PersistableMessage&) {} + void appendContent(const boost::intrusive_ptr<const PersistableMessage>&, const std::string&) {} + void loadContent(const qpid::broker::PersistableQueue&, const boost::intrusive_ptr<const PersistableMessage>&, + std::string&, uint64_t, uint32_t) { throw qpid::framing::InternalErrorException("Can't load content; persistence not enabled"); } + void flush(const qpid::broker::PersistableQueue&) {} + uint32_t outstandingQueueAIO(const PersistableQueue&) { return 0; } + + std::auto_ptr<TransactionContext> begin() { return std::auto_ptr<TransactionContext>(new SimpleDummyCtxt()); } + std::auto_ptr<TPCTransactionContext> begin(const std::string& xid) { return std::auto_ptr<TPCTransactionContext>(new DummyCtxt(xid)); } + void prepare(TPCTransactionContext& ctxt) { prepared.insert(DummyCtxt::getXid(ctxt)); } + void commit(TransactionContext& ctxt) { prepared.erase(DummyCtxt::getXid(ctxt)); } + void abort(TransactionContext& ctxt) { prepared.erase(DummyCtxt::getXid(ctxt)); } + void collectPreparedXids(std::set<std::string>& out) { out.insert(prepared.begin(), prepared.end()); } + + void recover(RecoveryManager&) {} }; @@ -703,7 +755,7 @@ not requeued to the store. QPID_AUTO_TEST_CASE(testLastNodeJournalError){ /* -simulate store excption going into last node standing +simulate store exception going into last node standing */ TestMessageStoreOC testStore; @@ -727,16 +779,271 @@ simulate store excption going into last node standing } -intrusive_ptr<Message> mkMsg(std::string exchange, std::string routingKey) { - intrusive_ptr<Message> msg(new Message()); - AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0))); - AMQFrame header((AMQHeaderBody())); - msg->getFrames().append(method); - msg->getFrames().append(header); - msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey); +intrusive_ptr<Message> mkMsg(MessageStore& store, std::string content = "", bool durable = false) +{ + intrusive_ptr<Message> msg = MessageUtils::createMessage("", "", durable); + if (content.size()) MessageUtils::addContent(msg, content); + msg->setStore(&store); return msg; } +QPID_AUTO_TEST_CASE(testFlowToDiskBlocking){ + + TestMessageStoreOC testStore; + client::QueueOptions args0; // No size policy + client::QueueOptions args1; + args1.setSizePolicy(FLOW_TO_DISK, 0, 1); + client::QueueOptions args2; + args2.setSizePolicy(FLOW_TO_DISK, 0, 2); + + // --- Fanout exchange bound to single transient queue ------------------------------------------------------------- + + FanOutExchange sbtFanout1("sbtFanout1", false, args0); // single binding to transient queue + Queue::shared_ptr tq1(new Queue("tq1", true)); // transient w/ limit + tq1->configure(args1); + sbtFanout1.bind(tq1, "", 0); + + intrusive_ptr<Message> msg01 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content + DeliverableMessage dmsg01(msg01); + sbtFanout1.route(dmsg01, "", 0); // Brings queue 1 to capacity limit + msg01->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg01->isContentReleased(), false); + BOOST_CHECK_EQUAL(1u, tq1->getMessageCount()); + + intrusive_ptr<Message> msg02 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content + DeliverableMessage dmsg02(msg02); + BOOST_CHECK_THROW(sbtFanout1.route(dmsg02, "", 0), ResourceLimitExceededException); + msg02->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg02->isContentReleased(), false); + BOOST_CHECK_EQUAL(1u, tq1->getMessageCount()); + + intrusive_ptr<Message> msg03 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content + DeliverableMessage dmsg03(msg03); + BOOST_CHECK_THROW(sbtFanout1.route(dmsg03, "", 0), ResourceLimitExceededException); + msg03->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg03->isContentReleased(), false); + BOOST_CHECK_EQUAL(1u, tq1->getMessageCount()); + + intrusive_ptr<Message> msg04 = mkMsg(testStore); // transient no content + DeliverableMessage dmsg04(msg04); + BOOST_CHECK_THROW(sbtFanout1.route(dmsg04, "", 0), ResourceLimitExceededException); + msg04->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg04->isContentReleased(), false); + BOOST_CHECK_EQUAL(1u, tq1->getMessageCount()); + + intrusive_ptr<Message> msg05 = mkMsg(testStore, "", true); // durable no content + DeliverableMessage dmsg05(msg05); + BOOST_CHECK_THROW(sbtFanout1.route(dmsg05, "", 0), ResourceLimitExceededException); + msg05->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg05->isContentReleased(), false); + BOOST_CHECK_EQUAL(1u, tq1->getMessageCount()); + + // --- Fanout exchange bound to single durable queue --------------------------------------------------------------- + + FanOutExchange sbdFanout2("sbdFanout2", false, args0); // single binding to durable queue + Queue::shared_ptr dq2(new Queue("dq2", true, &testStore)); // durable w/ limit + dq2->configure(args1); + sbdFanout2.bind(dq2, "", 0); + + intrusive_ptr<Message> msg06 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content + DeliverableMessage dmsg06(msg06); + sbdFanout2.route(dmsg06, "", 0); // Brings queue 2 to capacity limit + msg06->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg06->isContentReleased(), false); + BOOST_CHECK_EQUAL(1u, dq2->getMessageCount()); + + intrusive_ptr<Message> msg07 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content + DeliverableMessage dmsg07(msg07); + sbdFanout2.route(dmsg07, "", 0); + msg07->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg07->isContentReleased(), true); + BOOST_CHECK_EQUAL(2u, dq2->getMessageCount()); + + intrusive_ptr<Message> msg08 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content + DeliverableMessage dmsg08(msg08); + sbdFanout2.route(dmsg08, "", 0); + msg08->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg08->isContentReleased(), true); + BOOST_CHECK_EQUAL(3u, dq2->getMessageCount()); + + intrusive_ptr<Message> msg09 = mkMsg(testStore); // transient no content + DeliverableMessage dmsg09(msg09); + sbdFanout2.route(dmsg09, "", 0); + msg09->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg09->isContentReleased(), true); + BOOST_CHECK_EQUAL(4u, dq2->getMessageCount()); + + intrusive_ptr<Message> msg10 = mkMsg(testStore, "", true); // durable no content + DeliverableMessage dmsg10(msg10); + sbdFanout2.route(dmsg10, "", 0); + msg10->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg10->isContentReleased(), true); + BOOST_CHECK_EQUAL(5u, dq2->getMessageCount()); + + // --- Fanout exchange bound to multiple durable queues ------------------------------------------------------------ + + FanOutExchange mbdFanout3("mbdFanout3", false, args0); // multiple bindings to durable queues + Queue::shared_ptr dq3(new Queue("dq3", true, &testStore)); // durable w/ limit 2 + dq3->configure(args2); + mbdFanout3.bind(dq3, "", 0); + Queue::shared_ptr dq4(new Queue("dq4", true, &testStore)); // durable w/ limit 1 + dq4->configure(args1); + mbdFanout3.bind(dq4, "", 0); + Queue::shared_ptr dq5(new Queue("dq5", true, &testStore)); // durable no limit + dq5->configure(args0); + mbdFanout3.bind(dq5, "", 0); + + intrusive_ptr<Message> msg11 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content + DeliverableMessage dmsg11(msg11); + mbdFanout3.route(dmsg11, "", 0); // Brings queues 3 and 4 to capacity limit + msg11->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg11->isContentReleased(), false); + BOOST_CHECK_EQUAL(1u, dq3->getMessageCount()); + BOOST_CHECK_EQUAL(1u, dq4->getMessageCount()); + BOOST_CHECK_EQUAL(1u, dq5->getMessageCount()); + + intrusive_ptr<Message> msg12 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content + DeliverableMessage dmsg12(msg12); + mbdFanout3.route(dmsg12, "", 0); + msg12->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg12->isContentReleased(), false); // XXXX - consequence of transient msg multi-queue ftd policy-handling limitations, fix in broker at some point! + BOOST_CHECK_EQUAL(2u, dq3->getMessageCount()); + BOOST_CHECK_EQUAL(2u, dq4->getMessageCount()); + BOOST_CHECK_EQUAL(2u, dq5->getMessageCount()); + + intrusive_ptr<Message> msg13 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content + DeliverableMessage dmsg13(msg13); + mbdFanout3.route(dmsg13, "", 0); + msg13->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg13->isContentReleased(), true); + BOOST_CHECK_EQUAL(3u, dq3->getMessageCount()); + BOOST_CHECK_EQUAL(3u, dq4->getMessageCount()); + BOOST_CHECK_EQUAL(3u, dq5->getMessageCount()); + + intrusive_ptr<Message> msg14 = mkMsg(testStore); // transient no content + DeliverableMessage dmsg14(msg14); + mbdFanout3.route(dmsg14, "", 0); + msg14->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg14->isContentReleased(), false); // XXXX - consequence of transient msg multi-queue ftd policy-handling limitations, fix in broker at some point! + BOOST_CHECK_EQUAL(4u, dq3->getMessageCount()); + BOOST_CHECK_EQUAL(4u, dq4->getMessageCount()); + BOOST_CHECK_EQUAL(4u, dq5->getMessageCount()); + + intrusive_ptr<Message> msg15 = mkMsg(testStore, "", true); // durable no content + DeliverableMessage dmsg15(msg15); + mbdFanout3.route(dmsg15, "", 0); + msg15->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg15->isContentReleased(), true); + BOOST_CHECK_EQUAL(5u, dq3->getMessageCount()); + BOOST_CHECK_EQUAL(5u, dq4->getMessageCount()); + BOOST_CHECK_EQUAL(5u, dq5->getMessageCount()); + + // Bind a transient queue, this should block the release of any further messages. + // Note: this will result in a violation of the count policy of dq3 and dq4 - but this + // is expected until a better overall multi-queue design is implemented. Similarly + // for the other tests in this section. + + Queue::shared_ptr tq6(new Queue("tq6", true)); // transient no limit + tq6->configure(args0); + mbdFanout3.bind(tq6, "", 0); + + intrusive_ptr<Message> msg16 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content + DeliverableMessage dmsg16(msg16); + mbdFanout3.route(dmsg16, "", 0); + msg16->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg16->isContentReleased(), false); + BOOST_CHECK_EQUAL(6u, dq3->getMessageCount()); + BOOST_CHECK_EQUAL(6u, dq4->getMessageCount()); + BOOST_CHECK_EQUAL(6u, dq5->getMessageCount()); + + intrusive_ptr<Message> msg17 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content + DeliverableMessage dmsg17(msg17); + mbdFanout3.route(dmsg17, "", 0); + msg17->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg17->isContentReleased(), false); + BOOST_CHECK_EQUAL(7u, dq3->getMessageCount()); + BOOST_CHECK_EQUAL(7u, dq4->getMessageCount()); + BOOST_CHECK_EQUAL(7u, dq5->getMessageCount()); + + intrusive_ptr<Message> msg18 = mkMsg(testStore); // transient no content + DeliverableMessage dmsg18(msg18); + mbdFanout3.route(dmsg18, "", 0); + msg18->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg18->isContentReleased(), false); + BOOST_CHECK_EQUAL(8u, dq3->getMessageCount()); + BOOST_CHECK_EQUAL(8u, dq4->getMessageCount()); + BOOST_CHECK_EQUAL(8u, dq5->getMessageCount()); + + intrusive_ptr<Message> msg19 = mkMsg(testStore, "", true); // durable no content + DeliverableMessage dmsg19(msg19); + mbdFanout3.route(dmsg19, "", 0); + msg19->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg19->isContentReleased(), false); + BOOST_CHECK_EQUAL(9u, dq3->getMessageCount()); + BOOST_CHECK_EQUAL(9u, dq4->getMessageCount()); + BOOST_CHECK_EQUAL(9u, dq5->getMessageCount()); + + + // --- Fanout exchange bound to multiple durable and transient queues ---------------------------------------------- + + FanOutExchange mbmFanout4("mbmFanout4", false, args0); // multiple bindings to durable/transient queues + Queue::shared_ptr dq7(new Queue("dq7", true, &testStore)); // durable no limit + dq7->configure(args0); + mbmFanout4.bind(dq7, "", 0); + Queue::shared_ptr dq8(new Queue("dq8", true, &testStore)); // durable w/ limit + dq8->configure(args1); + mbmFanout4.bind(dq8, "", 0); + Queue::shared_ptr tq9(new Queue("tq9", true)); // transient no limit + tq9->configure(args0); + mbmFanout4.bind(tq9, "", 0); + + intrusive_ptr<Message> msg20 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content + DeliverableMessage dmsg20(msg20); + mbmFanout4.route(dmsg20, "", 0); // Brings queue 7 to capacity limit + msg20->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg20->isContentReleased(), false); + BOOST_CHECK_EQUAL(1u, dq7->getMessageCount()); + BOOST_CHECK_EQUAL(1u, dq8->getMessageCount()); + BOOST_CHECK_EQUAL(1u, tq9->getMessageCount()); + + intrusive_ptr<Message> msg21 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content + DeliverableMessage dmsg21(msg21); + mbmFanout4.route(dmsg21, "", 0); + msg21->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg21->isContentReleased(), false); + BOOST_CHECK_EQUAL(2u, dq7->getMessageCount()); // over limit + BOOST_CHECK_EQUAL(2u, dq8->getMessageCount()); + BOOST_CHECK_EQUAL(2u, tq9->getMessageCount()); + + intrusive_ptr<Message> msg22 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content + DeliverableMessage dmsg22(msg22); + mbmFanout4.route(dmsg22, "", 0); + msg22->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg22->isContentReleased(), false); + BOOST_CHECK_EQUAL(3u, dq7->getMessageCount()); // over limit + BOOST_CHECK_EQUAL(3u, dq8->getMessageCount()); // over limit + BOOST_CHECK_EQUAL(3u, tq9->getMessageCount()); + + intrusive_ptr<Message> msg23 = mkMsg(testStore); // transient no content + DeliverableMessage dmsg23(msg23); + mbmFanout4.route(dmsg23, "", 0); + msg23->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg23->isContentReleased(), false); + BOOST_CHECK_EQUAL(4u, dq7->getMessageCount()); // over limit + BOOST_CHECK_EQUAL(4u, dq8->getMessageCount()); // over limit + BOOST_CHECK_EQUAL(4u, tq9->getMessageCount()); + + intrusive_ptr<Message> msg24 = mkMsg(testStore, "", true); // durable no content + DeliverableMessage dmsg24(msg24); + mbmFanout4.route(dmsg24, "", 0); + msg24->tryReleaseContent(); + BOOST_CHECK_EQUAL(msg24->isContentReleased(), false); + BOOST_CHECK_EQUAL(5u, dq7->getMessageCount()); // over limit + BOOST_CHECK_EQUAL(5u, dq8->getMessageCount()); // over limit + BOOST_CHECK_EQUAL(5u, tq9->getMessageCount()); +} + + QPID_AUTO_TEST_SUITE_END() }} // namespace qpid::tests diff --git a/qpid/cpp/src/tests/TxPublishTest.cpp b/qpid/cpp/src/tests/TxPublishTest.cpp index fabb01b864..6b44d95baa 100644 --- a/qpid/cpp/src/tests/TxPublishTest.cpp +++ b/qpid/cpp/src/tests/TxPublishTest.cpp @@ -50,7 +50,7 @@ struct TxPublishTest TxPublishTest() : queue1(new Queue("queue1", false, &store, 0)), queue2(new Queue("queue2", false, &store, 0)), - msg(MessageUtils::createMessage("exchange", "routing_key", "id")), + msg(MessageUtils::createMessage("exchange", "routing_key", false, "id")), op(msg) { msg->getProperties<DeliveryProperties>()->setDeliveryMode(PERSISTENT); diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py index fc53d2ce8b..2d776e9941 100755 --- a/qpid/cpp/src/tests/acl.py +++ b/qpid/cpp/src/tests/acl.py @@ -220,10 +220,11 @@ class ACLTests(TestBase010): """ aclf = ACLFile() aclf.write('acl deny bob@QPID create queue name=q1 durable=true passive=true\n') - aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true\n') + aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true policytype=ring\n') aclf.write('acl deny bob@QPID access queue name=q3\n') aclf.write('acl deny bob@QPID purge queue name=q3\n') - aclf.write('acl deny bob@QPID delete queue name=q4\n') + aclf.write('acl deny bob@QPID delete queue name=q4\n') + aclf.write('acl deny bob@QPID create queue name=q5 maxqueuesize=1000 maxqueuecount=100\n') aclf.write('acl allow all all') aclf.close() @@ -241,19 +242,41 @@ class ACLTests(TestBase010): session = self.get_session('bob','bob') try: - session.queue_declare(queue="q2", exclusive=True) - self.fail("ACL should deny queue create request with name=q2 exclusive=true"); + queue_options = {} + queue_options["qpid.policy_type"] = "ring" + session.queue_declare(queue="q2", exclusive=True, arguments=queue_options) + self.fail("ACL should deny queue create request with name=q2 exclusive=true qpid.policy_type=ring"); except qpid.session.SessionException, e: self.assertEqual(530,e.args[0].error_code) session = self.get_session('bob','bob') try: - session.queue_declare(queue="q2", durable=True) + queue_options = {} + queue_options["qpid.policy_type"] = "ring_strict" + session.queue_declare(queue="q2", exclusive=True, arguments=queue_options) except qpid.session.SessionException, e: if (530 == e.args[0].error_code): - self.fail("ACL should allow queue create request for q2 with any parameter other than exclusive=true"); + self.fail("ACL should allow queue create request with name=q2 exclusive=true qpid.policy_type=ring_strict"); try: + queue_options = {} + queue_options["qpid.max_count"] = 200 + queue_options["qpid.max_size"] = 500 + session.queue_declare(queue="q5", exclusive=True, arguments=queue_options) + self.fail("ACL should deny queue create request with name=q2, qpid.max_size=500 and qpid.max_count=200"); + except qpid.session.SessionException, e: + self.assertEqual(530,e.args[0].error_code) + session = self.get_session('bob','bob') + + try: + queue_options = {} + queue_options["qpid.max_count"] = 200 + queue_options["qpid.max_size"] = 100 + session.queue_declare(queue="q2", exclusive=True, arguments=queue_options) + except qpid.session.SessionException, e: + if (530 == e.args[0].error_code): + self.fail("ACL should allow queue create request with name=q2, qpid.max_size=100 and qpid.max_count=200 "); + try: session.queue_declare(queue="q3", exclusive=True) session.queue_declare(queue="q4", durable=True) except qpid.session.SessionException, e: @@ -300,12 +323,13 @@ class ACLTests(TestBase010): """ aclf = ACLFile() aclf.write('acl allow bob@QPID create queue name=q1 durable=true passive=true\n') - aclf.write('acl allow bob@QPID create queue name=q2 exclusive=true\n') + aclf.write('acl allow bob@QPID create queue name=q2 exclusive=true policytype=ring\n') aclf.write('acl allow bob@QPID access queue name=q3\n') aclf.write('acl allow bob@QPID purge queue name=q3\n') aclf.write('acl allow bob@QPID create queue name=q3\n') aclf.write('acl allow bob@QPID create queue name=q4\n') - aclf.write('acl allow bob@QPID delete queue name=q4\n') + aclf.write('acl allow bob@QPID delete queue name=q4\n') + aclf.write('acl allow bob@QPID create queue name=q5 maxqueuesize=1000 maxqueuecount=100\n') aclf.write('acl allow guest@QPID all all\n') aclf.write('acl deny all all') aclf.close() @@ -337,10 +361,31 @@ class ACLTests(TestBase010): session = self.get_session('bob','bob') try: - session.queue_declare(queue="q2", exclusive=True) + queue_options = {} + queue_options["qpid.max_count"] = 200 + queue_options["qpid.max_size"] = 500 + session.queue_declare(queue="q5", arguments=queue_options) + self.fail("ACL should deny queue create request with name=q2 maxqueuesize=500 maxqueuecount=200"); + except qpid.session.SessionException, e: + self.assertEqual(530,e.args[0].error_code) + session = self.get_session('bob','bob') + + try: + queue_options = {} + queue_options["qpid.max_count"] = 100 + queue_options["qpid.max_size"] = 500 + session.queue_declare(queue="q5", arguments=queue_options) except qpid.session.SessionException, e: if (530 == e.args[0].error_code): - self.fail("ACL should allow queue create request for q2 with exclusive=true"); + self.fail("ACL should allow queue create request with name=q2 maxqueuesize=500 maxqueuecount=200"); + + try: + queue_options = {} + queue_options["qpid.policy_type"] = "ring" + session.queue_declare(queue="q2", exclusive=True, arguments=queue_options) + except qpid.session.SessionException, e: + if (530 == e.args[0].error_code): + self.fail("ACL should allow queue create request for q2 with exclusive=true policytype=ring"); try: session.queue_declare(queue="q3") @@ -733,7 +778,7 @@ class ACLTests(TestBase010): # ACL publish tests #===================================== - def test_publish_acl(self): + def test_publish_acl_allow_mode(self): """ Test various publish acl """ @@ -779,4 +824,61 @@ class ACLTests(TestBase010): session.message_transfer(destination="amq.direct", message=Message(props,"Test")) except qpid.session.SessionException, e: if (530 == e.args[0].error_code): - self.fail("ACL should allow message transfer to exchange amq.direct"); + self.fail("ACL should allow message transfer to exchange amq.direct with routing key rk2"); + + + def test_publish_acl_deny_mode(self): + """ + Test various publish acl + """ + aclf = ACLFile() + aclf.write('acl allow bob@QPID publish exchange name=amq.direct routingkey=rk1\n') + aclf.write('acl allow bob@QPID publish exchange name=amq.topic\n') + aclf.write('acl allow bob@QPID publish exchange name=myEx routingkey=rk2\n') + aclf.write('acl allow bob@QPID create exchange\n') + aclf.write('acl allow guest@QPID all all \n') + aclf.write('acl deny all all') + aclf.close() + + result = self.reload_acl() + if (result.text.find("format error",0,len(result.text)) != -1): + self.fail(result) + + session = self.get_session('bob','bob') + + props = session.delivery_properties(routing_key="rk2") + + try: + session.message_transfer(destination="amq.direct", message=Message(props,"Test")) + self.fail("ACL should deny message transfer to name=amq.direct routingkey=rk2"); + except qpid.session.SessionException, e: + self.assertEqual(530,e.args[0].error_code) + session = self.get_session('bob','bob') + + try: + session.message_transfer(destination="amq.topic", message=Message(props,"Test")) + except qpid.session.SessionException, e: + if (530 == e.args[0].error_code): + self.fail("ACL should allow message transfer to exchange amq.topic with any routing key"); + + try: + session.exchange_declare(exchange='myEx', type='direct', durable=False) + session.message_transfer(destination="myEx", message=Message(props,"Test")) + except qpid.session.SessionException, e: + if (530 == e.args[0].error_code): + self.fail("ACL should allow message transfer to exchange myEx with routing key=rk2"); + + props = session.delivery_properties(routing_key="rk1") + + try: + session.message_transfer(destination="myEx", message=Message(props,"Test")) + self.fail("ACL should deny message transfer to name=myEx routingkey=rk1"); + except qpid.session.SessionException, e: + self.assertEqual(530,e.args[0].error_code) + session = self.get_session('bob','bob') + + try: + session.message_transfer(destination="amq.direct", message=Message(props,"Test")) + except qpid.session.SessionException, e: + if (530 == e.args[0].error_code): + self.fail("ACL should allow message transfer to exchange amq.direct with routing key rk1"); diff --git a/qpid/cpp/src/tests/ais_check b/qpid/cpp/src/tests/ais_check index 79862d7439..92eaa9dd39 100755 --- a/qpid/cpp/src/tests/ais_check +++ b/qpid/cpp/src/tests/ais_check @@ -21,35 +21,14 @@ srcdir=`dirname $0` # Check AIS requirements and run tests if found. -id -nG | grep '\<ais\>' >/dev/null || \ - NOGROUP="You are not a member of the ais group." -ps -u root | grep 'aisexec\|corosync' >/dev/null || \ - NOAISEXEC="The aisexec or corosync daemon is not running as root" - -if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then - cat <<EOF - - =========== WARNING: NOT RUNNING AIS TESTS ============== - - Tests that depend on the openais library (used for clustering) - will not be run because: - $NOGROUP - $NOAISEXEC - - ========================================================== - -EOF +ps -u root | grep 'aisexec\|corosync' >/dev/null || { + echo WARNING: Skipping cluster tests, the aisexec or corosync daemon is not running. exit 0; # A warning, not a failure. -fi +} -# Execute command with the ais group set. +# Execute command with the ais group set if user is a member. with_ais_group() { - id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group."; exit 1; } - echo $* | newgrp ais + if id -nG | grep '\<ais\>' >/dev/null; then sg ais -c "$*" + else "$@" + fi } - -# Run the tests -srcdir=`dirname $0` -with_ais_group $srcdir/run_test ./cluster_test || ERROR=1 -exit $ERROR - diff --git a/qpid/cpp/src/tests/background.ps1 b/qpid/cpp/src/tests/background.ps1 index 934078602b..36e9e4e6e9 100644 --- a/qpid/cpp/src/tests/background.ps1 +++ b/qpid/cpp/src/tests/background.ps1 @@ -30,11 +30,26 @@ trap { break } $encodedScript = [convert]::ToBase64String(
[Text.Encoding]::Unicode.GetBytes([string] $script))
-$p = new-object System.Diagnostics.Process
+#$p = new-object System.Diagnostics.Process
$si = new-object System.Diagnostics.ProcessStartInfo
$si.WorkingDirectory = $pwd
-$si.UseShellExecute = $true
$si.FileName = (get-command powershell.exe).Definition
$si.Arguments = "-encodedCommand $encodedScript"
-[diagnostics.process]::Start($si)
+###### debugging setup
+#$si.CreateNoWindow = $true
+# UseShellExecute false required for RedirectStandard(Error, Output)
+#$si.UseShellExecute = $false
+#$si.RedirectStandardError = $true
+#$si.RedirectStandardOutput = $true
+######
+$si.UseShellExecute = $true
+
+##### Debugging, instead of the plain Start() above.
+#$output = [io.File]::AppendText("start.out")
+#$error = [io.File]::AppendText("start.err")
+$p = [System.Diagnostics.Process]::Start($si)
+#$output.WriteLine($p.StandardOutput.ReadToEnd())
+#$error.WriteLine($p.StandardError.ReadToEnd())
+#$p.WaitForExit()
+#$output.Close()
diff --git a/qpid/cpp/src/tests/cluster.mk b/qpid/cpp/src/tests/cluster.mk index 05e18ab9eb..bdec10ebb0 100644 --- a/qpid/cpp/src/tests/cluster.mk +++ b/qpid/cpp/src/tests/cluster.mk @@ -30,7 +30,8 @@ if HAVE_LIBCPG # ais_check checks pre-requisites for cluster tests and runs them if ok. TESTS += \ - ais_check \ + run_cluster_test \ + cluster_read_credit \ test_watchdog \ run_cluster_tests \ federated_cluster_test \ @@ -38,6 +39,8 @@ TESTS += \ EXTRA_DIST += \ ais_check \ + run_cluster_test \ + cluster_read_credit \ test_watchdog \ start_cluster \ stop_cluster \ diff --git a/qpid/cpp/src/tests/cluster_read_credit b/qpid/cpp/src/tests/cluster_read_credit new file mode 100755 index 0000000000..370d4098c5 --- /dev/null +++ b/qpid/cpp/src/tests/cluster_read_credit @@ -0,0 +1,27 @@ +#!/bin/sh +# +# 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. +# + +# Regression test for http://issues.apache.org/jira/browse/QPID-2086 + +srcdir=`dirname $0` +. $srcdir/ais_check +$srcdir/start_cluster 1 --cluster-read-max=2 || exit 1 +trap $srcdir/stop_cluster EXIT +seq 1 10000 | ./sender --port `cat cluster.ports` --routing-key no-such-queue diff --git a/qpid/cpp/src/tests/cluster_test.cpp b/qpid/cpp/src/tests/cluster_test.cpp index 28fcdd13ad..247aef1b2a 100644 --- a/qpid/cpp/src/tests/cluster_test.cpp +++ b/qpid/cpp/src/tests/cluster_test.cpp @@ -85,6 +85,12 @@ void prepareArgs(ClusterFixture::Args& args, const bool durableFlag = false) { args += "--no-data-dir"; } +ClusterFixture::Args prepareArgs(const bool durableFlag = false) { + ClusterFixture::Args args; + prepareArgs(args, durableFlag); + return args; +} + // Timeout for tests that wait for messages const sys::Duration TIMEOUT=sys::TIME_SEC/4; @@ -596,16 +602,19 @@ QPID_AUTO_TEST_CASE(testUpdateConsumers) { } } -QPID_AUTO_TEST_CASE(testCatchupSharedState) { +// Test that message data and delivery properties are updated properly. +QPID_AUTO_TEST_CASE(testUpdateMessages) { ClusterFixture::Args args; prepareArgs(args, durableFlag); ClusterFixture cluster(1, args, -1); Client c0(cluster[0], "c0"); - // Create some shared state. + // Create messages with different delivery properties c0.session.queueDeclare("q", arg::durable=durableFlag); + c0.session.exchangeBind(arg::exchange="amq.fanout", arg::queue="q"); c0.session.messageTransfer(arg::content=makeMessage("foo","q", durableFlag)); - c0.session.messageTransfer(arg::content=makeMessage("bar","q", durableFlag)); + c0.session.messageTransfer(arg::content=makeMessage("bar","q", durableFlag), + arg::destination="amq.fanout"); while (c0.session.queueQuery("q").getMessageCount() != 2) sys::usleep(1000); // Wait for message to show up on broker 0. @@ -628,9 +637,12 @@ QPID_AUTO_TEST_CASE(testCatchupSharedState) { BOOST_CHECK(c1.subs.get(m, "q", TIMEOUT)); BOOST_CHECK_EQUAL(m.getData(), "foo"); + BOOST_CHECK(m.getDeliveryProperties().hasExchange()); BOOST_CHECK_EQUAL(m.getDeliveryProperties().getExchange(), ""); BOOST_CHECK(c1.subs.get(m, "q", TIMEOUT)); BOOST_CHECK_EQUAL(m.getData(), "bar"); + BOOST_CHECK(m.getDeliveryProperties().hasExchange()); + BOOST_CHECK_EQUAL(m.getDeliveryProperties().getExchange(), "amq.fanout"); BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u); // Add another broker, don't wait for join - should be stalled till ready. @@ -905,6 +917,7 @@ QPID_AUTO_TEST_CASE(testExclusiveQueueUpdate) { BOOST_CHECK(!result.getDurable()); BOOST_CHECK_EQUAL(result.getAlternateExchange(), std::string("amq.fanout")); BOOST_CHECK_THROW(c2.session.queueDeclare(arg::queue="q", arg::exclusive=true, arg::passive=true), framing::ResourceLockedException); + c1.session.close(); c1.connection.close(); c2.session = c2.connection.newSession(); BOOST_CHECK_THROW(c2.session.queueDeclare(arg::queue="q", arg::passive=true), framing::NotFoundException); @@ -1100,6 +1113,44 @@ QPID_AUTO_TEST_CASE(testRelease) { } } -QPID_AUTO_TEST_SUITE_END() +// Browse for 1 message with byte credit, return true if a message was +// received false if not. +bool browseByteCredit(Client& c, const string& q, int n, Message& m) { + SubscriptionSettings browseSettings( + FlowControl(1, n, false), // 1 message, n bytes credit, no window + ACCEPT_MODE_NONE, + ACQUIRE_MODE_NOT_ACQUIRED, + 0 // No auto-ack. + ); + LocalQueue lq; + Subscription s = c.subs.subscribe(lq, q, browseSettings); + c.session.messageFlush(arg::destination=q, arg::sync=true); + c.session.sync(); + c.subs.getSubscription(q).cancel(); + return lq.get(m, 0); // No timeout, flush should push message thru. +} + +// Ensure cluster update preserves exact message size, use byte credt as test. +QPID_AUTO_TEST_CASE(testExactByteCredit) { + ClusterFixture cluster(1, prepareArgs(), -1); + Client c0(cluster[0], "c0"); + c0.session.queueDeclare("q"); + c0.session.messageTransfer(arg::content=Message("MyMessage", "q")); + cluster.add(); + + int size=36; // Size of message on broker: headers+body + Client c1(cluster[1], "c1"); + Message m; + + // Ensure we get the message with exact credit. + BOOST_CHECK(browseByteCredit(c0, "q", size, m)); + BOOST_CHECK(browseByteCredit(c1, "q", size, m)); + // and not with one byte less. + BOOST_CHECK(!browseByteCredit(c0, "q", size-1, m)); + BOOST_CHECK(!browseByteCredit(c1, "q", size-1, m)); +} + + +QPID_AUTO_TEST_SUITE_END() }} // namespace qpid::tests diff --git a/qpid/cpp/src/tests/clustered_replication_test b/qpid/cpp/src/tests/clustered_replication_test index cc331957ad..4f13b4672c 100755 --- a/qpid/cpp/src/tests/clustered_replication_test +++ b/qpid/cpp/src/tests/clustered_replication_test @@ -22,8 +22,7 @@ # Test reliability of the replication feature in the face of link # failures: srcdir=`dirname $0` -PYTHON_DIR=$srcdir/../../../python -export PYTHONPATH=$PYTHON_DIR +. $srcdir/python_env.sh trap stop_brokers INT EXIT @@ -31,10 +30,6 @@ fail() { echo $1 exit 1 } -with_ais_group() { - id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group." 1>&2; exit 1; } - echo $* | newgrp ais -} stop_brokers() { if [[ $PRIMARY1 ]] ; then @@ -55,26 +50,8 @@ stop_brokers() { fi } -if test -d ${PYTHON_DIR}; then - id -nG | grep '\<ais\>' >/dev/null || \ - NOGROUP="You are not a member of the ais group." - ps -u root | grep 'aisexec\|corosync' >/dev/null || \ - NOAISEXEC="The aisexec or corosync daemon is not running as root" - - if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then - cat <<EOF - - =========== WARNING: NOT RUNNING AIS TESTS ============== - - Not running cluster replication test because: - $NOGROUP - $NOAISEXEC - - ========================================================== - -EOF - exit 0; - fi +if test -d $PYTHON_DIR; then + . $srcdir/ais_check #todo: these cluster names need to be unique to prevent clashes PRIMARY_CLUSTER=PRIMARY_$(hostname)_$(pwd) @@ -89,8 +66,8 @@ EOF #start first node of primary cluster and set up test queue echo Starting primary cluster PRIMARY1=$(with_ais_group ../qpidd $GENERAL_OPTS $PRIMARY_OPTS --log-to-file repl.primary.1.tmp) || fail "Could not start node" - $PYTHON_DIR/commands/qpid-config -a "localhost:$PRIMARY1" add queue test-queue --generate-queue-events 2 - $PYTHON_DIR/commands/qpid-config -a "localhost:$PRIMARY1" add queue control-queue --generate-queue-events 1 + $PYTHON_COMMANDS/qpid-config -a "localhost:$PRIMARY1" add queue test-queue --generate-queue-events 2 + $PYTHON_COMMANDS/qpid-config -a "localhost:$PRIMARY1" add queue control-queue --generate-queue-events 1 #send 10 messages, consume 5 of them for i in `seq 1 10`; do echo Message$i; done | ./sender --port $PRIMARY1 @@ -105,10 +82,10 @@ EOF DR1=$(with_ais_group ../qpidd $GENERAL_OPTS $DR_OPTS --log-to-file repl.dr.1.tmp) DR2=$(with_ais_group ../qpidd $GENERAL_OPTS $DR_OPTS --log-to-file repl.dr.2.tmp) - $PYTHON_DIR/commands/qpid-config -a "localhost:$DR1" add queue test-queue - $PYTHON_DIR/commands/qpid-config -a "localhost:$DR1" add queue control-queue - $PYTHON_DIR/commands/qpid-config -a "localhost:$DR1" add exchange replication REPLICATION_EXCHANGE - $PYTHON_DIR/commands/qpid-route queue add localhost:$DR2 localhost:$PRIMARY2 REPLICATION_EXCHANGE REPLICATION_QUEUE + $PYTHON_COMMANDS/qpid-config -a "localhost:$DR1" add queue test-queue + $PYTHON_COMMANDS/qpid-config -a "localhost:$DR1" add queue control-queue + $PYTHON_COMMANDS/qpid-config -a "localhost:$DR1" add exchange replication REPLICATION_EXCHANGE + $PYTHON_COMMANDS/qpid-route queue add localhost:$DR2 localhost:$PRIMARY2 REPLICATION_EXCHANGE REPLICATION_QUEUE #send more messages to primary for i in `seq 11 20`; do echo Message$i; done | ./sender --port $PRIMARY1 --send-eos 1 diff --git a/qpid/cpp/src/tests/federated_cluster_test b/qpid/cpp/src/tests/federated_cluster_test index a781e269d6..8b3ce3cb95 100755 --- a/qpid/cpp/src/tests/federated_cluster_test +++ b/qpid/cpp/src/tests/federated_cluster_test @@ -22,7 +22,7 @@ # Test reliability of the replication feature in the face of link # failures: srcdir=`dirname $0` -PYTHON_DIR=$srcdir/../../../python +. $srcdir/python_env.sh trap stop_brokers EXIT @@ -61,22 +61,21 @@ start_brokers() { } setup() { - export PYTHONPATH=$PYTHON_DIR #create exchange on both cluster and single broker - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add exchange direct test-exchange - $PYTHON_DIR/commands/qpid-config -a "localhost:$NODE_1" add exchange direct test-exchange + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add exchange direct test-exchange + $PYTHON_COMMANDS/qpid-config -a "localhost:$NODE_1" add exchange direct test-exchange #create dynamic routes for test exchange - $PYTHON_DIR/commands/qpid-route dynamic add "localhost:$NODE_2" "localhost:$BROKER_A" test-exchange - $PYTHON_DIR/commands/qpid-route dynamic add "localhost:$BROKER_A" "localhost:$NODE_2" test-exchange + $PYTHON_COMMANDS/qpid-route dynamic add "localhost:$NODE_2" "localhost:$BROKER_A" test-exchange + $PYTHON_COMMANDS/qpid-route dynamic add "localhost:$BROKER_A" "localhost:$NODE_2" test-exchange #create test queue on cluster and bind it to the test exchange - $PYTHON_DIR/commands/qpid-config -a "localhost:$NODE_1" add queue test-queue - $PYTHON_DIR/commands/qpid-config -a "localhost:$NODE_1" bind test-exchange test-queue to-cluster + $PYTHON_COMMANDS/qpid-config -a "localhost:$NODE_1" add queue test-queue + $PYTHON_COMMANDS/qpid-config -a "localhost:$NODE_1" bind test-exchange test-queue to-cluster #create test queue on single broker and bind it to the test exchange - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue test-queue - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" bind test-exchange test-queue from-cluster + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue test-queue + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" bind test-exchange test-queue from-cluster } run_test_pull_to_cluster_two_consumers() { @@ -127,25 +126,7 @@ run_test_pull_from_cluster() { if test -d ${PYTHON_DIR}; then - id -nG | grep '\<ais\>' >/dev/null || \ - NOGROUP="You are not a member of the ais group." - ps -u root | grep 'aisexec\|corosync' >/dev/null || \ - NOAISEXEC="The aisexec or corosync daemon is not running as root" - - if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then - cat <<EOF - - =========== WARNING: NOT RUNNING AIS TESTS ============== - - Not running federation to cluster test because: - $NOGROUP - $NOAISEXEC - - ========================================================== - -EOF - exit 0; - fi + . $srcdir/ais_check rm -f fed*.tmp #cleanup any files left from previous run start_brokers diff --git a/qpid/cpp/src/tests/federated_topic_test b/qpid/cpp/src/tests/federated_topic_test index 21d8411eaf..dbe9a85e95 100755 --- a/qpid/cpp/src/tests/federated_topic_test +++ b/qpid/cpp/src/tests/federated_topic_test @@ -43,7 +43,7 @@ while getopts "s:m:b:" opt ; do done MY_DIR=$(dirname $(which $0)) -PYTHON_DIR=${MY_DIR}/../../../python +. $MY_DIR/python_env.sh trap stop_brokers EXIT @@ -87,29 +87,28 @@ setup_routes() { BROKER_A="localhost:$PORT_A" BROKER_B="localhost:$PORT_B" BROKER_C="localhost:$PORT_C" - export PYTHONPATH=$PYTHON_DIR if (($VERBOSE)); then echo "Establishing routes for topic..." fi - $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_A amq.topic topic_control B B - $PYTHON_DIR/commands/qpid-route route add $BROKER_C $BROKER_B amq.topic topic_control C C + $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_A amq.topic topic_control B B + $PYTHON_COMMANDS/qpid-route route add $BROKER_C $BROKER_B amq.topic topic_control C C if (($VERBOSE)); then echo "linked A->B->C" fi - $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_C amq.topic topic_control B B - $PYTHON_DIR/commands/qpid-route route add $BROKER_A $BROKER_B amq.topic topic_control A A + $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_C amq.topic topic_control B B + $PYTHON_COMMANDS/qpid-route route add $BROKER_A $BROKER_B amq.topic topic_control A A if (($VERBOSE)); then echo "linked C->B->A" echo "Establishing routes for response queue..." fi - $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_C amq.direct response B B - $PYTHON_DIR/commands/qpid-route route add $BROKER_A $BROKER_B amq.direct response A A + $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_C amq.direct response B B + $PYTHON_COMMANDS/qpid-route route add $BROKER_A $BROKER_B amq.direct response A A if (($VERBOSE)); then echo "linked C->B->A" for b in $BROKER_A $BROKER_B $BROKER_C; do echo "Routes for $b" - $PYTHON_DIR/commands/qpid-route route list $b + $PYTHON_COMMANDS/qpid-route route list $b done fi } diff --git a/qpid/cpp/src/tests/python_env.sh b/qpid/cpp/src/tests/python_env.sh new file mode 100644 index 0000000000..f5dca97a56 --- /dev/null +++ b/qpid/cpp/src/tests/python_env.sh @@ -0,0 +1,26 @@ +# +# 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. +# + +# Environment for python tests +test -d python || { echo "WARNING: skipping `basename $0`, no python directory."; exit 0; } +PYTHON_DIR=$PWD/python +PYTHON_COMMANDS=$PYTHON_DIR/commands +PYTHONPATH=$PYTHON_DIR +export PYTHONPATH PYTHON_DIR + diff --git a/qpid/cpp/src/tests/python_tests b/qpid/cpp/src/tests/python_tests index e3906c1685..e2077ef7dc 100755 --- a/qpid/cpp/src/tests/python_tests +++ b/qpid/cpp/src/tests/python_tests @@ -20,14 +20,10 @@ # # Run the python tests. +. `dirname $0`/python_env.sh QPID_PORT=${QPID_PORT:-5672} PYTHON_TESTS=${PYTHON_TESTS:-$*} -QPID_PYTHON_DIR=${QPID_PYTHON_DIR:-`dirname $0`/../../../python} FAILING=${FAILING:-/dev/null} -if test -d $QPID_PYTHON_DIR; then - cd $QPID_PYTHON_DIR - ./qpid-python-test -b localhost:$QPID_PORT -I $FAILING $PYTHON_TESTS || { echo "FAIL python tests"; exit 1; } -else - echo "WARNING: No python tests. $QPID_PYTHON_DIR not found." -fi +cd $PYTHON_DIR +python commands/qpid-python-test -b localhost:$QPID_PORT -I $FAILING $PYTHON_TESTS || exit 1 diff --git a/qpid/cpp/src/tests/python_tests.ps1 b/qpid/cpp/src/tests/python_tests.ps1 new file mode 100644 index 0000000000..a7f6920783 --- /dev/null +++ b/qpid/cpp/src/tests/python_tests.ps1 @@ -0,0 +1,42 @@ +# +# 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. +# + +# Run the python tests; intended to be run by run_test.ps1 which sets up +# QPID_PORT +$srcdir = Split-Path $myInvocation.InvocationName +$PYTHON_DIR = "$srcdir\..\..\..\python" +if (!(Test-Path $PYTHON_DIR -pathType Container)) { + "Skipping header test as python libs not found" + exit 1 +} + +if (Test-Path env:FAILING) { + $fails = "-I $env:FAILING" +} +if (Test-Path env:PYTHON_TESTS) { + $tests = "$env:PYTHON_TESTS" +} +else { + $tests = "*" +} + +#cd $PYTHON_DIR +$env:PYTHONPATH="$PYTHON_DIR;$env:PYTHONPATH" +python $PYTHON_DIR/qpid-python-test -b localhost:$env:QPID_PORT $fails $tests +exit $LASTEXITCODE diff --git a/qpid/cpp/src/tests/qpid_stream.cpp b/qpid/cpp/src/tests/qpid_stream.cpp index 8e02baa8a0..8195bf390e 100644 --- a/qpid/cpp/src/tests/qpid_stream.cpp +++ b/qpid/cpp/src/tests/qpid_stream.cpp @@ -34,6 +34,9 @@ using namespace qpid::messaging; using namespace qpid::sys; +namespace qpid { +namespace tests { + struct Args : public qpid::Options { std::string url; @@ -139,10 +142,14 @@ struct Consume : Client << ", min=" << minLatency << ", max=" << maxLatency << std::endl; } - } + } } }; +}} // namespace qpid::tests + +using namespace qpid::tests; + int main(int argc, char** argv) { try { diff --git a/qpid/cpp/src/tests/quick_topictest.ps1 b/qpid/cpp/src/tests/quick_topictest.ps1 index 2b857edfff..b1e0ed1f7d 100644 --- a/qpid/cpp/src/tests/quick_topictest.ps1 +++ b/qpid/cpp/src/tests/quick_topictest.ps1 @@ -18,12 +18,13 @@ # # Quick and quiet topic test for make check. -$srcdir = Split-Path $myInvocation.ScriptName -$PsHome\powershell $srcdir\topictest.ps1 -subscribers 2 -messages 2 -batches 1 > topictest.log 2>&1 -if ($LastExitCode != 0) { - echo $0 FAILED: +[string]$me = $myInvocation.InvocationName +$srcdir = Split-Path $me +powershell "$srcdir\topictest.ps1" -subscribers 2 -messages 2 -batches 1 > topictest.log 2>&1 +if (!$?) { + "$me FAILED:" cat topictest.log exit $LastExitCode } -rm topictest.log +Remove-Item topictest.log exit 0 diff --git a/qpid/cpp/src/tests/reliable_replication_test b/qpid/cpp/src/tests/reliable_replication_test index a788d5a76b..db06259f0c 100755 --- a/qpid/cpp/src/tests/reliable_replication_test +++ b/qpid/cpp/src/tests/reliable_replication_test @@ -22,7 +22,7 @@ # Test reliability of the replication feature in the face of link # failures: MY_DIR=`dirname \`which $0\`` -PYTHON_DIR=${MY_DIR}/../../../python +. ${MY_DIR}/python_env.sh trap stop_brokers EXIT @@ -53,12 +53,12 @@ setup() { echo "Testing replication from port $BROKER_A to port $BROKER_B" export PYTHONPATH=$PYTHON_DIR - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add exchange replication replication - $PYTHON_DIR/commands/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication + $PYTHON_COMMANDS/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication #create test queue (only replicate enqueues for this test): - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 1 - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-a + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 1 + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-a } send() { @@ -72,10 +72,10 @@ receive() { bounce_link() { echo "Destroying link..." - $PYTHON_DIR/commands/qpid-route link del "localhost:$BROKER_B" "localhost:$BROKER_A" + $PYTHON_COMMANDS/qpid-route link del "localhost:$BROKER_B" "localhost:$BROKER_A" echo "Link destroyed; recreating route..." sleep 2 - $PYTHON_DIR/commands/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication + $PYTHON_COMMANDS/qpid-route --ack 500 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication echo "Route re-established" } diff --git a/qpid/cpp/src/tests/replication_test b/qpid/cpp/src/tests/replication_test index 8b3022b260..000b4591da 100755 --- a/qpid/cpp/src/tests/replication_test +++ b/qpid/cpp/src/tests/replication_test @@ -21,7 +21,8 @@ # Run a test of the replication feature MY_DIR=`dirname \`which $0\`` -PYTHON_DIR=${MY_DIR}/../../../python +. `dirname $0`/python_env.sh + trap stop_brokers INT TERM QUIT stop_brokers() { @@ -47,21 +48,21 @@ if test -d ${PYTHON_DIR} && test -f ../.libs/replicating_listener.so && test -f export PYTHONPATH echo "Running replication test between localhost:$BROKER_A and localhost:$BROKER_B" - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add exchange replication replication - $PYTHON_DIR/commands/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication + $PYTHON_COMMANDS/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication #create test queues - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 2 - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-b --generate-queue-events 2 - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-c --generate-queue-events 1 - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 2 - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 1 + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-a --generate-queue-events 2 + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-b --generate-queue-events 2 + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-c --generate-queue-events 1 + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 2 + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 1 - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-a - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-b - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-c - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-e + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-a + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-b + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-c + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-e #queue-d deliberately not declared on DR; this error case should be handled #publish and consume from test queues on broker A: @@ -125,13 +126,13 @@ if test -d ${PYTHON_DIR} && test -f ../.libs/replicating_listener.so && test -f ../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module ../.libs/replication_exchange.so --log-enable info+ --log-to-file replication-dest.log --log-to-stderr 0 > qpidd.port BROKER_B=`cat qpidd.port` - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add exchange replication replication - $PYTHON_DIR/commands/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication + $PYTHON_COMMANDS/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 2 - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-e - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 1 - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-d + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-e --generate-queue-events 2 + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-e + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_A" add queue queue-d --generate-queue-events 1 + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-d i=1 while [ $i -le 10 ]; do @@ -153,9 +154,9 @@ if test -d ${PYTHON_DIR} && test -f ../.libs/replicating_listener.so && test -f ../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no --load-module ../.libs/replication_exchange.so --log-enable info+ --log-to-file replication-dest.log --log-to-stderr 0 > qpidd.port BROKER_B=`cat qpidd.port` - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add queue queue-e - $PYTHON_DIR/commands/qpid-config -a "localhost:$BROKER_B" add exchange replication replication - $PYTHON_DIR/commands/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add queue queue-e + $PYTHON_COMMANDS/qpid-config -a "localhost:$BROKER_B" add exchange replication replication + $PYTHON_COMMANDS/qpid-route --ack 5 queue add "localhost:$BROKER_B" "localhost:$BROKER_A" replication replication # now send another 15 i=11 while [ $i -le 15 ]; do diff --git a/qpid/cpp/src/tests/ring_queue_test b/qpid/cpp/src/tests/ring_queue_test index 5805989d7e..553746eb49 100755 --- a/qpid/cpp/src/tests/ring_queue_test +++ b/qpid/cpp/src/tests/ring_queue_test @@ -48,7 +48,7 @@ receive() { cleanup() { rm -f sender_${QUEUE_NAME}_* receiver_${QUEUE_NAME}_* - qpid-config $BROKER_URL add queue $QUEUE_NAME + qpid-config $BROKER_URL del queue $QUEUE_NAME --force } log() { @@ -64,10 +64,11 @@ validate() { if [[ $RECEIVERS -eq 0 ]]; then #queue should have $LIMIT messages on it, but need to send an eos also sender --routing-key $QUEUE_NAME --send-eos 1 < /dev/null - if [[ $(receiver --queue $QUEUE_NAME --browse | wc -l) -eq $(( $LIMIT - 1)) ]]; then + received=$(receiver --queue $QUEUE_NAME --browse | wc -l) + if [[ received -eq $(( $LIMIT - 1)) ]]; then log "queue contains $LIMIT messages as expected" else - fail "queue does not contain the expected $LIMIT messages" + fail "queue does not contain the expected $LIMIT messages (received $received)" fi elif [[ $CONCURRENT -eq 0 ]]; then #sum of length of all output files should be equal to $LIMIT - $RECEIVERS (1 eos message each) diff --git a/qpid/cpp/src/tests/run_acl_tests b/qpid/cpp/src/tests/run_acl_tests index d9b654c7cd..c67e2d421d 100755 --- a/qpid/cpp/src/tests/run_acl_tests +++ b/qpid/cpp/src/tests/run_acl_tests @@ -20,7 +20,7 @@ # # Run the acl tests. $srcdir is set by the Makefile. -PYTHON_DIR=$srcdir/../../../python +. `dirname $0`/python_env.sh DATA_DIR=`pwd`/data_dir trap stop_brokers INT TERM QUIT @@ -55,7 +55,7 @@ if test -d ${PYTHON_DIR} ; then echo "Running acl tests using brokers on ports $LOCAL_PORT" PYTHONPATH=$PYTHON_DIR:$srcdir export PYTHONPATH - $PYTHON_DIR/qpid-python-test -b localhost:$LOCAL_PORT -m acl || EXITCODE=1 + $PYTHON_COMMANDS/qpid-python-test -b localhost:$LOCAL_PORT -m acl || EXITCODE=1 stop_brokers || EXITCODE=1 test_loading_acl_from_absolute_path || EXITCODE=1 rm -rf $DATA_DIR diff --git a/qpid/cpp/src/tests/run_cli_tests b/qpid/cpp/src/tests/run_cli_tests index ea0d591176..bb9605410c 100755 --- a/qpid/cpp/src/tests/run_cli_tests +++ b/qpid/cpp/src/tests/run_cli_tests @@ -21,8 +21,8 @@ # Run the cli-utility tests. MY_DIR=`dirname \`which $0\`` -PYTHON_DIR=${MY_DIR}/../../../python -CLI_DIR=${PYTHON_DIR}/commands +. `dirname $0`/python_env.sh +CLI_DIR=$PYTHON_COMMANDS trap stop_brokers INT TERM QUIT @@ -43,7 +43,7 @@ if test -d ${PYTHON_DIR} ; then echo "Running CLI tests using brokers on ports $LOCAL_PORT $REMOTE_PORT" PYTHONPATH=${PYTHON_DIR}:${MY_DIR} export PYTHONPATH - ${PYTHON_DIR}/qpid-python-test -m cli_tests -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dcli-dir=$CLI_DIR $@ + $PYTHON_COMMANDS/qpid-python-test -m cli_tests -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dcli-dir=$CLI_DIR $@ RETCODE=$? stop_brokers if test x$RETCODE != x0; then diff --git a/qpid/cpp/src/tests/run_cluster_test b/qpid/cpp/src/tests/run_cluster_test new file mode 100755 index 0000000000..c022eea1fe --- /dev/null +++ b/qpid/cpp/src/tests/run_cluster_test @@ -0,0 +1,26 @@ +#!/bin/bash + +# +# 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. +# + + +# Run the tests +srcdir=`dirname $0` +. $srcdir/ais_check +with_ais_group $srcdir/run_test ./cluster_test diff --git a/qpid/cpp/src/tests/run_cluster_tests b/qpid/cpp/src/tests/run_cluster_tests index 8b039346db..d1a58f9f6a 100755 --- a/qpid/cpp/src/tests/run_cluster_tests +++ b/qpid/cpp/src/tests/run_cluster_tests @@ -22,45 +22,21 @@ # Check that top_builddir and srcdir are set # If not, assume local run from test dir if [ -z ${top_builddir} -o -z ${srcdir} ]; then - srcdir=`pwd` + srcdir=`dirname $0` top_builddir=${srcdir}/../../ fi TEST_DIR=${top_builddir}/src/tests -PYTHON_DIR=${srcdir}/../../../python +. $srcdir/python_env.sh if test -z $1; then - CLUSTER_TEST="${PYTHON_DIR}/qpid-python-test -m cluster_tests cluster_tests.ShortTests.\*" + CLUSTER_TEST="$PYTHON_COMMANDS/qpid-python-test -m cluster_tests cluster_tests.ShortTests.\*" else - CLUSTER_TEST="${PYTHON_DIR}/qpid-python-test -m cluster_tests cluster_tests.LongTests.\*" + CLUSTER_TEST="$PYTHON_COMMANDS/qpid-python-test -m cluster_tests cluster_tests.LongTests.\*" echo "Running $1..." fi - # Check AIS requirements -id -nG | grep '\<ais\>' > /dev/null || NOGROUP="You are not a member of the ais group." -ps -u root | grep 'aisexec\|corosync' > /dev/null || NOAISEXEC="The aisexec or corosync daemon is not running as root." -if ! test -d ${PYTHON_DIR}; then - NO_PYTHON_DIR="PYTHON_DIR=\"${PYTHON_DIR}\" not found or does not exist." -fi - -if test -n "${NOGROUP}" -o -n "${NOAISEXEC}" -o -n "${NO_PYTHON_DIR}"; then - cat <<EOF - - ======== WARNING: PYTHON CLUSTER TESTS DISABLED =========== - - Tests that depend on the openais library (used for clustering) - and python will not be run because: - - ${NOGROUP} - ${NOAISEXEC} - ${NO_PYTHON_DIR} - - =========================================================== - -EOF - exit 0 -fi - +. $srcdir/ais_check # Check XML exchange requirements XML_LIB=$srcdir/../.libs/xml.so @@ -103,7 +79,7 @@ export TMP_DATA_DIR # Run the test -sg ais -c "${CLUSTER_TEST}" +with_ais_group ${CLUSTER_TEST} RETCODE=$? if test x${RETCODE} != x0; then @@ -114,4 +90,4 @@ fi # Delete cluster store dir if test was successful. rm -rf ${TMP_DATA_DIR} -exit 0
\ No newline at end of file +exit 0 diff --git a/qpid/cpp/src/tests/run_failover_soak b/qpid/cpp/src/tests/run_failover_soak index 3c9a5589c4..8d5b37f008 100755 --- a/qpid/cpp/src/tests/run_failover_soak +++ b/qpid/cpp/src/tests/run_failover_soak @@ -19,29 +19,7 @@ # under the License. # -# Check AIS requirements and run tests if found. -id -ng | grep '\<ais\>' >/dev/null || \ - NOGROUP="The ais group is not your primary group." -ps -u root | grep 'aisexec\|corosync' >/dev/null || \ - NOAISEXEC="The aisexec/corosync daemon is not running as root" - -if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then - cat <<EOF - - =========== WARNING: NOT RUNNING AIS TESTS ============== - - Tests that depend on the openais library (used for clustering) - will not be run because: - - $NOGROUP - $NOAISEXEC - - ========================================================== - -EOF - exit 0; # A warning, not a failure. -fi - +. `dirname $0`/ais_check host=127.0.0.1 diff --git a/qpid/cpp/src/tests/run_federation_tests b/qpid/cpp/src/tests/run_federation_tests index 8640fb728f..3fe4bccb13 100755 --- a/qpid/cpp/src/tests/run_federation_tests +++ b/qpid/cpp/src/tests/run_federation_tests @@ -21,7 +21,7 @@ # Run the federation tests. MY_DIR=`dirname \`which $0\`` -PYTHON_DIR=${MY_DIR}/../../../python +. `dirname $0`/python_env.sh trap stop_brokers INT TERM QUIT @@ -42,7 +42,7 @@ if test -d ${PYTHON_DIR} ; then echo "Running federation tests using brokers on ports $LOCAL_PORT $REMOTE_PORT" PYTHONPATH=${PYTHON_DIR}:${MY_DIR} export PYTHONPATH - ${PYTHON_DIR}/qpid-python-test -m federation -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT $@ + $PYTHON_COMMANDS/qpid-python-test -m federation -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT $@ RETCODE=$? stop_brokers if test x$RETCODE != x0; then diff --git a/qpid/cpp/src/tests/run_federation_tests.ps1 b/qpid/cpp/src/tests/run_federation_tests.ps1 index db3dbf5a11..dd0ea2fe5b 100644 --- a/qpid/cpp/src/tests/run_federation_tests.ps1 +++ b/qpid/cpp/src/tests/run_federation_tests.ps1 @@ -18,42 +18,63 @@ # # Run the federation tests. -$srcdir = Split-Path $myInvocation.ScriptName -$PYTHON_DIR = $srcdir\..\..\..\python -trap stop_brokers INT TERM QUIT +$srcdir = Split-Path $myInvocation.InvocationName +$PYTHON_DIR = "$srcdir\..\..\..\python" +if (!(Test-Path $PYTHON_DIR -pathType Container)) { + "Skipping federation tests as python libs not found" + exit 1 +} -start_brokers() { +# Test runs from the tests directory but the broker executable is one level +# up, and most likely in a subdirectory from there based on what build type. +# Look around for it before trying to start it. +$subs = "Debug","Release","MinSizeRel","RelWithDebInfo" +foreach ($sub in $subs) { + $prog = "..\$sub\qpidd.exe" + if (Test-Path $prog) { + break + } +} +if (!(Test-Path $prog)) { + "Cannot locate qpidd.exe" + exit 1 +} +$cmdline = "$prog --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port `$_ }" +$cmdblock = $executioncontext.invokecommand.NewScriptBlock($cmdline) + +function start_brokers { # Start 2 brokers, saving the port numbers in LOCAL_PORT, REMOTE_PORT. - . $srcdir\background.ps1 { - ..\Debug\qpidd --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port $_ } } + . $srcdir\background.ps1 $cmdblock while (!(Test-Path qpidd.port)) { Start-Sleep 2 } set-item -path env:LOCAL_PORT -value (get-content -path qpidd.port -totalcount 1) Remove-Item qpidd.port - . $srcdir\background.ps1 { - ..\Debug\qpidd --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port $_ } } + . $srcdir\background.ps1 $cmdblock while (!(Test-Path qpidd.port)) { Start-Sleep 2 } set-item -path env:REMOTE_PORT -value (get-content -path qpidd.port -totalcount 1) } -stop_brokers() { - ..\Debug\qpidd -q --port $LOCAL_PORT | Out-Default - ..\Debug\qpidd -q --port $REMOTE_PORT | Out-Default +function stop_brokers { + Invoke-Expression "$prog -q --port $env:LOCAL_PORT" | Out-Default + Invoke-Expression "$prog -q --port $env:REMOTE_PORT" | Out-Default +} + +trap { + &stop_brokers + break } -if (Test-Path $PYTHON_DIR -pathType Container) { - start_brokers - "Running federation tests using brokers on ports $LOCAL_PORT $REMOTE_PORT" - $env:PYTHONPATH=$PYTHON_DIR - $srcdir/federation.py -v -s $srcdir\..\..\..\specs\amqp.0-10-qpid-errata.xml -b localhost:$LOCAL_PORT --remote-port $REMOTE_PORT $args - $RETCODE=$LASTEXITCODE - stop_brokers - if ($RETCODE != 0) { - "FAIL federation tests" - exit 1 - } +&start_brokers +"Running federation tests using brokers on ports $env:LOCAL_PORT $env:REMOTE_PORT" +$env:PYTHONPATH=$PYTHON_DIR +python $srcdir/federation.py -v -s $srcdir\..\..\..\specs\amqp.0-10-qpid-errata.xml -b localhost:$env:LOCAL_PORT --remote-port $env:REMOTE_PORT $args +$RETCODE=$LASTEXITCODE +&stop_brokers +if ($RETCODE -ne 0) { + "FAIL federation tests" + exit 1 } diff --git a/qpid/cpp/src/tests/run_header_test b/qpid/cpp/src/tests/run_header_test index 414fecd28f..1b5a3963db 100755 --- a/qpid/cpp/src/tests/run_header_test +++ b/qpid/cpp/src/tests/run_header_test @@ -24,7 +24,7 @@ # in both directions srcdir=`dirname $0` -PYTHON_DIR=$srcdir/../../../python +. `dirname $0`/python_env.sh test -f qpidd.port && QPID_PORT=`cat qpidd.port` if test -d ${PYTHON_DIR} ; then diff --git a/qpid/cpp/src/tests/run_header_test.ps1 b/qpid/cpp/src/tests/run_header_test.ps1 index add680f569..c7bc2d788e 100644 --- a/qpid/cpp/src/tests/run_header_test.ps1 +++ b/qpid/cpp/src/tests/run_header_test.ps1 @@ -21,20 +21,33 @@ # TODO: this should be expanded to cover a wider set of types and go # in both directions -$srcdir = Split-Path $myInvocation.ScriptName -$PYTHON_DIR = $srcdir\..\..\..\python +$srcdir = Split-Path $myInvocation.InvocationName +$PYTHON_DIR = "$srcdir\..\..\..\python" +if (!(Test-Path $PYTHON_DIR -pathType Container)) { + "Skipping header test as python libs not found" + exit 0 +} + if (Test-Path qpidd.port) { set-item -path env:QPID_PORT -value (get-content -path qpidd.port -totalcount 1) } -if (Test-Path $PYTHON_DIR -pathType Container) { - ./header_test -p $QPID_PORT - $env:PYTHONPATH="$PYTHON_DIR;$env:PYTHONPATH" - $srcdir/header_test.py "localhost" $QPID_PORT - exit $LASTEXITCODE +# Test runs from the tests directory but the test executables are in a +# subdirectory based on the build type. Look around for it before trying +# to start it. +$subs = "Debug","Release","MinSizeRel","RelWithDebInfo" +foreach ($sub in $subs) { + $prog = ".\$sub\header_test.exe" + if (Test-Path $prog) { + break + } } -else { - "Skipping header test as python libs not found" - exit 0 +if (!(Test-Path $prog)) { + "Cannot locate header_test.exe" + exit 1 } +Invoke-Expression "$prog -p $env:QPID_PORT" | Write-Output +$env:PYTHONPATH="$PYTHON_DIR;$env:PYTHONPATH" +Invoke-Expression "python $srcdir/header_test.py localhost $env:QPID_PORT" | Write-Output +exit $LASTEXITCODE diff --git a/qpid/cpp/src/tests/run_long_cluster_tests b/qpid/cpp/src/tests/run_long_cluster_tests index bc1ae8a0c1..cb9c6b219b 100755 --- a/qpid/cpp/src/tests/run_long_cluster_tests +++ b/qpid/cpp/src/tests/run_long_cluster_tests @@ -19,4 +19,5 @@ # under the License. # -./run_cluster_tests long_cluster_tests +srcdir=`dirname $0` +$srcdir/run_cluster_tests long_cluster_tests diff --git a/qpid/cpp/src/tests/run_ring_queue_test b/qpid/cpp/src/tests/run_ring_queue_test index fb90075458..9cd3775de1 100755 --- a/qpid/cpp/src/tests/run_ring_queue_test +++ b/qpid/cpp/src/tests/run_ring_queue_test @@ -22,9 +22,8 @@ #setup path to find qpid-config and sender/receiver test progs srcdir=`dirname $0` -PYTHON_DIR=$srcdir/../../../python -export PYTHONPATH=$PYTHON_DIR -export PATH=./:$PYTHON_DIR/commands:$PATH +. `dirname $0`/python_env.sh +export PATH=$PWD:$srcdir:$PYTHON_COMMANDS:$PATH #set port to connect to via env var test -s qpidd.port && QPID_PORT=`cat qpidd.port` diff --git a/qpid/cpp/src/tests/run_test.ps1 b/qpid/cpp/src/tests/run_test.ps1 index ebbef07f1d..551368bc9b 100644 --- a/qpid/cpp/src/tests/run_test.ps1 +++ b/qpid/cpp/src/tests/run_test.ps1 @@ -52,7 +52,6 @@ if (Test-Path qpidd.port) { set-item -path env:QPID_PORT -value (get-content -path qpidd.port -totalcount 1) } -#$p = new-object System.Diagnostics.Process $si = new-object System.Diagnostics.ProcessStartInfo $si.WorkingDirectory = $pwd $si.UseShellExecute = $true @@ -67,6 +66,6 @@ else { $si.Arguments = $args[1..$args.length-1] } } -$p = [diagnostics.process]::Start($si) +$p = [System.Diagnostics.Process]::Start($si) $p.WaitForExit() exit $? diff --git a/qpid/cpp/src/tests/start_broker.ps1 b/qpid/cpp/src/tests/start_broker.ps1 index f2aa20439a..9263262b9f 100644 --- a/qpid/cpp/src/tests/start_broker.ps1 +++ b/qpid/cpp/src/tests/start_broker.ps1 @@ -28,9 +28,26 @@ function Get-ScriptPath if (Test-Path qpidd.port) { Remove-Item qpidd.port } + +# Test runs from the tests directory but the broker executable is one level +# up, and most likely in a subdirectory from there based on what build type. +# Look around for it before trying to start it. +$subs = "Debug","Release","MinSizeRel","RelWithDebInfo" +foreach ($sub in $subs) { + $prog = "..\$sub\qpidd.exe" + if (Test-Path $prog) { + break + } +} +if (!(Test-Path $prog)) { + "Cannot locate qpidd.exe" + exit 1 +} +$cmdline = "$prog --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port `$_ }" +$cmdblock = $executioncontext.invokecommand.NewScriptBlock($cmdline) $srcdir = Get-ScriptPath -. $srcdir\background.ps1 { - ..\Debug\qpidd --auth=no --no-module-dir --port=0 --log-to-file qpidd.log $args | foreach { set-content qpidd.port $_ } } +. $srcdir\background.ps1 $cmdblock + $wait_time = 0 while (!(Test-Path qpidd.port) -and ($wait_time -lt 10)) { Start-Sleep 2 diff --git a/qpid/cpp/src/tests/start_cluster b/qpid/cpp/src/tests/start_cluster index 585ba082d5..fb3d27373a 100755 --- a/qpid/cpp/src/tests/start_cluster +++ b/qpid/cpp/src/tests/start_cluster @@ -23,20 +23,17 @@ # # Execute command with the ais group set. -with_ais_group() { - id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group." 1>&2; exit 1; } - echo $* | newgrp ais -} +. `dirname $0`/ais_check rm -f cluster*.log cluster.ports qpidd.port SIZE=${1:-3}; shift CLUSTER=`pwd` # Cluster name=pwd, avoid clashes. -OPTS="-d --no-module-dir --load-module ../.libs/cluster.so --cluster-name=$CLUSTER --auth=no $@" +OPTS="-d --no-module-dir --load-module ../.libs/cluster.so --cluster-name=$CLUSTER --auth=no --log-enable notice+ --log-enable debug+:cluster $@" for (( i=0; i<SIZE; ++i )); do DDIR=`mktemp -d /tmp/start_cluster.XXXXXXXXXX` - PORT=`with_ais_group ../qpidd -p0 --log-to-file=cluster$i.log $OPTS --data-dir=$DDIR` || exit 1 + PORT=`with_ais_group ../qpidd -p0 --log-to-file=cluster$i.log $OPTS --data-dir=$DDIR` || exit 1 echo $PORT >> cluster.ports done diff --git a/qpid/cpp/src/tests/stop_broker.ps1 b/qpid/cpp/src/tests/stop_broker.ps1 index 165c7a63b0..4fdeb26e2b 100644 --- a/qpid/cpp/src/tests/stop_broker.ps1 +++ b/qpid/cpp/src/tests/stop_broker.ps1 @@ -21,8 +21,23 @@ Get-Content -path qpidd.port -totalCount 1 | Set-Variable -name qpid_port Remove-Item qpidd.port +# Test runs from the tests directory but the broker executable is one level +# up, and most likely in a subdirectory from there based on what build type. +# Look around for it before trying to start it. +$subs = "Debug","Release","MinSizeRel","RelWithDebInfo" +foreach ($sub in $subs) { + $prog = "..\$sub\qpidd.exe" + if (Test-Path $prog) { + break + } +} +if (!(Test-Path $prog)) { + "Cannot locate qpidd.exe" + exit 1 +} + # Piping the output makes the script wait for qpidd to finish. -..\Debug\qpidd --quit --port $qpid_port | Write-Output +Invoke-Expression "$prog --quit --port $qpid_port" | Write-Output $stopped = $? # Check qpidd.log. diff --git a/qpid/cpp/src/tests/test_store.cpp b/qpid/cpp/src/tests/test_store.cpp index 64a96bf71a..f2d3aa65a3 100644 --- a/qpid/cpp/src/tests/test_store.cpp +++ b/qpid/cpp/src/tests/test_store.cpp @@ -140,7 +140,8 @@ struct TestStorePlugin : public Plugin { { Broker* broker = dynamic_cast<Broker*>(&target); if (!broker) return; - broker->setStore (new TestStore(options.name, *broker)); + boost::shared_ptr<MessageStore> p(new TestStore(options.name, *broker)); + broker->setStore (p); } void initialize(qpid::Plugin::Target&) {} diff --git a/qpid/cpp/src/tests/topictest.ps1 b/qpid/cpp/src/tests/topictest.ps1 index 04dae23ad9..58ae50c67c 100644 --- a/qpid/cpp/src/tests/topictest.ps1 +++ b/qpid/cpp/src/tests/topictest.ps1 @@ -19,9 +19,6 @@ # Run the C++ topic test -# Clean up old log files -Get-Item subscriber_*.log | Remove-Item - # Parameters with default values: s (subscribers) m (messages) b (batches) # h (host) t (false; use transactions) param ( @@ -32,23 +29,28 @@ param ( [switch] $t # transactional ) +# Clean up old log files +Get-Item subscriber_*.log | Remove-Item + +if ($t) { + $transactional = "--transactional --durable" +} + function subscribe { - "Start subscriber $args[0]" - $LOG = "subscriber_$args[0].log" - . $srcdir\background.ps1 { - $env:OUTDIR\topic_listener $TRANSACTIONAL > $LOG 2>&1 - if ($LastExitCode -ne 0) { Remove-Item $LOG } - } -inconsole + param ([int]$num) + "Start subscriber $num" + $LOG = "subscriber_$num.log" + $cmdline = "$env:OUTDIR\topic_listener $transactional > $LOG 2>&1 + if (`$LastExitCode -ne 0) { Remove-Item $LOG }" + $cmdblock = $executioncontext.invokecommand.NewScriptBlock($cmdline) + . $srcdir\background.ps1 $cmdblock } -publish() { - if ($t) { - $transactional = "--transactional --durable" - } - $env:OUTDIR\topic_publisher --messages $messages --batches $batches --subscribers $subscribers $host $transactional 2>&1 +function publish { + Invoke-Expression "$env:OUTDIR\topic_publisher --messages $messages --batches $batches --subscribers $subscribers $host $transactional" 2>&1 } -$srcdir = Split-Path $myInvocation.ScriptName +$srcdir = Split-Path $MyInvocation.MyCommand.Path if ($broker.length) { $broker = "-h$broker" } diff --git a/qpid/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp b/qpid/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp index d51ed90758..a0b665db73 100644 --- a/qpid/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp +++ b/qpid/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp @@ -28,9 +28,23 @@ #include <crtdbg.h> #include <windows.h> +#include <iostream> namespace { +// Instead of popping up a window for exceptions, just print something out +LONG _stdcall UnhandledExceptionFilter (PEXCEPTION_POINTERS pExceptionInfo) +{ + DWORD dwExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode; + + if (dwExceptionCode == EXCEPTION_ACCESS_VIOLATION) + std::cerr << "\nERROR: ACCESS VIOLATION\n" << std::endl; + else + std::cerr << "\nERROR: UNHANDLED EXCEPTION\n" << std::endl; + + return EXCEPTION_EXECUTE_HANDLER; +} + struct redirect_errors_to_stderr { redirect_errors_to_stderr (); }; @@ -50,6 +64,9 @@ redirect_errors_to_stderr::redirect_errors_to_stderr() // and can't-open-file message boxes. SetErrorMode(SEM_FAILCRITICALERRORS); SetErrorMode(SEM_NOOPENFILEERRORBOX); + + // And this will catch all unhandled exceptions. + SetUnhandledExceptionFilter (&UnhandledExceptionFilter); } } // namespace diff --git a/qpid/cpp/src/windows/QpiddBroker.cpp b/qpid/cpp/src/windows/QpiddBroker.cpp index 5c6eef48f8..5bf9477e6a 100644 --- a/qpid/cpp/src/windows/QpiddBroker.cpp +++ b/qpid/cpp/src/windows/QpiddBroker.cpp @@ -133,6 +133,14 @@ void ShutdownHandler::run() { } } +// Console control handler to properly handle ctl-c. +BOOL CtrlHandler(DWORD ctl) +{ + ShutdownEvent shutter; // no pid specified == shut me down + shutter.signal(); + return ((ctl == CTRL_C_EVENT || ctl == CTRL_CLOSE_EVENT) ? TRUE : FALSE); +} + } struct ProcessControlOptions : public qpid::Options { @@ -245,6 +253,7 @@ int QpiddBroker::execute (QpiddOptions *options) { ShutdownHandler waitShut(brokerPtr); qpid::sys::Thread waitThr(waitShut); // Wait for shutdown event + SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); brokerPtr->run(); waitShut.signal(); // In case we shut down some other way waitThr.join(); |