diff options
author | Kim van der Riet <kpvdr@apache.org> | 2013-09-20 18:59:30 +0000 |
---|---|---|
committer | Kim van der Riet <kpvdr@apache.org> | 2013-09-20 18:59:30 +0000 |
commit | c70bf3ea28cdf6bafd8571690d3e5c466a0658a2 (patch) | |
tree | 68b24940e433f3f9c278b054d9ea1622389bd332 /qpid/cpp/src | |
parent | fcdf1723c7b5cdf0772054a93edb6e7d97c4bb1e (diff) | |
download | qpid-python-c70bf3ea28cdf6bafd8571690d3e5c466a0658a2.tar.gz |
QPID-4984: WIP - Merge from trunk r.1525056
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/linearstore@1525101 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/cpp/src')
368 files changed, 13748 insertions, 15076 deletions
diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt index dcbb17d1e0..e7cf72e745 100644 --- a/qpid/cpp/src/CMakeLists.txt +++ b/qpid/cpp/src/CMakeLists.txt @@ -26,6 +26,16 @@ foreach (r ${REQUIRE}) message(STATUS "Forcing ${r} to ${${r}_force}") endforeach(r) +# Capture specified C++ compiler (if any) +if (NOT ENV_CXX) + if (NOT "$ENV{CXX}" STREQUAL "") + set(CXX $ENV{CXX}) + else(NOT "$ENV{CXX}" STREQUAL "") + set(CXX ${CMAKE_CXX_COMPILER}) + endif(NOT "$ENV{CXX}" STREQUAL "") + set(ENV_CXX ${CXX} CACHE INTERNAL "C++ compiler specified in cmake environment") +endif (NOT ENV_CXX) + include(CheckFunctionExists) include(CheckIncludeFileCXX) include(CheckIncludeFiles) @@ -145,6 +155,13 @@ MACRO (add_msvc_version verProject verProjectType verProjectFileExt) endif (MSVC) ENDMACRO (add_msvc_version) +# Add a test to check the exported library API against expected API symbols +MACRO (add_api_test libname) + if (NOT CMAKE_SYSTEM_NAME STREQUAL Windows) + add_test(api_check_${libname} ${CMAKE_CURRENT_SOURCE_DIR}/check-abi "${ENV_CXX}" ${CMAKE_CURRENT_BINARY_DIR}/lib${libname}.so ${CMAKE_CURRENT_SOURCE_DIR}/lib${libname}-api-symbols.txt) + endif (NOT CMAKE_SYSTEM_NAME STREQUAL Windows) +ENDMACRO (add_api_test libname) + # # Install optional windows version settings. Override variables are specified in a file. @@ -263,6 +280,9 @@ 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) +# Do not keep on linking against transitive library dependencies +set (CMAKE_LINK_INTERFACE_LIBRARIES "") + if (CMAKE_COMPILER_IS_GNUCXX) # Warnings: Enable as many as possible, keep the code clean. Please # do not disable warnings or remove -Werror without discussing on @@ -279,18 +299,24 @@ if (CMAKE_COMPILER_IS_GNUCXX) if (CMAKE_SYSTEM_NAME STREQUAL SunOS) set (CATCH_UNDEFINED "") endif (CMAKE_SYSTEM_NAME STREQUAL SunOS) - set (COMPILER_FLAGS "-fvisibility-inlines-hidden") + set (COMPILER_FLAGS "-fvisibility-inlines-hidden -Wl,--as-needed") # gcc 4.1.2 on RHEL 5 needs -Wno-attributes to avoid an error that's fixed # in later gcc versions. execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if (GCC_VERSION VERSION_EQUAL 4.1.2) + set (COMPILER_FLAGS "-Wl,--as-needed") message (STATUS "Cannot use -fvisibility=hidden on gcc 4.1.2") else (GCC_VERSION VERSION_EQUAL 4.1.2) - set (HIDE_SYMBOL_FLAGS "-fvisibility=hidden") + set (HIDE_SYMBOL_FLAGS "-fno-visibility-inlines-hidden -fvisibility=hidden") endif (GCC_VERSION VERSION_EQUAL 4.1.2) endif (CMAKE_COMPILER_IS_GNUCXX) +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + set (QPID_LINKMAP ${CMAKE_CURRENT_SOURCE_DIR}/qpid.linkmap) + set (LINK_VERSION_SCRIPT_FLAG "-Wl,--version-script=${QPID_LINKMAP}") +endif (CMAKE_SYSTEM_NAME STREQUAL Linux) + if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro) set (COMPILER_FLAGS "-library=stlport4 -mt") set (WARNING_FLAGS "+w") @@ -301,9 +327,9 @@ endif (CMAKE_CXX_COMPILER_ID STREQUAL SunPro) if (CMAKE_SYSTEM_NAME STREQUAL Windows) # Allow MSVC user to select 'WinXP-SP3/Windows Server 2003' as build target version set (win32_winnt_default OFF) - if (MSVC) - set (win32_winnt_default ON) - endif (MSVC) + if (MSVC) + set (win32_winnt_default ON) + endif (MSVC) option(SET_WIN32_WINNT "In Windows-MSVC build: define _WIN32_WINNT=0x0502 to select target version: Windows XP with SP3" ${win32_winnt_default}) endif (CMAKE_SYSTEM_NAME STREQUAL Windows) @@ -356,7 +382,7 @@ endif (CMAKE_SYSTEM_NAME STREQUAL Windows) # where Boost 1.45 is supported, or we can just accept some versions using # the Additional_versions variable. if (NOT DEFINED Boost_ADDITIONAL_VERSIONS) - set (Boost_ADDITIONAL_VERSIONS + set (Boost_ADDITIONAL_VERSIONS "1.45" "1.45.0" "1.46" "1.46.0" "1.47" "1.47.0" "1.48" "1.48.0" "1.49" "1.49.0" "1.50" "1.50.0" "1.51" "1.51.0" "1.52" "1.52.0" "1.53" "1.53.0") @@ -513,44 +539,49 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../include ) link_directories( ${Boost_LIBRARY_DIRS} ) -CHECK_LIBRARY_EXISTS (rt clock_gettime "" CLOCK_GETTIME_IN_RT) -if (NOT CLOCK_GETTIME_IN_RT) - CHECK_FUNCTION_EXISTS (clock_gettime QPID_HAS_CLOCK_GETTIME) -else (NOT CLOCK_GETTIME_IN_RT) - set(CMAKE_REQUIRED_LIBS ${CMAKE_REQUIRED_LIBS} rt) - set(QPID_HAS_CLOCK_GETTIME YES CACHE BOOL "Platform has clock_gettime") -endif (NOT CLOCK_GETTIME_IN_RT) - -# Check for header file for dtrace static probes -check_include_files(sys/sdt.h HAVE_SYS_SDT_H) -if (HAVE_SYS_SDT_H) - set(probes_default ON) -endif (HAVE_SYS_SDT_H) -option(BUILD_PROBES "Build with DTrace/systemtap static probes" ${probes_default}) -if (NOT BUILD_PROBES) - set (HAVE_SYS_SDT_H 0) -endif (NOT BUILD_PROBES) - -# Check for poll/epoll header files -check_include_files(sys/poll.h HAVE_POLL) -check_include_files(sys/epoll.h HAVE_EPOLL) - -# Set default poller implementation (check from general to specific to allow overriding) -if (HAVE_POLL) - set(poller_default poll) -endif (HAVE_POLL) -if (HAVE_EPOLL) - set(poller_default epoll) -endif (HAVE_EPOLL) -set(POLLER ${poller_default} CACHE STRING "Poller implementation (poll/epoll)") - -# If not windows ensure that we have uuid library +# These dependencies aren't found on windows if (NOT CMAKE_SYSTEM_NAME STREQUAL Windows) + # Ensure we have clock_gettime + CHECK_FUNCTION_EXISTS (clock_gettime CLOCK_GETTIME_IN_LIBC) + if (NOT CLOCK_GETTIME_IN_LIBC) + CHECK_LIBRARY_EXISTS (rt clock_gettime "" CLOCK_GETTIME_IN_RT) + if (CLOCK_GETTIME_IN_RT) + set(clock_gettime_LIB "rt") + else () + message(FATAL_ERROR "Cannot find clock_gettime()") + endif (CLOCK_GETTIME_IN_RT) + endif (NOT CLOCK_GETTIME_IN_LIBC) + + # Ensure we have uuid library CHECK_LIBRARY_EXISTS (uuid uuid_compare "" HAVE_UUID) CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H) if (NOT HAVE_UUID AND NOT HAVE_UUID_H) message(FATAL_ERROR "Uuid library and/or header file not found") endif (NOT HAVE_UUID AND NOT HAVE_UUID_H) + set (uuid_LIB "uuid") + + # Check for header file for dtrace static probes + check_include_files(sys/sdt.h HAVE_SYS_SDT_H) + if (HAVE_SYS_SDT_H) + set(probes_default ON) + endif (HAVE_SYS_SDT_H) + option(BUILD_PROBES "Build with DTrace/systemtap static probes" ${probes_default}) + if (NOT BUILD_PROBES) + set (HAVE_SYS_SDT_H 0) + endif (NOT BUILD_PROBES) + + # Check for poll/epoll header files + check_include_files(sys/poll.h HAVE_POLL) + check_include_files(sys/epoll.h HAVE_EPOLL) + + # Set default poller implementation (check from general to specific to allow overriding) + if (HAVE_POLL) + set(poller_default poll) + endif (HAVE_POLL) + if (HAVE_EPOLL) + set(poller_default epoll) + endif (HAVE_EPOLL) + set(POLLER ${poller_default} CACHE STRING "Poller implementation (poll/epoll)") endif (NOT CMAKE_SYSTEM_NAME STREQUAL Windows) # See if Cyrus SASL is desired and available @@ -578,7 +609,10 @@ if (BUILD_SASL) qpid/sys/cyrus/CyrusSecurityLayer.h qpid/sys/cyrus/CyrusSecurityLayer.cpp ) - set(qpidcommon_sasl_lib sasl2) + set(sasl_LIB sasl2) +else (BUILD_SASL) + set(HAVE_SASL OFF) + set(BROKER_SASL_NAME "qpidd" CACHE STRING "SASL app name for the qpid broker") endif (BUILD_SASL) # Optional SSL/TLS support. Requires Netscape Portable Runtime on Linux. @@ -604,27 +638,23 @@ if (BUILD_SSL) set (sslcommon_SOURCES qpid/sys/windows/SslAsynchIO.cpp ) + set (ssl_SOURCES qpid/broker/windows/SslProtocolFactory.cpp ) + set (sslconnector_SOURCES qpid/client/windows/SslConnector.cpp ) - set (windows_ssl_libs Secur32.lib) - set (windows_ssl_server_libs Crypt32.lib) + set (ssl_INCLUDES "") + set (ssl_LIBDIRS "") + set (ssl_LIBS Secur32.lib) + set (ssl_server_LIBS Crypt32.lib Secur32.lib) else (CMAKE_SYSTEM_NAME STREQUAL Windows) if (NOT NSS_FOUND) message(FATAL_ERROR "nss/nspr not found, required for ssl support") endif (NOT NSS_FOUND) - foreach(f ${NSS_CFLAGS}) - set (NSS_COMPILE_FLAGS "${NSS_COMPILE_FLAGS} ${f}") - endforeach(f) - - foreach(f ${NSS_LDFLAGS}) - set (NSS_LINK_FLAGS "${NSS_LINK_FLAGS} ${f}") - endforeach(f) - set (sslcommon_SOURCES qpid/sys/ssl/check.h qpid/sys/ssl/check.cpp @@ -643,14 +673,17 @@ if (BUILD_SSL) qpid/messaging/amqp/SslTransport.cpp ) - set_source_files_properties ( - ${sslcommon_SOURCES} - ${ssl_SOURCES} - ${sslconnector_SOURCES} - PROPERTIES - COMPILE_FLAGS "${NSS_COMPILE_FLAGS}" - ) + set (ssl_INCLUDES "${NSS_INCLUDE_DIRS}") + set (ssl_LIBDIRS "${NSS_LIBRARY_DIRS}") + set (ssl_LIBS "${NSS_LIBRARIES}") + set (ssl_server_LIBS "${NSS_LIBRARIES}") endif (CMAKE_SYSTEM_NAME STREQUAL Windows) + + # Add include directories and link directories for NSS + # unfortunately this doesn't get done automatically for + # libraries detected by FindPkgConfig + include_directories(${ssl_INCLUDES}) + link_directories(${ssl_LIBDIRS}) endif (BUILD_SSL) # See if XML Exchange is desired and prerequisites are available @@ -690,7 +723,7 @@ if (BUILD_XML) qpid/xml/XmlExchange.cpp qpid/xml/XmlExchange.h qpid/xml/XmlExchangePlugin.cpp) - target_link_libraries (xml xerces-c xqilla qpidbroker pthread) + target_link_libraries (xml xerces-c xqilla qpidbroker qpidcommon) set_target_properties (xml PROPERTIES PREFIX "" COMPILE_DEFINITIONS _IN_QPID_BROKER @@ -744,16 +777,15 @@ if (BUILD_HA) qpid/ha/BrokerReplicator.h qpid/ha/ConnectionObserver.cpp qpid/ha/ConnectionObserver.h + qpid/ha/Event.cpp + qpid/ha/Event.h qpid/ha/FailoverExchange.cpp qpid/ha/FailoverExchange.h qpid/ha/HaBroker.cpp qpid/ha/HaBroker.h qpid/ha/HaPlugin.cpp - qpid/ha/hash.h qpid/ha/IdSetter.h qpid/ha/QueueSnapshot.h - qpid/ha/makeMessage.cpp - qpid/ha/makeMessage.h qpid/ha/Membership.cpp qpid/ha/Membership.h qpid/ha/Primary.cpp @@ -773,18 +805,22 @@ if (BUILD_HA) qpid/ha/StandAlone.h qpid/ha/StatusCheck.cpp qpid/ha/StatusCheck.h + qpid/ha/PrimaryTxObserver.cpp + qpid/ha/PrimaryTxObserver.h qpid/ha/types.cpp + qpid/ha/TxReplicator.cpp + qpid/ha/TxReplicator.h qpid/ha/types.h ) add_library (ha MODULE ${ha_SOURCES}) - set_target_properties (ha PROPERTIES PREFIX "" COMPILE_DEFINITIONS _IN_QPID_BROKER) - target_link_libraries (ha qpidtypes qpidcommon qpidbroker qpidmessaging) - if (CMAKE_COMPILER_IS_GNUCXX) - set_target_properties (ha PROPERTIES - PREFIX "" - LINK_FLAGS -Wl,--no-undefined) - endif (CMAKE_COMPILER_IS_GNUCXX) + target_link_libraries (ha + qpidtypes qpidcommon qpidbroker qpidmessaging + "${Boost_PROGRAM_OPTIONS_LIBRARY}") + set_target_properties (ha PROPERTIES + PREFIX "" + COMPILE_DEFINITIONS _IN_QPID_BROKER + LINK_FLAGS "${CATCH_UNDEFINED}") install (TARGETS ha DESTINATION ${QPIDD_MODULE_DIR} COMPONENT ${QPID_COMPONENT_BROKER}) @@ -799,7 +835,7 @@ include (amqp.cmake) # Check for syslog capabilities not present on all systems check_symbol_exists (LOG_AUTHPRIV "sys/syslog.h" HAVE_LOG_AUTHPRIV) check_symbol_exists (LOG_FTP "sys/syslog.h" HAVE_LOG_FTP) - + # Set default Memory Status module (Null implementation) set (qpid_memstat_module qpid/sys/MemStat.cpp @@ -834,20 +870,20 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows) ) set (qpidcommon_platform_LIBS - ${Boost_THREAD_LIBRARY} ${windows_ssl_libs} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${Boost_SYSTEM_LIBRARY} ws2_32 ) + ${Boost_THREAD_LIBRARY} + ${Boost_DATE_TIME_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ws2_32 + ) + set (qpidbroker_platform_SOURCES qpid/broker/windows/BrokerDefaults.cpp qpid/broker/windows/SaslAuthenticator.cpp ) - set (qpidbroker_platform_LIBS - ${windows_ssl_libs} ${windows_ssl_server_libs} - ) + set (qpidclient_platform_SOURCES qpid/client/windows/ClientDllMain.cpp ) - set (qpidclient_platform_LIBS - ${windows_ssl_libs} - ) set (qpidd_platform_SOURCES windows/QpiddBroker.cpp @@ -885,7 +921,7 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows) # On Linux override memory status module set (qpid_memstat_module qpid/sys/posix/MemStat.cpp - ) + ) endif (CMAKE_SYSTEM_NAME STREQUAL Linux) if (CMAKE_SYSTEM_NAME STREQUAL SunOS) @@ -908,8 +944,7 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows) set (qpidtypes_platform_SOURCES) set (qpidtypes_platform_LIBS - uuid - ${Boost_SYSTEM_LIBRARY} + "${uuid_LIB}" ) set (qpidcommon_platform_SOURCES @@ -934,9 +969,11 @@ else (CMAKE_SYSTEM_NAME STREQUAL Windows) ${qpid_system_module} ${qpid_poller_module} ) + set (qpidcommon_platform_LIBS - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${CMAKE_DL_LIBS} + "${CMAKE_DL_LIBS}" + "${clock_gettime_LIB}" + "${uuid_LIB}" ) set (qpidbroker_platform_SOURCES @@ -977,6 +1014,7 @@ set (qpidcommon_SOURCES qpid/StringUtils.cpp qpid/Url.cpp qpid/UrlArray.cpp + qpid/NullSaslClient.cpp qpid/NullSaslServer.cpp qpid/amqp_0_10/SessionHandler.cpp qpid/framing/AccumulatedAck.cpp @@ -1024,12 +1062,16 @@ set (qpidcommon_SOURCES qpid/amqp_0_10/Codecs.cpp qpid/amqp/CharSequence.h qpid/amqp/CharSequence.cpp + qpid/amqp/DataBuilder.h + qpid/amqp/DataBuilder.cpp qpid/amqp/Decoder.h qpid/amqp/Decoder.cpp qpid/amqp/Descriptor.h qpid/amqp/Descriptor.cpp qpid/amqp/Encoder.h qpid/amqp/Encoder.cpp + qpid/amqp/ListBuilder.h + qpid/amqp/ListBuilder.cpp qpid/amqp/MapHandler.h qpid/amqp/MapEncoder.h qpid/amqp/MapEncoder.cpp @@ -1060,20 +1102,17 @@ set (qpidcommon_SOURCES add_msvc_version (qpidcommon library dll) add_library (qpidcommon SHARED ${qpidcommon_SOURCES}) -if (CLOCK_GETTIME_IN_RT) - set (qpidcommon_platform_LIBS ${qpidcommon_platform_LIBS} rt) -endif (CLOCK_GETTIME_IN_RT) -# Not all platforms have NSS_LINK_FLAGS -if (NSS_LINK_FLAGS) - set (qpidcommon_LINK_FLAGS LINK_FLAGS ${NSS_LINK_FLAGS}) -endif (NSS_LINK_FLAGS) + target_link_libraries (qpidcommon qpidtypes ${qpidcommon_platform_LIBS} - ${qpidcommon_sasl_lib}) + ${Boost_PROGRAM_OPTIONS_LIBRARY} + "${sasl_LIB}" + ${ssl_LIBS}) + set_target_properties (qpidcommon PROPERTIES - VERSION ${qpidcommon_version} - SOVERSION ${qpidcommon_version_major} - ${qpidcommon_LINK_FLAGS}) + VERSION ${qpidcommon_version} + SOVERSION ${qpidcommon_version_major}) + install (TARGETS qpidcommon DESTINATION ${QPID_INSTALL_LIBDIR} COMPONENT ${QPID_COMPONENT_COMMON}) @@ -1085,17 +1124,26 @@ set(qpidtypes_SOURCES qpid/types/Variant.cpp ${qpidtypes_platform_SOURCES} ) +set_source_files_properties( + ${qpidtypes_SOURCES} + PROPERTIES + COMPILE_FLAGS "${HIDE_SYMBOL_FLAGS}") + add_msvc_version (qpidtypes library dll) add_library(qpidtypes SHARED ${qpidtypes_SOURCES}) target_link_libraries(qpidtypes ${qpidtypes_platform_LIBS}) -set_target_properties (qpidtypes PROPERTIES +set_target_properties (qpidtypes PROPERTIES + LINK_FLAGS "${HIDE_SYMBOL_FLAGS} ${LINK_VERSION_SCRIPT_FLAG}" VERSION ${qpidtypes_version} SOVERSION ${qpidtypes_version_major}) + install(TARGETS qpidtypes DESTINATION ${QPID_INSTALL_LIBDIR} COMPONENT ${QPID_COMPONENT_COMMON}) install_pdb (qpidtypes ${QPID_COMPONENT_COMMON}) +add_api_test(qpidtypes) + set (qpidclient_SOURCES ${rgen_client_srcs} ${qpidclient_platform_SOURCES} @@ -1137,9 +1185,15 @@ set (qpidclient_SOURCES add_msvc_version (qpidclient library dll) add_library (qpidclient SHARED ${qpidclient_SOURCES}) -target_link_libraries (qpidclient qpidcommon ${qpidclient_platform_LIBS}) -set_target_properties (qpidclient PROPERTIES VERSION ${qpidclient_version} -SOVERSION ${qpidclient_version_major}) + +target_link_libraries (qpidclient qpidcommon + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${ssl_LIBS}) + +set_target_properties (qpidclient PROPERTIES + VERSION ${qpidclient_version} + SOVERSION ${qpidclient_version_major}) + install (TARGETS qpidclient DESTINATION ${QPID_INSTALL_LIBDIR} COMPONENT ${QPID_COMPONENT_CLIENT}) @@ -1202,27 +1256,25 @@ set (qpidmessaging_SOURCES qpid/messaging/amqp/EncodedMessage.h qpid/messaging/amqp/EncodedMessage.cpp ) +set_source_files_properties( + ${qpidmessaging_SOURCES} + PROPERTIES + COMPILE_FLAGS "${HIDE_SYMBOL_FLAGS}") + add_msvc_version (qpidmessaging library dll) add_library (qpidmessaging SHARED ${qpidmessaging_SOURCES}) -target_link_libraries (qpidmessaging qpidclient) -set_target_properties (qpidmessaging PROPERTIES - VERSION ${qpidmessaging_version} +target_link_libraries (qpidmessaging qpidtypes qpidclient qpidcommon) +set_target_properties (qpidmessaging PROPERTIES + LINK_FLAGS "${HIDE_SYMBOL_FLAGS} ${LINK_VERSION_SCRIPT_FLAG}" + VERSION ${qpidmessaging_version} SOVERSION ${qpidmessaging_version_major}) install (TARGETS qpidmessaging DESTINATION ${QPID_INSTALL_LIBDIR} COMPONENT ${QPID_COMPONENT_CLIENT}) install_pdb (qpidmessaging ${QPID_COMPONENT_CLIENT}) -# Released source artifacts from Apache have the generated headers included in -# the source tree, not the binary tree. So don't attempt to grab them when -# they're not supposed to be there. -if (NOT QPID_GENERATED_HEADERS_IN_SOURCE) - install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../include/qpid - DESTINATION ${QPID_INSTALL_INCLUDEDIR} - COMPONENT ${QPID_COMPONENT_CLIENT_INCLUDE}) -endif (NOT QPID_GENERATED_HEADERS_IN_SOURCE) - +add_api_test(qpidmessaging) if (MSVC) # Install the DtcPlugin project and call it qpidxarm. @@ -1312,6 +1364,7 @@ set (qpidbroker_SOURCES qpid/broker/SelectorToken.cpp qpid/broker/SelectorValue.h qpid/broker/SelectorValue.cpp + qpid/broker/SelfDestructQueue.cpp qpid/broker/SemanticState.h qpid/broker/SemanticState.cpp qpid/broker/SessionAdapter.cpp @@ -1337,11 +1390,17 @@ set (qpidbroker_SOURCES ) add_msvc_version (qpidbroker library dll) add_library (qpidbroker SHARED ${qpidbroker_SOURCES}) -target_link_libraries (qpidbroker qpidcommon ${qpidbroker_platform_LIBS}) -set_target_properties (qpidbroker PROPERTIES + +target_link_libraries (qpidbroker qpidcommon qpidtypes + "${Boost_PROGRAM_OPTIONS_LIBRARY}" + "${sasl_LIB}" + ${ssl_server_LIBS}) + +set_target_properties (qpidbroker PROPERTIES VERSION ${qpidbroker_version} - SOVERSION ${qpidbroker_version_major} + SOVERSION ${qpidbroker_version_major} COMPILE_DEFINITIONS _IN_QPID_BROKER) + if (MSVC) set_target_properties (qpidbroker PROPERTIES COMPILE_FLAGS /wd4290) endif (MSVC) @@ -1373,30 +1432,6 @@ if (UNIX) install (CODE "FILE(MAKE_DIRECTORY \$ENV{DESTDIR}/${QPID_LOCALSTATE_DIR}/spool/qpidd)") endif (UNIX) -set (qmf_SOURCES - qpid/agent/ManagementAgentImpl.cpp - qpid/agent/ManagementAgentImpl.h - ) -set (qmf_HEADERS - ../include/qpid/agent/ManagementAgent.h - ../include/qpid/agent/QmfAgentImportExport.h - ../include/qmf/BrokerImportExport.h - ) - -add_msvc_version (qmf library dll) -add_library (qmf SHARED ${qmf_SOURCES}) -target_link_libraries (qmf qmfengine) -set_target_properties (qmf PROPERTIES - VERSION ${qmf_version} - SOVERSION ${qmf_version_major}) -install (TARGETS qmf OPTIONAL - DESTINATION ${QPID_INSTALL_LIBDIR} - COMPONENT ${QPID_COMPONENT_QMF}) -install (FILES ${qmf_HEADERS} - DESTINATION ${QPID_INSTALL_INCLUDEDIR}/qpid/agent - COMPONENT ${QPID_COMPONENT_QMF}) -install_pdb (qmf ${QPID_COMPONENT_QMF}) - if (NOT WIN32) set (qmf2_platform_headers ../include/qmf/posix/EventNotifier.h @@ -1477,7 +1512,7 @@ endif (NOT WIN32) add_library (qmf2 SHARED ${qmf2_SOURCES}) target_link_libraries (qmf2 qpidmessaging qpidtypes qpidclient qpidcommon) set_target_properties (qmf2 PROPERTIES - VERSION ${qmf2_version} + VERSION ${qmf2_version} SOVERSION ${qmf2_version_major}) install (TARGETS qmf2 OPTIONAL DESTINATION ${QPID_INSTALL_LIBDIR} @@ -1487,111 +1522,6 @@ endif (NOT WIN32) COMPONENT ${QPID_COMPONENT_QMF}) install_pdb (qmf2 ${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/EventImpl.cpp - qmf/engine/EventImpl.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/SequenceManager.cpp - qmf/engine/SequenceManager.h - qmf/engine/SchemaImpl.cpp - qmf/engine/SchemaImpl.h - qmf/engine/ValueImpl.cpp - qmf/engine/ValueImpl.h - ) - -set (qmfengine_HEADERS - ../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 - ) -install (FILES ${qmfengine_HEADERS} - DESTINATION ${QPID_INSTALL_INCLUDEDIR}/qmf/engine - COMPONENT ${QPID_COMPONENT_QMF}) - -if (NOT WIN32) - list(APPEND qmfengine_SOURCES qmf/engine/ResilientConnection.cpp) -endif (NOT WIN32) -add_msvc_version (qmfengine library dll) - -add_library (qmfengine SHARED ${qmfengine_SOURCES}) -target_link_libraries (qmfengine qpidclient) -set_target_properties (qmfengine PROPERTIES - VERSION ${qmfengine_version} - SOVERSION ${qmfengine_version_major}) -install (TARGETS qmfengine OPTIONAL - DESTINATION ${QPID_INSTALL_LIBDIR} - COMPONENT ${QPID_COMPONENT_QMF}) -install_pdb (qmfengine ${QPID_COMPONENT_QMF}) - -set (qmfconsole_SOURCES - qpid/console/Agent.cpp - qpid/console/Broker.cpp - qpid/console/ClassKey.cpp - qpid/console/Event.cpp - qpid/console/Object.cpp - qpid/console/ObjectId.cpp - qpid/console/Package.cpp - qpid/console/Schema.cpp - qpid/console/SequenceManager.cpp - qpid/console/SessionManager.cpp - qpid/console/Value.cpp - ) -set (qmfconsole_HEADERS - ../include/qpid/console/Agent.h - ../include/qpid/console/Broker.h - ../include/qpid/console/ClassKey.h - ../include/qpid/console/ConsoleImportExport.h - ../include/qpid/console/ConsoleListener.h - ../include/qpid/console/Event.h - ../include/qpid/console/Object.h - ../include/qpid/console/ObjectId.h - ../include/qpid/console/Package.h - ../include/qpid/console/Schema.h - ../include/qpid/console/SequenceManager.h - ../include/qpid/console/SessionManager.h - ../include/qpid/console/Value.h - ) -add_msvc_version (qmfconsole library dll) -add_library (qmfconsole SHARED ${qmfconsole_SOURCES}) -target_link_libraries (qmfconsole qpidclient) -set_target_properties (qmfconsole PROPERTIES - VERSION ${qmfconsole_version} - SOVERSION ${qmfconsole_version_major}) -install (TARGETS qmfconsole - DESTINATION ${QPID_INSTALL_LIBDIR} - COMPONENT ${QPID_COMPONENT_QMF}) -install (FILES ${qmfconsole_HEADERS} - DESTINATION ${QPID_INSTALL_INCLUDEDIR}/qpid/console - COMPONENT ${QPID_COMPONENT_QMF}) -install_pdb (qmfconsole ${QPID_COMPONENT_QMF}) - - # # Legacy store # diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am deleted file mode 100644 index 8a98cea1ee..0000000000 --- a/qpid/cpp/src/Makefile.am +++ /dev/null @@ -1,1119 +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. -# - -SUBDIRS = . tests - -# The Windows-only sources are not compiled using this Makefile, but -# are listed here to ensure they're included in releases. They are built -# using Visual Studio solutions/projects. -windows_dist = \ - qpid/client/windows/SaslFactory.cpp \ - qpid/client/windows/SslConnector.cpp \ - qpid/client/windows/ClientDllMain.cpp \ - qpid/log/windows/SinkOptions.cpp \ - qpid/log/windows/SinkOptions.h \ - ../include/qpid/sys/windows/check.h \ - qpid/sys/MemStat.cpp \ - qpid/sys/windows/AsynchIO.cpp \ - qpid/sys/windows/AsynchIoResult.h \ - ../include/qpid/sys/windows/Condition.h \ - qpid/sys/windows/FileSysDir.cpp \ - ../include/qpid/sys/windows/IntegerTypes.h \ - qpid/sys/windows/IocpPoller.cpp \ - qpid/sys/windows/IOHandle.cpp \ - qpid/sys/windows/IoHandlePrivate.h \ - qpid/sys/windows/LockFile.cpp \ - qpid/sys/windows/MemoryMappedFile.cpp \ - qpid/sys/windows/mingw32_compat.h \ - qpid/sys/windows/PollableCondition.cpp \ - qpid/sys/windows/PipeHandle.cpp \ - ../include/qpid/sys/windows/Mutex.h \ - qpid/sys/windows/QpidDllMain.h \ - qpid/sys/windows/Shlib.cpp \ - qpid/sys/windows/SocketAddress.cpp \ - qpid/sys/windows/SslAsynchIO.cpp \ - qpid/sys/windows/SslAsynchIO.h \ - qpid/sys/windows/StrError.cpp \ - qpid/sys/windows/SystemInfo.cpp \ - qpid/sys/windows/Thread.cpp \ - qpid/sys/windows/Time.cpp \ - ../include/qpid/sys/windows/Time.h \ - qpid/sys/windows/uuid.cpp \ - qpid/sys/windows/uuid.h \ - qpid/sys/windows/WinSocket.cpp \ - qpid/sys/windows/WinSocket.h \ - windows/QpiddBroker.cpp \ - windows/SCM.h \ - windows/SCM.cpp \ - qpid/broker/windows/BrokerDefaults.cpp \ - qpid/broker/windows/SaslAuthenticator.cpp \ - qpid/broker/windows/SslProtocolFactory.cpp \ - qpid/messaging/HandleInstantiator.cpp \ - windows/resources/template-resource.rc \ - windows/resources/version-resource.h \ - windows/resources/qpid-icon.ico - -EXTRA_DIST= $(platform_dist) $(rgen_srcs) $(windows_dist) - -# Define variables that are be appended to by this file and included .mk files. -nobase_include_HEADERS = -libqpidcommon_la_SOURCES = -pkgconfig_DATA = - -## Generated code - -# Note: generated soure and makefiles included in distribution so a -# distribution can be built without code generation tools and XML -# sources. - -# This phony target is needed by generated makefile fragments: -force: - -if GENERATE - -# AMQP_FINAL_XML is defined in ../configure.ac -amqp_0_10_xml=@AMQP_FINAL_XML@ -specs=$(amqp_0_10_xml) - -# Ruby generator. -rgen_dir=$(top_srcdir)/rubygen -rgen_cmd=ruby -I $(rgen_dir) $(rgen_dir)/generate . ../include $(specs) all - -$(rgen_srcs) $(srcdir)/rubygen.mk: rgen.timestamp -rgen.timestamp: $(rgen_generator) $(specs) - $(rgen_cmd) $(srcdir)/rubygen.mk && touch $@ -$(rgen_generator): - -# The CMake version is needed for dist -$(srcdir)/rubygen.cmake: $(rgen_generator) $(specs) - $(rgen_cmd) $(srcdir)/rubygen.cmake - -# Management generator. -mgen_dir=$(top_srcdir)/managementgen -mgen_xml=$(top_srcdir)/../specs/management-schema.xml \ - $(srcdir)/qpid/acl/management-schema.xml \ - $(srcdir)/qpid/ha/management-schema.xml \ - $(srcdir)/qpid/legacystore/management-schema.xml -mgen_cmd=$(mgen_dir)/qmf-gen -m $(srcdir)/managementgen.mk \ - -c $(srcdir)/managementgen.cmake -q -b -l -o qmf \ - $(mgen_xml) - -$(srcdir)/managementgen.mk $(mgen_broker_cpp) $(dist_qpid_management_HEADERS): mgen.timestamp -mgen.timestamp: $(mgen_generator) $(mgen_xml) - $(mgen_cmd); touch $@ -$(mgen_generator): - -endif # GENERATE - -include $(srcdir)/rubygen.mk -include $(srcdir)/managementgen.mk - -## Compiler flags -AM_CXXFLAGS = $(WARNING_CFLAGS) -INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(srcdir) -I=$(builddir) - -# -# Destination for intalled programs and tests defined here -# -qpidexecdir = $(libexecdir)/qpid -qpidexec_PROGRAMS = -qpidexec_SCRIPTS = -qpidtestdir = $(qpidexecdir)/tests -qpidtest_PROGRAMS = -qpidtest_SCRIPTS = -tmoduleexecdir = $(libdir)/qpid/tests -tmoduleexec_LTLIBRARIES= - -BROKER_CXXFLAGS = -D_IN_QPID_BROKER - -## Automake macros to build libraries and executables. -qpidd_CXXFLAGS = $(AM_CXXFLAGS) $(BROKER_CXXFLAGS) -DQPIDD_MODULE_DIR=\"$(dmoduleexecdir)\" -DQPIDD_CONF_FILE=\"$(sysconfdir)/qpidd.conf\" -DQPIDC_CONF_FILE=\"$(confdir)/qpidc.conf\" -libqpidcommon_la_CXXFLAGS = $(AM_CXXFLAGS) -libqpidbroker_la_CXXFLAGS = $(AM_CXXFLAGS) $(BROKER_CXXFLAGS) -libqpidclient_la_CXXFLAGS = $(AM_CXXFLAGS) -DQPIDC_MODULE_DIR=\"$(cmoduleexecdir)\" -DQPIDC_CONF_FILE=\"$(confdir)/qpidc.conf\" - -qpidd_LDADD = \ - libqpidbroker.la \ - libqpidcommon.la \ - -lboost_program_options - -posix_qpidd_src = posix/QpiddBroker.cpp - -sbin_PROGRAMS = qpidd -qpidd_SOURCES = qpidd.cpp qpidd.h $(posix_qpidd_src) - -## Platform specific code. - -# Posix-specific code -libqpidcommon_la_SOURCES += \ - qpid/log/posix/SinkOptions.cpp \ - qpid/sys/posix/IOHandle.cpp \ - qpid/sys/posix/BSDSocket.cpp \ - qpid/sys/posix/BSDSocket.h \ - qpid/sys/posix/SocketAddress.cpp \ - qpid/sys/posix/AsynchIO.cpp \ - qpid/sys/posix/FileSysDir.cpp \ - qpid/sys/posix/LockFile.cpp \ - qpid/sys/posix/MemoryMappedFile.cpp \ - qpid/sys/posix/Time.cpp \ - qpid/sys/posix/Thread.cpp \ - qpid/sys/posix/Shlib.cpp \ - qpid/sys/posix/MemStat.cpp \ - qpid/sys/posix/Mutex.cpp \ - qpid/sys/posix/Fork.cpp \ - qpid/sys/posix/StrError.cpp \ - qpid/sys/posix/PollableCondition.cpp \ - qpid/sys/posix/PidFile.h \ - qpid/sys/posix/PipeHandle.cpp \ - qpid/log/posix/SinkOptions.h \ - qpid/sys/posix/Fork.h - -nobase_include_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 - -if USE_EPOLL - poller = qpid/sys/epoll/EpollPoller.cpp -endif - -if USE_POLL - poller = qpid/sys/posix/PosixPoller.cpp -endif - -if USE_ECF - poller = qpid/sys/solaris/ECFPoller.cpp -endif - -if SUNOS - systeminfo = qpid/sys/solaris/SystemInfo.cpp -else - systeminfo = qpid/sys/posix/SystemInfo.cpp -endif - -libqpidcommon_la_SOURCES += $(poller) $(systeminfo) - -posix_broker_src = \ - qpid/broker/posix/BrokerDefaults.cpp \ - qpid/broker/posix/SocketFDPlugin.cpp - - -lib_LTLIBRARIES = libqpidtypes.la libqpidcommon.la libqpidbroker.la libqpidclient.la libqpidmessaging.la - - -# Definitions for client and daemon plugins -PLUGINLDFLAGS=-no-undefined -module -avoid-version -confdir=$(sysconfdir)/qpid -dmoduleexecdir=$(libdir)/qpid/daemon -cmoduleexecdir=$(libdir)/qpid/client -dmoduleexec_LTLIBRARIES = -cmoduleexec_LTLIBRARIES = - -include ha.mk -include qmf.mk -include qmfc.mk -if HAVE_XML -include xml.mk -endif -include legacystore.mk - -if RDMA - -# RDMA (Infiniband) protocol code -librdmawrap_la_SOURCES = \ - qpid/sys/rdma/rdma_exception.h \ - qpid/sys/rdma/rdma_factories.cpp \ - qpid/sys/rdma/rdma_factories.h \ - qpid/sys/rdma/RdmaIO.cpp \ - qpid/sys/rdma/RdmaIO.h \ - qpid/sys/rdma/rdma_wrap.cpp \ - qpid/sys/rdma/rdma_wrap.h -librdmawrap_la_LIBADD = \ - libqpidcommon.la \ - -lrdmacm \ - -libverbs -librdmawrap_la_CXXFLAGS = \ - $(AM_CXXFLAGS) -Wno-missing-field-initializers -lib_LTLIBRARIES += \ - librdmawrap.la -RDMAWRAP_VERSION_INFO = 2:0:0 -librdmawrap_la_LDFLAGS = -version-info $(RDMAWRAP_VERSION_INFO) -no-undefined - -rdma_la_SOURCES = \ - qpid/sys/RdmaIOPlugin.cpp -rdma_la_LIBADD = \ - libqpidbroker.la \ - librdmawrap.la \ - -libverbs -rdma_la_LDFLAGS = $(PLUGINLDFLAGS) -rdma_la_CXXFLAGS = \ - $(AM_CXXFLAGS) -Wno-missing-field-initializers -D_IN_QPID_BROKER -dmoduleexec_LTLIBRARIES += \ - rdma.la - -rdmaconnector_la_SOURCES = \ - qpid/client/RdmaConnector.cpp -rdmaconnector_la_LIBADD = \ - libqpidclient.la \ - librdmawrap.la \ - -libverbs -rdmaconnector_la_LDFLAGS = $(PLUGINLDFLAGS) -rdmaconnector_la_CXXFLAGS = \ - $(AM_CXXFLAGS) -Wno-missing-field-initializers -cmoduleexec_LTLIBRARIES += \ - rdmaconnector.la - -# RDMA test/sample programs -noinst_PROGRAMS = RdmaServer RdmaClient -RdmaServer_SOURCES = qpid/sys/rdma/RdmaServer.cpp -RdmaServer_LDADD = \ - librdmawrap.la libqpidcommon.la -RdmaClient_SOURCES = qpid/sys/rdma/RdmaClient.cpp -RdmaClient_CXXFLAGS = \ - $(AM_CXXFLAGS) -Wno-missing-field-initializers -RdmaClient_LDADD = \ - librdmawrap.la libqpidcommon.la - -endif - -EXTRA_DIST +=\ - CMakeLists.txt \ - config.h.cmake \ - amqp.cmake \ - rdma.cmake \ - legacystore.cmake \ - managementgen.cmake \ - rubygen.cmake \ - versions.cmake \ - finddb.cmake \ - $(rgen_amqp_0_10_srcs) \ - qpid/amqp_0_10/apply.h \ - qpid/amqp_0_10/built_in_types.h \ - qpid/amqp_0_10/complex_types.cpp \ - qpid/amqp_0_10/Array.h \ - qpid/amqp_0_10/Array.cpp \ - qpid/amqp_0_10/Body.h \ - qpid/amqp_0_10/Command.h \ - qpid/amqp_0_10/CommmandPacker.h \ - qpid/amqp_0_10/Control.h \ - qpid/amqp_0_10/Header.h \ - qpid/amqp_0_10/Header.cpp \ - qpid/amqp_0_10/FrameHeader.h \ - qpid/amqp_0_10/FrameHeader.cpp \ - qpid/amqp_0_10/Holder.h \ - qpid/amqp_0_10/Codec.h \ - qpid/amqp_0_10/Packer.h \ - qpid/amqp_0_10/Decimal.h \ - qpid/amqp_0_10/SerializableString.h \ - qpid/amqp_0_10/Map.h \ - qpid/amqp_0_10/Map.cpp \ - qpid/amqp_0_10/Struct.h \ - qpid/amqp_0_10/Struct32.h \ - qpid/amqp_0_10/Struct32.cpp \ - qpid/amqp_0_10/Unit.h \ - qpid/amqp_0_10/Unit.cpp \ - qpid/amqp_0_10/UnitHandler.h \ - qpid/amqp_0_10/UnknownType.h \ - qpid/amqp_0_10/UnknownType.cpp \ - qpid/amqp_0_10/UnknownStruct.h \ - qpid/amqp_0_10/UnknownStruct.cpp \ - qpid/store - -libqpidcommon_la_LIBADD = \ - libqpidtypes.la \ - -lboost_program_options \ - -luuid \ - -lpthread \ - $(LIB_DLOPEN) \ - $(LIB_CLOCK_GETTIME) - -libqpidcommon_la_SOURCES += \ - $(rgen_framing_srcs) \ - $(platform_src) \ - qpid/Address.cpp \ - qpid/DataDir.cpp \ - qpid/DataDir.h \ - qpid/DisableExceptionLogging.h \ - qpid/Exception.cpp \ - qpid/Modules.cpp \ - qpid/Modules.h \ - qpid/Options.cpp \ - qpid/Plugin.cpp \ - qpid/Plugin.h \ - qpid/RefCounted.h \ - qpid/RefCountedBuffer.cpp \ - qpid/RefCountedBuffer.h \ - qpid/BufferRef.h \ - qpid/Sasl.h \ - qpid/SaslFactory.cpp \ - qpid/SaslFactory.h \ - qpid/SaslServer.h \ - qpid/NullSaslServer.h \ - qpid/NullSaslServer.cpp \ - qpid/Serializer.h \ - qpid/SessionId.cpp \ - qpid/SessionState.cpp \ - qpid/SessionState.h \ - qpid/SessionState.h \ - qpid/SharedObject.h \ - qpid/StringUtils.cpp \ - qpid/StringUtils.h \ - qpid/Url.cpp \ - qpid/UrlArray.cpp \ - qpid/UrlArray.h \ - qpid/Version.h \ - qpid/amqp_0_10/Exception.h \ - qpid/amqp_0_10/SessionHandler.cpp \ - qpid/amqp_0_10/SessionHandler.h \ - qpid/amqp_0_10/apply.h \ - qpid/assert.cpp qpid/assert.h \ - qpid/assert.h \ - qpid/framing/AMQBody.cpp \ - qpid/framing/AMQBody.h \ - qpid/framing/AMQContentBody.cpp \ - qpid/framing/AMQContentBody.h \ - qpid/framing/AMQDataBlock.h \ - qpid/framing/AMQFrame.cpp \ - qpid/framing/AMQFrame.h \ - qpid/framing/AMQHeaderBody.cpp \ - qpid/framing/AMQHeaderBody.h \ - qpid/framing/AMQHeartbeatBody.cpp \ - qpid/framing/AMQHeartbeatBody.h \ - qpid/framing/AMQMethodBody.cpp \ - qpid/framing/AMQMethodBody.h \ - qpid/framing/AMQP_HighestVersion.h \ - qpid/framing/AMQP_HighestVersion.h \ - qpid/framing/AccumulatedAck.cpp \ - qpid/framing/AccumulatedAck.h \ - qpid/framing/Array.cpp \ - qpid/framing/BodyFactory.h \ - qpid/framing/Buffer.cpp \ - qpid/framing/ResizableBuffer.h \ - qpid/framing/ChannelHandler.h \ - qpid/framing/Endian.cpp \ - qpid/framing/Endian.h \ - qpid/framing/FieldTable.cpp \ - qpid/framing/FieldValue.cpp \ - qpid/framing/FrameDecoder.cpp \ - qpid/framing/FrameDecoder.h \ - qpid/framing/FrameDefaultVisitor.h \ - qpid/framing/FrameHandler.h \ - qpid/framing/FrameSet.cpp \ - qpid/framing/FrameSet.h \ - qpid/framing/Handler.h \ - qpid/framing/HeaderProperties.h \ - qpid/framing/InitiationHandler.h \ - qpid/framing/InputHandler.h \ - qpid/framing/Invoker.h \ - qpid/framing/IsInSequenceSet.h \ - qpid/framing/List.cpp \ - qpid/framing/MethodBodyFactory.h \ - qpid/framing/MethodContent.h \ - qpid/framing/ModelMethod.h \ - qpid/framing/ProtocolInitiation.cpp \ - qpid/framing/ProtocolInitiation.h \ - qpid/framing/ProtocolVersion.cpp \ - qpid/framing/Proxy.cpp \ - qpid/framing/Proxy.h \ - qpid/framing/SendContent.cpp \ - qpid/framing/SendContent.h \ - qpid/framing/SequenceNumber.cpp \ - qpid/framing/SequenceNumberSet.cpp \ - qpid/framing/SequenceNumberSet.h \ - qpid/framing/SequenceSet.cpp \ - qpid/framing/TransferContent.cpp \ - qpid/framing/TransferContent.h \ - qpid/framing/TypeFilter.h \ - qpid/framing/Uuid.cpp \ - qpid/framing/Visitor.h \ - qpid/framing/amqp_framing.h \ - qpid/framing/frame_functors.h \ - qpid/framing/variant.h \ - qpid/log/Helpers.h \ - qpid/log/Logger.cpp \ - qpid/log/Options.cpp \ - qpid/log/OstreamOutput.cpp \ - qpid/log/OstreamOutput.h \ - qpid/log/Selector.cpp \ - qpid/log/Statement.cpp \ - qpid/management/Buffer.cpp \ - qpid/management/ConnectionSettings.cpp \ - qpid/management/Manageable.cpp \ - qpid/management/ManagementObject.cpp \ - qpid/management/Mutex.cpp \ - qpid/memory.h \ - qpid/pointer_to_other.h \ - qpid/ptr_map.h \ - qpid/sys/AggregateOutput.cpp \ - qpid/sys/AggregateOutput.h \ - qpid/sys/AsynchIO.h \ - qpid/sys/AsynchIOHandler.cpp \ - qpid/sys/AsynchIOHandler.h \ - qpid/sys/AtomicCount.h \ - qpid/sys/AtomicValue.h \ - qpid/sys/AtomicValue_gcc.h \ - qpid/sys/AtomicValue_mutex.h \ - qpid/sys/BlockingQueue.h \ - qpid/sys/Codec.h \ - qpid/sys/ConnectionCodec.h \ - qpid/sys/ConnectionInputHandler.h \ - qpid/sys/ConnectionInputHandlerFactory.h \ - qpid/sys/ConnectionOutputHandler.h \ - qpid/sys/CopyOnWriteArray.h \ - qpid/sys/DeletionManager.h \ - qpid/sys/DispatchHandle.cpp \ - qpid/sys/DispatchHandle.h \ - qpid/sys/Dispatcher.cpp \ - qpid/sys/Dispatcher.h \ - qpid/sys/FileSysDir.h \ - qpid/sys/Fork.h \ - qpid/sys/LockFile.h \ - qpid/sys/LockPtr.h \ - qpid/sys/MemoryMappedFile.h \ - qpid/sys/MemStat.h \ - qpid/sys/OutputControl.h \ - qpid/sys/OutputTask.h \ - qpid/sys/PipeHandle.h \ - qpid/sys/PollableCondition.h \ - qpid/sys/PollableQueue.h \ - qpid/sys/Poller.h \ - qpid/sys/Probes.h \ - qpid/sys/regex.h \ - qpid/sys/Runnable.cpp \ - qpid/sys/ScopedIncrement.h \ - qpid/sys/SecurityLayer.h \ - qpid/sys/SecuritySettings.h \ - qpid/sys/Semaphore.h \ - qpid/sys/Shlib.cpp \ - qpid/sys/Shlib.h \ - qpid/sys/ShutdownHandler.h \ - qpid/sys/Socket.h \ - qpid/sys/SocketAddress.h \ - qpid/sys/StateMonitor.h \ - qpid/sys/Timer.cpp \ - qpid/sys/Timer.h \ - qpid/sys/TimerWarnings.cpp \ - qpid/sys/TimerWarnings.h \ - qpid/sys/Waitable.h \ - qpid/sys/uuid.h \ - qpid/sys/unordered_map.h \ - qpid/amqp_0_10/CodecsInternal.h \ - qpid/amqp_0_10/Codecs.cpp \ - qpid/amqp/CharSequence.h \ - qpid/amqp/CharSequence.cpp \ - qpid/amqp/Codec.h \ - qpid/amqp/Constructor.h \ - qpid/amqp/Decoder.h \ - qpid/amqp/Decoder.cpp \ - qpid/amqp/Descriptor.h \ - qpid/amqp/Descriptor.cpp \ - qpid/amqp/descriptors.h \ - qpid/amqp/Encoder.h \ - qpid/amqp/Encoder.cpp \ - qpid/amqp/ListReader.h \ - qpid/amqp/LoggingReader.h \ - qpid/amqp/MapHandler.h \ - qpid/amqp/MapEncoder.h \ - qpid/amqp/MapEncoder.cpp \ - qpid/amqp/MapSizeCalculator.h \ - qpid/amqp/MapSizeCalculator.cpp \ - qpid/amqp/MapBuilder.h \ - qpid/amqp/MapBuilder.cpp \ - qpid/amqp/MapReader.h \ - qpid/amqp/MapReader.cpp \ - qpid/amqp/MessageEncoder.h \ - qpid/amqp/MessageEncoder.cpp \ - qpid/amqp/MessageId.h \ - qpid/amqp/MessageId.cpp \ - qpid/amqp/MessageReader.h \ - qpid/amqp/MessageReader.cpp \ - qpid/amqp/Reader.h \ - qpid/amqp/Sasl.h \ - qpid/amqp/Sasl.cpp \ - qpid/amqp/SaslClient.h \ - qpid/amqp/SaslClient.cpp \ - qpid/amqp/SaslServer.h \ - qpid/amqp/SaslServer.cpp \ - qpid/amqp/typecodes.h - -#libqpidcommon is not really the 'right' place for the Transport -#interface, which is only used in 1.0 impl of messaging API, but this -#lets the 1.0 SSL support be included in the existing sslconnector lib -#which in turn addresses common ssl needs in qpidclient and -#qpidmessaging: -libqpidcommon_la_SOURCES += \ - qpid/messaging/amqp/Transport.h \ - qpid/messaging/amqp/Transport.cpp \ - qpid/messaging/amqp/TransportContext.h - -if HAVE_SASL -libqpidcommon_la_SOURCES += qpid/sys/cyrus/CyrusSecurityLayer.h -libqpidcommon_la_SOURCES += qpid/sys/cyrus/CyrusSecurityLayer.cpp -libqpidcommon_la_LIBADD += -lsasl2 -endif - -QPIDCOMMON_VERSION_INFO = 2:0:0 -libqpidcommon_la_LDFLAGS=-version-info $(QPIDCOMMON_VERSION_INFO) - -libqpidbroker_la_LIBADD = libqpidcommon.la -libqpidbroker_la_SOURCES = \ - $(mgen_broker_cpp) \ - $(posix_broker_src) \ - qpid/acl/Acl.cpp \ - qpid/acl/Acl.h \ - qpid/acl/AclConnectionCounter.cpp \ - qpid/acl/AclConnectionCounter.h \ - qpid/acl/AclData.cpp \ - qpid/acl/AclData.h \ - qpid/acl/AclPlugin.cpp \ - qpid/acl/AclReader.cpp \ - qpid/acl/AclReader.h \ - qpid/acl/AclResourceCounter.cpp \ - qpid/acl/AclResourceCounter.h \ - qpid/acl/AclTopicMatch.h \ - qpid/acl/AclValidator.cpp \ - qpid/acl/AclValidator.h \ - qpid/amqp_0_10/Connection.cpp \ - qpid/amqp_0_10/Connection.h \ - qpid/broker/AclModule.h \ - qpid/broker/Bridge.cpp \ - qpid/broker/Bridge.h \ - qpid/broker/Broker.cpp \ - qpid/broker/Broker.h \ - qpid/broker/BrokerImportExport.h \ - qpid/broker/amqp_0_10/Connection.cpp \ - qpid/broker/amqp_0_10/Connection.h \ - qpid/broker/ConnectionHandler.cpp \ - qpid/broker/ConnectionHandler.h \ - qpid/broker/Consumer.h \ - qpid/broker/Credit.h \ - qpid/broker/Credit.cpp \ - qpid/broker/ConsumerFactory.h \ - qpid/broker/Connection.h \ - qpid/broker/ConnectionObserver.h \ - qpid/broker/ConnectionObservers.h \ - qpid/broker/ConfigurationObserver.h \ - qpid/broker/ConfigurationObservers.h \ - qpid/broker/Daemon.cpp \ - qpid/broker/Daemon.h \ - qpid/broker/Deliverable.h \ - qpid/broker/DeliverableMessage.cpp \ - qpid/broker/DeliverableMessage.h \ - qpid/broker/DeliveryId.h \ - qpid/broker/DeliveryRecord.cpp \ - qpid/broker/DeliveryRecord.h \ - qpid/broker/DirectExchange.cpp \ - qpid/broker/DirectExchange.h \ - qpid/broker/DtxAck.cpp \ - qpid/broker/DtxAck.h \ - qpid/broker/DtxBuffer.cpp \ - qpid/broker/DtxBuffer.h \ - qpid/broker/DtxManager.cpp \ - qpid/broker/DtxManager.h \ - qpid/broker/DtxTimeout.cpp \ - qpid/broker/DtxTimeout.h \ - qpid/broker/DtxWorkRecord.cpp \ - qpid/broker/DtxWorkRecord.h \ - qpid/broker/Exchange.cpp \ - qpid/broker/Exchange.h \ - qpid/broker/ExchangeRegistry.cpp \ - qpid/broker/ExchangeRegistry.h \ - qpid/broker/ExpiryPolicy.cpp \ - qpid/broker/ExpiryPolicy.h \ - qpid/broker/Fairshare.h \ - qpid/broker/Fairshare.cpp \ - qpid/broker/FanOutExchange.cpp \ - qpid/broker/FanOutExchange.h \ - qpid/broker/FedOps.h \ - qpid/broker/HandlerImpl.h \ - qpid/broker/HeadersExchange.cpp \ - qpid/broker/HeadersExchange.h \ - qpid/broker/AsyncCompletion.h \ - qpid/broker/IngressCompletion.h \ - qpid/broker/IngressCompletion.cpp \ - qpid/broker/IndexedDeque.h \ - qpid/broker/Link.cpp \ - qpid/broker/Link.h \ - qpid/broker/LinkRegistry.cpp \ - qpid/broker/LinkRegistry.h \ - qpid/broker/Lvq.h \ - qpid/broker/Lvq.cpp \ - qpid/broker/Message.cpp \ - qpid/broker/Message.h \ - qpid/broker/MessageAdapter.cpp \ - qpid/broker/MessageAdapter.h \ - qpid/broker/MessageBuilder.cpp \ - qpid/broker/MessageBuilder.h \ - qpid/broker/MessageDeque.h \ - qpid/broker/MessageDeque.cpp \ - qpid/broker/MessageInterceptor.h \ - qpid/broker/MessageMap.h \ - qpid/broker/MessageMap.cpp \ - qpid/broker/Messages.h \ - qpid/broker/MessageStore.h \ - qpid/broker/MessageStoreModule.cpp \ - qpid/broker/MessageStoreModule.h \ - qpid/broker/PagedQueue.h \ - qpid/broker/PagedQueue.cpp \ - qpid/broker/PriorityQueue.h \ - qpid/broker/PriorityQueue.cpp \ - qpid/broker/Protocol.h \ - qpid/broker/Protocol.cpp \ - qpid/broker/NameGenerator.cpp \ - qpid/broker/NameGenerator.h \ - qpid/broker/NullMessageStore.cpp \ - qpid/broker/NullMessageStore.h \ - qpid/broker/ObjectFactory.h \ - qpid/broker/ObjectFactory.cpp \ - qpid/broker/Observers.h \ - qpid/broker/OwnershipToken.h \ - qpid/broker/Persistable.h \ - qpid/broker/PersistableConfig.h \ - qpid/broker/PersistableExchange.h \ - qpid/broker/PersistableMessage.cpp \ - qpid/broker/PersistableMessage.h \ - qpid/broker/PersistableObject.h \ - qpid/broker/PersistableObject.cpp \ - qpid/broker/PersistableQueue.h \ - qpid/broker/Queue.cpp \ - qpid/broker/Queue.h \ - qpid/broker/QueueBindings.cpp \ - qpid/broker/QueueBindings.h \ - qpid/broker/QueueCleaner.cpp \ - qpid/broker/QueueCleaner.h \ - qpid/broker/QueueCursor.h \ - qpid/broker/QueueCursor.cpp \ - qpid/broker/QueueDepth.h \ - qpid/broker/QueueDepth.cpp \ - qpid/broker/QueueFactory.h \ - qpid/broker/QueueFactory.cpp \ - qpid/broker/QueueSettings.h \ - qpid/broker/QueueSettings.cpp \ - qpid/broker/QueueListeners.cpp \ - qpid/broker/QueueListeners.h \ - qpid/broker/QueueObserver.h \ - qpid/broker/QueueRegistry.cpp \ - qpid/broker/QueueRegistry.h \ - qpid/broker/QueuedMessage.cpp \ - qpid/broker/QueuedMessage.h \ - qpid/broker/QueueFlowLimit.h \ - qpid/broker/QueueFlowLimit.cpp \ - qpid/broker/LossyQueue.h \ - qpid/broker/LossyQueue.cpp \ - qpid/broker/RecoverableConfig.h \ - qpid/broker/RecoverableExchange.h \ - qpid/broker/RecoverableMessage.h \ - qpid/broker/RecoverableQueue.h \ - qpid/broker/RecoverableTransaction.h \ - qpid/broker/RecoveredDequeue.cpp \ - qpid/broker/RecoveredDequeue.h \ - qpid/broker/RecoveredEnqueue.cpp \ - qpid/broker/RecoveredEnqueue.h \ - qpid/broker/RecoveryManager.h \ - qpid/broker/RecoveryManagerImpl.cpp \ - qpid/broker/RecoveryManagerImpl.h \ - qpid/broker/RecoverableMessageImpl.h \ - qpid/broker/RetryList.cpp \ - qpid/broker/RetryList.h \ - qpid/broker/SaslAuthenticator.cpp \ - qpid/broker/SaslAuthenticator.h \ - qpid/broker/SecureConnection.cpp \ - qpid/broker/SecureConnection.h \ - qpid/broker/SecureConnectionFactory.cpp \ - qpid/broker/SecureConnectionFactory.h \ - qpid/broker/Selector.cpp \ - qpid/broker/Selector.h \ - qpid/broker/SelectorExpression.cpp \ - qpid/broker/SelectorExpression.h \ - qpid/broker/SelectorToken.cpp \ - qpid/broker/SelectorToken.h \ - qpid/broker/SelectorValue.cpp \ - qpid/broker/SelectorValue.h \ - qpid/broker/SemanticState.cpp \ - qpid/broker/SemanticState.h \ - qpid/broker/SessionAdapter.cpp \ - qpid/broker/SessionAdapter.h \ - qpid/broker/SessionAdapter.h \ - qpid/broker/SessionContext.h \ - qpid/broker/SessionHandler.cpp \ - qpid/broker/SessionHandler.h \ - qpid/broker/SessionManager.cpp \ - qpid/broker/SessionManager.h \ - qpid/broker/SessionManager.h \ - qpid/broker/SessionOutputException.h \ - qpid/broker/SessionState.cpp \ - qpid/broker/SessionState.h \ - qpid/broker/SignalHandler.cpp \ - qpid/broker/SignalHandler.h \ - qpid/broker/System.cpp \ - qpid/broker/System.h \ - qpid/broker/ThresholdAlerts.cpp \ - qpid/broker/ThresholdAlerts.h \ - qpid/broker/TopicExchange.cpp \ - qpid/broker/TopicExchange.h \ - qpid/broker/TopicKeyNode.h \ - qpid/broker/TransactionalStore.h \ - qpid/broker/TxAccept.cpp \ - qpid/broker/TxAccept.h \ - qpid/broker/TxBuffer.cpp \ - qpid/broker/TxBuffer.h \ - qpid/broker/TxOp.h \ - qpid/broker/Vhost.cpp \ - qpid/broker/Vhost.h \ - qpid/broker/MessageDistributor.h \ - qpid/broker/FifoDistributor.h \ - qpid/broker/FifoDistributor.cpp \ - qpid/broker/MessageGroupManager.cpp \ - qpid/broker/MessageGroupManager.h \ - qpid/broker/amqp_0_10/MessageTransfer.h \ - qpid/broker/amqp_0_10/MessageTransfer.cpp \ - qpid/management/ManagementAgent.cpp \ - qpid/management/ManagementAgent.h \ - qpid/management/ManagementDirectExchange.cpp \ - qpid/management/ManagementDirectExchange.h \ - qpid/management/ManagementTopicExchange.cpp \ - qpid/management/ManagementTopicExchange.h \ - qpid/sys/TCPIOPlugin.cpp \ - qpid/sys/SocketTransport.cpp \ - qpid/sys/SocketTransport.h \ - qpid/sys/TransportFactory.h - -QPIDBROKER_VERSION_INFO = 2:0:0 -libqpidbroker_la_LDFLAGS = -version-info $(QPIDBROKER_VERSION_INFO) - -if HAVE_PROTON - -dmoduleexec_LTLIBRARIES += amqp.la -amqp_la_LIBADD = libqpidcommon.la -amqp_la_SOURCES = \ - qpid/broker/amqp/Authorise.h \ - qpid/broker/amqp/Authorise.cpp \ - qpid/broker/amqp/BrokerContext.h \ - qpid/broker/amqp/BrokerContext.cpp \ - qpid/broker/amqp/Connection.h \ - qpid/broker/amqp/Connection.cpp \ - qpid/broker/amqp/DataReader.h \ - qpid/broker/amqp/DataReader.cpp \ - qpid/broker/amqp/Domain.h \ - qpid/broker/amqp/Domain.cpp \ - qpid/broker/amqp/Exception.h \ - qpid/broker/amqp/Exception.cpp \ - qpid/broker/amqp/Filter.h \ - qpid/broker/amqp/Filter.cpp \ - qpid/broker/amqp/Header.h \ - qpid/broker/amqp/Header.cpp \ - qpid/broker/amqp/Incoming.h \ - qpid/broker/amqp/Incoming.cpp \ - qpid/broker/amqp/Interconnect.h \ - qpid/broker/amqp/Interconnect.cpp \ - qpid/broker/amqp/Interconnects.h \ - qpid/broker/amqp/Interconnects.cpp \ - qpid/broker/amqp/ManagedConnection.h \ - qpid/broker/amqp/ManagedConnection.cpp \ - qpid/broker/amqp/ManagedSession.h \ - qpid/broker/amqp/ManagedSession.cpp \ - qpid/broker/amqp/ManagedIncomingLink.h \ - qpid/broker/amqp/ManagedIncomingLink.cpp \ - qpid/broker/amqp/ManagedOutgoingLink.h \ - qpid/broker/amqp/ManagedOutgoingLink.cpp \ - qpid/broker/amqp/Message.h \ - qpid/broker/amqp/Message.cpp \ - qpid/broker/amqp/NodeProperties.h \ - qpid/broker/amqp/NodeProperties.cpp \ - qpid/broker/amqp/Outgoing.h \ - qpid/broker/amqp/Outgoing.cpp \ - qpid/broker/amqp/ProtocolPlugin.cpp \ - qpid/broker/amqp/Relay.h \ - qpid/broker/amqp/Relay.cpp \ - qpid/broker/amqp/Sasl.h \ - qpid/broker/amqp/Sasl.cpp \ - qpid/broker/amqp/SaslClient.h \ - qpid/broker/amqp/SaslClient.cpp \ - qpid/broker/amqp/Session.h \ - qpid/broker/amqp/Session.cpp \ - qpid/broker/amqp/Topic.h \ - qpid/broker/amqp/Topic.cpp \ - qpid/broker/amqp/Translation.h \ - qpid/broker/amqp/Translation.cpp - -amqp_la_CXXFLAGS=$(AM_CXXFLAGS) $(BROKER_CXXFLAGS) $(PROTON_CFLAGS) -amqp_la_LDFLAGS = $(PLUGINLDFLAGS) $(PROTON_LIBS) - -cmoduleexec_LTLIBRARIES += amqpc.la -amqpc_la_LIBADD = libqpidcommon.la -amqpc_la_SOURCES = \ - qpid/messaging/amqp/AddressHelper.h \ - qpid/messaging/amqp/AddressHelper.cpp \ - qpid/messaging/amqp/ConnectionContext.h \ - qpid/messaging/amqp/ConnectionContext.cpp \ - qpid/messaging/amqp/ConnectionHandle.h \ - qpid/messaging/amqp/ConnectionHandle.cpp \ - qpid/messaging/amqp/DriverImpl.h \ - qpid/messaging/amqp/DriverImpl.cpp \ - qpid/messaging/amqp/ReceiverContext.h \ - qpid/messaging/amqp/ReceiverContext.cpp \ - qpid/messaging/amqp/ReceiverHandle.h \ - qpid/messaging/amqp/ReceiverHandle.cpp \ - qpid/messaging/amqp/Sasl.h \ - qpid/messaging/amqp/Sasl.cpp \ - qpid/messaging/amqp/SenderContext.h \ - qpid/messaging/amqp/SenderContext.cpp \ - qpid/messaging/amqp/SenderHandle.h \ - qpid/messaging/amqp/SenderHandle.cpp \ - qpid/messaging/amqp/SessionContext.h \ - qpid/messaging/amqp/SessionContext.cpp \ - qpid/messaging/amqp/SessionHandle.h \ - qpid/messaging/amqp/SessionHandle.cpp \ - qpid/messaging/amqp/TcpTransport.h \ - qpid/messaging/amqp/TcpTransport.cpp - -amqpc_la_CXXFLAGS=$(AM_CXXFLAGS) $(PROTON_CFLAGS) -amqpc_la_LDFLAGS = $(PLUGINLDFLAGS) $(PROTON_LIBS) - -endif #HAVE_PROTON - -libqpidclient_la_LIBADD = libqpidcommon.la -luuid - -libqpidclient_la_SOURCES = \ - $(rgen_client_srcs) \ - qpid/client/Bounds.cpp \ - qpid/client/Bounds.h \ - qpid/client/ChainableFrameHandler.h \ - qpid/client/Completion.cpp \ - qpid/client/CompletionImpl.h \ - qpid/client/Connection.cpp \ - qpid/client/ConnectionAccess.h \ - qpid/client/ConnectionHandler.cpp \ - qpid/client/ConnectionHandler.h \ - qpid/client/ConnectionImpl.cpp \ - qpid/client/ConnectionImpl.h \ - qpid/client/ConnectionSettings.cpp \ - qpid/client/Connector.cpp \ - qpid/client/Connector.h \ - qpid/client/Demux.cpp \ - qpid/client/Demux.h \ - qpid/client/Dispatcher.cpp \ - qpid/client/Dispatcher.h \ - qpid/client/Execution.h \ - qpid/client/FailoverListener.cpp \ - qpid/client/FailoverManager.cpp \ - qpid/client/Future.cpp \ - qpid/client/FutureCompletion.cpp \ - qpid/client/FutureResult.cpp \ - qpid/client/LoadPlugins.h \ - qpid/client/LoadPlugins.cpp \ - qpid/client/LocalQueue.cpp \ - qpid/client/LocalQueueImpl.cpp \ - qpid/client/LocalQueueImpl.h \ - qpid/client/Message.cpp \ - qpid/client/MessageImpl.cpp \ - qpid/client/MessageImpl.h \ - qpid/client/MessageListener.cpp \ - qpid/client/MessageReplayTracker.cpp \ - qpid/client/PrivateImplRef.h \ - qpid/client/QueueOptions.cpp \ - qpid/client/Results.cpp \ - qpid/client/Results.h \ - qpid/client/SessionBase_0_10.cpp \ - qpid/client/SessionBase_0_10Access.h \ - qpid/client/SessionImpl.cpp \ - qpid/client/SessionImpl.h \ - qpid/client/StateManager.cpp \ - qpid/client/StateManager.h \ - qpid/client/Subscription.cpp \ - qpid/client/SubscriptionImpl.cpp \ - qpid/client/SubscriptionImpl.h \ - qpid/client/SubscriptionManager.cpp \ - qpid/client/SubscriptionManagerImpl.cpp \ - qpid/client/SubscriptionManagerImpl.h \ - qpid/client/TCPConnector.cpp \ - qpid/client/TCPConnector.h - -QPIDCLIENT_VERSION_INFO = 2:0:0 -libqpidclient_la_LDFLAGS = -version-info $(QPIDCLIENT_VERSION_INFO) - -if SSL -include ssl.mk -endif - -libqpidtypes_la_LIBADD= -luuid -libqpidtypes_la_SOURCES= \ - qpid/types/Exception.cpp \ - qpid/types/Uuid.cpp \ - qpid/types/Variant.cpp \ - ../include/qpid/types/ImportExport.h - -QPIDTYPES_VERSION_INFO = 1:0:0 -libqpidtypes_la_LDFLAGS = -version-info $(QPIDTYPES_VERSION_INFO) - -libqpidmessaging_la_LIBADD = libqpidclient.la libqpidtypes.la -libqpidmessaging_la_SOURCES = \ - qpid/messaging/Address.cpp \ - qpid/messaging/AddressImpl.h \ - qpid/messaging/AddressParser.h \ - qpid/messaging/AddressParser.cpp \ - qpid/messaging/Connection.cpp \ - qpid/messaging/ConnectionOptions.h \ - qpid/messaging/ConnectionOptions.cpp \ - qpid/messaging/Duration.cpp \ - qpid/messaging/exceptions.cpp \ - qpid/messaging/Message.cpp \ - qpid/messaging/MessageImpl.h \ - qpid/messaging/MessageImpl.cpp \ - qpid/messaging/PrivateImplRef.h \ - qpid/messaging/ProtocolRegistry.h \ - qpid/messaging/ProtocolRegistry.cpp \ - qpid/messaging/Sender.cpp \ - qpid/messaging/Receiver.cpp \ - qpid/messaging/Session.cpp \ - qpid/messaging/ConnectionImpl.h \ - qpid/messaging/SenderImpl.h \ - qpid/messaging/ReceiverImpl.h \ - qpid/messaging/SessionImpl.h \ - qpid/messaging/FailoverUpdates.cpp \ - qpid/messaging/amqp/EncodedMessage.h \ - qpid/messaging/amqp/EncodedMessage.cpp \ - qpid/client/amqp0_10/AcceptTracker.h \ - qpid/client/amqp0_10/AcceptTracker.cpp \ - qpid/client/amqp0_10/AddressResolution.h \ - qpid/client/amqp0_10/AddressResolution.cpp \ - qpid/client/amqp0_10/ConnectionImpl.h \ - qpid/client/amqp0_10/ConnectionImpl.cpp \ - qpid/client/amqp0_10/IncomingMessages.h \ - qpid/client/amqp0_10/IncomingMessages.cpp \ - qpid/client/amqp0_10/MessageSink.h \ - qpid/client/amqp0_10/MessageSource.h \ - qpid/client/amqp0_10/OutgoingMessage.h \ - qpid/client/amqp0_10/OutgoingMessage.cpp \ - qpid/client/amqp0_10/ReceiverImpl.h \ - qpid/client/amqp0_10/ReceiverImpl.cpp \ - qpid/client/amqp0_10/SessionImpl.h \ - qpid/client/amqp0_10/SessionImpl.cpp \ - qpid/client/amqp0_10/SenderImpl.h \ - qpid/client/amqp0_10/SenderImpl.cpp - -QPIDMESSAGING_VERSION_INFO = 2:0:0 -libqpidmessaging_la_LDFLAGS = -version-info $(QPIDMESSAGING_VERSION_INFO) - -# NOTE: only public header files (which should be in ../include) -# should go in this list. Private headers should go in the SOURCES -# list for one of the libraries or executables that includes it. -# Also included are the swig descriptor files. - -nobase_include_HEADERS += \ - ../include/qpid/Address.h \ - ../include/qpid/CommonImportExport.h \ - ../include/qpid/Exception.h \ - ../include/qpid/ImportExport.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/amqp_0_10/Codecs.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/FailoverListener.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/Buffer.h \ - ../include/qpid/management/ConnectionSettings.h \ - ../include/qpid/management/Manageable.h \ - ../include/qpid/management/ManagementEvent.h \ - ../include/qpid/management/ManagementObject.h \ - ../include/qpid/management/Mutex.h \ - ../include/qpid/sys/Condition.h \ - ../include/qpid/sys/ExceptionHolder.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/Duration.h \ - ../include/qpid/messaging/exceptions.h \ - ../include/qpid/messaging/Handle.h \ - ../include/qpid/messaging/ImportExport.h \ - ../include/qpid/messaging/Message.h \ - ../include/qpid/messaging/Receiver.h \ - ../include/qpid/messaging/Sender.h \ - ../include/qpid/messaging/Session.h \ - ../include/qpid/messaging/FailoverUpdates.h \ - ../include/qpid/types/Exception.h \ - ../include/qpid/types/Uuid.h \ - ../include/qpid/types/Variant.h \ - ../include/qpid/types/ImportExport.h \ - ../include/qpid/qpid.i \ - ../include/qmf/qmfengine.i \ - ../include/qmf/qmf2.i - -# Create the default data directory -install-data-local: - $(mkinstalldirs) $(DESTDIR)/$(localstatedir)/lib/qpidd - -# Support for pkg-config -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA += qpid.pc - diff --git a/qpid/cpp/src/amqp.cmake b/qpid/cpp/src/amqp.cmake index 2d0ca06250..38b7d01315 100644 --- a/qpid/cpp/src/amqp.cmake +++ b/qpid/cpp/src/amqp.cmake @@ -23,15 +23,43 @@ include(FindPkgConfig) pkg_check_modules(PROTON libqpid-proton) +if (NOT PROTON_FOUND) + # if pkg-config is absent or fails to find proton then use + # PROTON_ROOT command line option or environment variable to locate + # local installed proton build. + if (NOT PROTON_ROOT) + set (PROTON_ROOT "$ENV{PROTON_ROOT}") + endif() + if (PROTON_ROOT) + find_package(proton PATHS ${PROTON_ROOT} NO_DEFAULT_PATH) + + if (proton_FOUND EQUAL 1) + set(iFile "${PROTON_ROOT}/lib/proton.cmake/libqpid-proton.cmake") + if(EXISTS ${iFile}) + include("${iFile}") + else() + message(FATAL_ERROR "PROTON_ROOT defined but file ${iFile} is missing") + endif() + else() + message(FATAL_ERROR "Proton package files not found in ${PROTON_ROOT}") + endif() + endif() +endif() + set (amqp_default ${amqp_force}) -set (required_version 0.3) +set (minimum_version 0.5) +set (maximum_version 0.5) if (PROTON_FOUND) - if (PROTON_VERSION LESS ${required_version}) - message(STATUS "Qpid proton is too old, amqp 1.0 support not enabled") - else (PROTON_VERSION LESS ${required_version}) - message(STATUS "Qpid proton found, amqp 1.0 support enabled") - set (amqp_default ON) - endif (PROTON_VERSION LESS ${required_version}) + if (PROTON_VERSION LESS ${minimum_version}) + message(STATUS "Qpid proton ${PROTON_VERSION} is too old, require ${minimum_version} - ${maximum_version}; amqp 1.0 support not enabled") + else (PROTON_VERSION LESS ${minimum_version}) + if (PROTON_VERSION GREATER ${maximum_version}) + message(STATUS "Qpid proton ${PROTON_VERSION} is too new, require ${minimum_version} - ${maximum_version}; amqp 1.0 support not enabled") + else (PROTON_VERSION GREATER ${maximum_version}) + message(STATUS "Qpid proton found, amqp 1.0 support enabled") + set (amqp_default ON) + endif (PROTON_VERSION GREATER ${maximum_version}) + endif (PROTON_VERSION LESS ${minimum_version}) else (PROTON_FOUND) message(STATUS "Qpid proton not found, amqp 1.0 support not enabled") endif (PROTON_FOUND) @@ -43,15 +71,6 @@ if (BUILD_AMQP) message(FATAL_ERROR "Qpid proton not found, required for amqp 1.0 support") endif (NOT PROTON_FOUND) - foreach(f ${PROTON_CFLAGS}) - set (PROTON_COMPILE_FLAGS "${PROTON_COMPILE_FLAGS} ${f}") - endforeach(f) - - foreach(f ${PROTON_LDFLAGS}) - set (PROTON_LINK_FLAGS "${PROTON_LINK_FLAGS} ${f}") - endforeach(f) - - set (amqp_SOURCES qpid/broker/amqp/Authorise.h qpid/broker/amqp/Authorise.cpp @@ -103,18 +122,21 @@ if (BUILD_AMQP) qpid/broker/amqp/Translation.h qpid/broker/amqp/Translation.cpp ) + + include_directories(${PROTON_INCLUDE_DIRS}) + link_directories(${PROTON_LIBRARY_DIRS}) + add_library (amqp MODULE ${amqp_SOURCES}) - target_link_libraries (amqp qpidbroker qpidcommon) + target_link_libraries (amqp qpidtypes qpidbroker qpidcommon ${PROTON_LIBRARIES} ${Boost_PROGRAM_OPTIONS_LIBRARY}) set_target_properties (amqp PROPERTIES PREFIX "" - COMPILE_FLAGS "${PROTON_COMPILE_FLAGS}" - LINK_FLAGS "${PROTON_LINK_FLAGS}") - set_target_properties (amqp PROPERTIES COMPILE_DEFINITIONS _IN_QPID_BROKER) + LINK_FLAGS "${CATCH_UNDEFINED}" + COMPILE_DEFINITIONS _IN_QPID_BROKER) + install (TARGETS amqp DESTINATION ${QPIDD_MODULE_DIR} COMPONENT ${QPID_COMPONENT_BROKER}) - set (amqpc_SOURCES qpid/messaging/amqp/AddressHelper.h qpid/messaging/amqp/AddressHelper.cpp @@ -142,11 +164,11 @@ if (BUILD_AMQP) qpid/messaging/amqp/TcpTransport.cpp ) add_library (amqpc MODULE ${amqpc_SOURCES}) - target_link_libraries (amqpc qpidclient qpidcommon) + target_link_libraries (amqpc qpidmessaging qpidtypes qpidclient qpidcommon ${PROTON_LIBRARIES}) set_target_properties (amqpc PROPERTIES PREFIX "" - COMPILE_FLAGS "${PROTON_COMPILE_FLAGS}" - LINK_FLAGS "${PROTON_LINK_FLAGS}") + LINK_FLAGS "${CATCH_UNDEFINED}") + install (TARGETS amqpc DESTINATION ${QPIDC_MODULE_DIR} COMPONENT ${QPID_COMPONENT_CLIENT}) diff --git a/qpid/cpp/src/check-abi b/qpid/cpp/src/check-abi new file mode 100755 index 0000000000..2b5d4eda68 --- /dev/null +++ b/qpid/cpp/src/check-abi @@ -0,0 +1,81 @@ +#! /bin/bash + +# Ask the compiler the implementation specific type for a standard typedeffed type +# (int64_t, size_t etc.). Operates by test compiling and using the demangling ABI call. +# +# This works for gcc and clang on Unix. +full_type_of () { + prog=$(mktemp) + trap "rm $prog" EXIT + + ${CXX:-g++} -x c++ -o $prog - <<END-FILE +#include <stdint.h> +#include <stdlib.h> +#include <cxxabi.h> +#include <iostream> +#include <typeinfo> + +int main() { + int status; + char* printable_type = + __cxxabiv1::__cxa_demangle(typeid($1).name(), 0, 0, &status); + if (printable_type) { + std::cout << printable_type; + } else { + std::cout << "$1"; + } + ::free(printable_type); +} +END-FILE +$prog +} + +rc=0 +syms_desired=$(mktemp) +syms_library=$(mktemp) +syms_missing=$(mktemp) +syms_extra=$(mktemp) + +trap 'rm $syms_desired $syms_library $syms_missing $syms_extra' EXIT + +CXX=$1 +export CXX + +# Extract exported symbols from library +nm -DC --defined-only -f s $2 | cut -f1 -d'|' -s | sort -u > $syms_library + +# Process API syms (substitute in some typedefs etc.) +sed $3 -e " + s/uint64_t/$(full_type_of uint64_t)/ + s/uint32_t/unsigned int/ + s/uint16_t/unsigned short/ + s/uint8_t/unsigned char/ + s/size_t/$(full_type_of size_t)/ + s/int64_t/$(full_type_of int64_t)/ + s/int32_t/int/ + s/int16_t/short/ + s/int8_t/signed char/ + s/qpid::types::Variant::Map/std::map<std::string, qpid::types::Variant, std::less<std::string>, std::allocator<std::pair<std::string const, qpid::types::Variant> > >/ + s/qpid::types::Variant::List/std::list<qpid::types::Variant, std::allocator<qpid::types::Variant> >/ + /^\$/d + /^#.*\$/d +" | sort -u > $syms_desired + +comm -23 $syms_desired $syms_library > $syms_missing +comm -13 $syms_desired $syms_library > $syms_extra + +if [ -n "$(cat $syms_missing)" ] ; then + (echo "Not exported from library (should be)" + echo "=====================================" + cat $syms_missing ) 1>&2 + rc=1 +fi + + +if [ -n "$(cat $syms_extra)" ]; then + (echo "Exported by library but not in spec" + echo "===================================" + cat $syms_extra ) 1>&2 +fi + +exit $rc diff --git a/qpid/cpp/src/finddb.cmake b/qpid/cpp/src/finddb.cmake index fad827cffe..2f2f94f469 100644 --- a/qpid/cpp/src/finddb.cmake +++ b/qpid/cpp/src/finddb.cmake @@ -22,31 +22,33 @@ if(UNIX) # - Find BerkeleyDB # Find the BerkeleyDB includes and library # This module defines -# DB_INCLUDE_DIR, where to find db.h, etc. +# DB_CXX_INCLUDE_DIR, where to find db_cxx.h, etc. # DB_LIBRARIES, the libraries needed to use BerkeleyDB. # DB_FOUND, If false, do not try to use BerkeleyDB. # also defined, but not for general use are # DB_LIBRARY, where to find the BerkeleyDB library. -FIND_PATH(DB_INCLUDE_DIR db.h +FIND_PATH(DB_CXX_INCLUDE_DIR db_cxx.h /usr/local/include/db4 + /usr/local/include/libdb4 /usr/local/include /usr/include/db4 + /usr/include/libdb4 /usr/include ) -SET(DB_NAMES ${DB_NAMES} db_cxx) +SET(DB_NAMES ${DB_NAMES} db_cxx db_cxx-4) FIND_LIBRARY(DB_LIBRARY NAMES ${DB_NAMES} PATHS /usr/lib /usr/local/lib ) -IF (DB_LIBRARY AND DB_INCLUDE_DIR) +IF (DB_LIBRARY AND DB_CXX_INCLUDE_DIR) SET(DB_LIBRARIES ${DB_LIBRARY}) SET(DB_FOUND "YES") -ELSE (DB_LIBRARY AND DB_INCLUDE_DIR) +ELSE (DB_LIBRARY AND DB_CXX_INCLUDE_DIR) UNSET( DB_FOUND ) -ENDIF (DB_LIBRARY AND DB_INCLUDE_DIR) +ENDIF (DB_LIBRARY AND DB_CXX_INCLUDE_DIR) IF (DB_FOUND) @@ -60,15 +62,15 @@ ELSE (DB_FOUND) ENDIF (DB_FOUND) # Deprecated declarations. -SET (NATIVE_DB_INCLUDE_PATH ${DB_INCLUDE_DIR} ) +SET (NATIVE_DB_INCLUDE_PATH ${DB_CXX_INCLUDE_DIR} ) GET_FILENAME_COMPONENT (NATIVE_DB_LIB_PATH ${DB_LIBRARY} PATH) MARK_AS_ADVANCED( DB_LIBRARY - DB_INCLUDE_DIR + DB_CXX_INCLUDE_DIR ) else(UNIX) MESSAGE(STATUS "BerkeleyDB is ignored on non-Unix platforms") UNSET( DB_FOUND ) -endif(UNIX)
\ No newline at end of file +endif(UNIX) diff --git a/qpid/cpp/src/ha.mk b/qpid/cpp/src/ha.mk deleted file mode 100644 index aa3a572286..0000000000 --- a/qpid/cpp/src/ha.mk +++ /dev/null @@ -1,72 +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. -# -# -# HA plugin makefile fragment, to be included in Makefile.am -# - -dmoduleexec_LTLIBRARIES += ha.la - -ha_la_SOURCES = \ - qpid/ha/AlternateExchangeSetter.h \ - qpid/ha/Backup.cpp \ - qpid/ha/Backup.h \ - qpid/ha/BackupConnectionExcluder.h \ - qpid/ha/BrokerInfo.cpp \ - qpid/ha/BrokerInfo.h \ - qpid/ha/BrokerReplicator.cpp \ - qpid/ha/BrokerReplicator.h \ - qpid/ha/ConnectionObserver.cpp \ - qpid/ha/ConnectionObserver.h \ - qpid/ha/FailoverExchange.cpp \ - qpid/ha/FailoverExchange.h \ - qpid/ha/HaBroker.cpp \ - qpid/ha/HaBroker.h \ - qpid/ha/HaPlugin.cpp \ - qpid/ha/hash.h \ - qpid/ha/IdSetter.h \ - qpid/ha/QueueSnapshot.h \ - qpid/ha/makeMessage.cpp \ - qpid/ha/makeMessage.h \ - qpid/ha/Membership.cpp \ - qpid/ha/Membership.h \ - qpid/ha/Primary.cpp \ - qpid/ha/Primary.h \ - qpid/ha/QueueGuard.cpp \ - qpid/ha/QueueGuard.h \ - qpid/ha/QueueReplicator.cpp \ - qpid/ha/QueueReplicator.h \ - qpid/ha/QueueSnapshot.h \ - qpid/ha/QueueSnapshots.h \ - qpid/ha/RemoteBackup.cpp \ - qpid/ha/RemoteBackup.h \ - qpid/ha/ReplicatingSubscription.cpp \ - qpid/ha/ReplicatingSubscription.h \ - qpid/ha/ReplicationTest.cpp \ - qpid/ha/ReplicationTest.h \ - qpid/ha/Role.h \ - qpid/ha/Settings.h \ - qpid/ha/StandAlone.h \ - qpid/ha/StatusCheck.cpp \ - qpid/ha/StatusCheck.h \ - qpid/ha/types.cpp \ - qpid/ha/types.h - -ha_la_LIBADD = libqpidbroker.la libqpidmessaging.la -ha_la_LDFLAGS = $(PLUGINLDFLAGS) -ha_la_CXXFLAGS = $(AM_CXXFLAGS) -D_IN_QPID_BROKER diff --git a/qpid/cpp/src/legacystore.cmake b/qpid/cpp/src/legacystore.cmake index 9d6876b8d6..1fdb51aa32 100644 --- a/qpid/cpp/src/legacystore.cmake +++ b/qpid/cpp/src/legacystore.cmake @@ -126,10 +126,10 @@ if (BUILD_LEGACYSTORE) ) if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/db-inc.h) - message(STATUS "Including BDB from ${DB_INCLUDE_DIR}/db_cxx.h") + message(STATUS "Including BDB from ${DB_CXX_INCLUDE_DIR}/db_cxx.h") file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/db-inc.h - "#include <${DB_INCLUDE_DIR}/db_cxx.h>\n") + "#include <${DB_CXX_INCLUDE_DIR}/db_cxx.h>\n") endif() add_library (legacystore MODULE diff --git a/qpid/cpp/src/legacystore.mk b/qpid/cpp/src/legacystore.mk deleted file mode 100644 index 7dbfac8a28..0000000000 --- a/qpid/cpp/src/legacystore.mk +++ /dev/null @@ -1,110 +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. -# -# -# Legacy store plugin makefile fragment, to be included in Makefile.am -# NOTE: this fragment only includes legacystore sources in -# the distribution, it does not build the store. -# -# To build the store use the cmake build system, see ../INSTALL -# - -EXTRA_DIST += \ - qpid/legacystore/BindingDbt.cpp \ - qpid/legacystore/BindingDbt.h \ - qpid/legacystore/BufferValue.cpp \ - qpid/legacystore/BufferValue.h \ - qpid/legacystore/Cursor.h \ - qpid/legacystore/DataTokenImpl.cpp \ - qpid/legacystore/DataTokenImpl.h \ - qpid/legacystore/IdDbt.cpp \ - qpid/legacystore/IdDbt.h \ - qpid/legacystore/IdSequence.cpp \ - qpid/legacystore/IdSequence.h \ - qpid/legacystore/JournalImpl.cpp \ - qpid/legacystore/JournalImpl.h \ - qpid/legacystore/MessageStoreImpl.cpp \ - qpid/legacystore/MessageStoreImpl.h \ - qpid/legacystore/PreparedTransaction.cpp \ - qpid/legacystore/PreparedTransaction.h \ - qpid/legacystore/StoreException.h \ - qpid/legacystore/StorePlugin.cpp \ - qpid/legacystore/TxnCtxt.cpp \ - qpid/legacystore/TxnCtxt.h \ - qpid/legacystore/jrnl/aio.cpp \ - qpid/legacystore/jrnl/aio.h \ - qpid/legacystore/jrnl/aio_callback.h \ - qpid/legacystore/jrnl/cvar.cpp \ - qpid/legacystore/jrnl/cvar.h \ - qpid/legacystore/jrnl/data_tok.cpp \ - qpid/legacystore/jrnl/data_tok.h \ - qpid/legacystore/jrnl/deq_hdr.h \ - qpid/legacystore/jrnl/deq_rec.cpp \ - qpid/legacystore/jrnl/deq_rec.h \ - qpid/legacystore/jrnl/enq_hdr.h \ - qpid/legacystore/jrnl/enq_map.cpp \ - qpid/legacystore/jrnl/enq_map.h \ - qpid/legacystore/jrnl/enq_rec.cpp \ - qpid/legacystore/jrnl/enq_rec.h \ - qpid/legacystore/jrnl/enums.h \ - qpid/legacystore/jrnl/fcntl.cpp \ - qpid/legacystore/jrnl/fcntl.h \ - qpid/legacystore/jrnl/file_hdr.h \ - qpid/legacystore/jrnl/jcfg.h \ - qpid/legacystore/jrnl/jcntl.cpp \ - qpid/legacystore/jrnl/jcntl.h \ - qpid/legacystore/jrnl/jdir.cpp \ - qpid/legacystore/jrnl/jdir.h \ - qpid/legacystore/jrnl/jerrno.cpp \ - qpid/legacystore/jrnl/jerrno.h \ - qpid/legacystore/jrnl/jexception.cpp \ - qpid/legacystore/jrnl/jexception.h \ - qpid/legacystore/jrnl/jinf.cpp \ - qpid/legacystore/jrnl/jinf.h \ - qpid/legacystore/jrnl/jrec.cpp \ - qpid/legacystore/jrnl/jrec.h \ - qpid/legacystore/jrnl/lp_map.cpp \ - qpid/legacystore/jrnl/lp_map.h \ - qpid/legacystore/jrnl/lpmgr.cpp \ - qpid/legacystore/jrnl/lpmgr.h \ - qpid/legacystore/jrnl/pmgr.cpp \ - qpid/legacystore/jrnl/pmgr.h \ - qpid/legacystore/jrnl/rcvdat.h \ - qpid/legacystore/jrnl/rec_hdr.h \ - qpid/legacystore/jrnl/rec_tail.h \ - qpid/legacystore/jrnl/rfc.cpp \ - qpid/legacystore/jrnl/rfc.h \ - qpid/legacystore/jrnl/rmgr.cpp \ - qpid/legacystore/jrnl/rmgr.h \ - qpid/legacystore/jrnl/rrfc.cpp \ - qpid/legacystore/jrnl/rrfc.h \ - qpid/legacystore/jrnl/slock.cpp \ - qpid/legacystore/jrnl/slock.h \ - qpid/legacystore/jrnl/smutex.cpp \ - qpid/legacystore/jrnl/smutex.h \ - qpid/legacystore/jrnl/time_ns.cpp \ - qpid/legacystore/jrnl/time_ns.h \ - qpid/legacystore/jrnl/txn_hdr.h \ - qpid/legacystore/jrnl/txn_map.cpp \ - qpid/legacystore/jrnl/txn_map.h \ - qpid/legacystore/jrnl/txn_rec.cpp \ - qpid/legacystore/jrnl/txn_rec.h \ - qpid/legacystore/jrnl/wmgr.cpp \ - qpid/legacystore/jrnl/wmgr.h \ - qpid/legacystore/jrnl/wrfc.cpp \ - qpid/legacystore/jrnl/wrfc.h diff --git a/qpid/cpp/src/libqpidmessaging-api-symbols.txt b/qpid/cpp/src/libqpidmessaging-api-symbols.txt new file mode 100644 index 0000000000..dc889afaed --- /dev/null +++ b/qpid/cpp/src/libqpidmessaging-api-symbols.txt @@ -0,0 +1,214 @@ +# Address +qpid::messaging::Address::Address() +qpid::messaging::Address::Address(std::string const&) +qpid::messaging::Address::Address(std::string const&, std::string const&, qpid::types::Variant::Map const&, std::string const&) +qpid::messaging::Address::Address(qpid::messaging::Address const&) +qpid::messaging::Address::~Address() +qpid::messaging::Address::operator=(qpid::messaging::Address const&) +qpid::messaging::Address::getName() const +qpid::messaging::Address::setName(std::string const&) +qpid::messaging::Address::getSubject() const +qpid::messaging::Address::setSubject(std::string const&) +qpid::messaging::Address::getOptions() const +qpid::messaging::Address::getOptions() +qpid::messaging::Address::setOptions(qpid::types::Variant::Map const&) +qpid::messaging::Address::getType() const +qpid::messaging::Address::setType(std::string const&) +qpid::messaging::Address::str() const +qpid::messaging::Address::operator bool() const +qpid::messaging::Address::operator!() const + +qpid::messaging::operator<<(std::ostream&, qpid::messaging::Address const&) + +# Connection +qpid::messaging::Connection::Connection(qpid::messaging::ConnectionImpl*) +qpid::messaging::Connection::Connection(qpid::messaging::Connection const&) +qpid::messaging::Connection::Connection() +qpid::messaging::Connection::Connection(std::string const&, qpid::types::Variant::Map const&) +qpid::messaging::Connection::Connection(std::string const&, std::string const&) +qpid::messaging::Connection::~Connection() +qpid::messaging::Connection::operator=(qpid::messaging::Connection const&) +qpid::messaging::Connection::setOption(std::string const&, qpid::types::Variant const&) +qpid::messaging::Connection::open() +qpid::messaging::Connection::isOpen() +qpid::messaging::Connection::isOpen() const +qpid::messaging::Connection::close() +qpid::messaging::Connection::createTransactionalSession(std::string const&) +qpid::messaging::Connection::createSession(std::string const&) +qpid::messaging::Connection::getSession(std::string const&) const +qpid::messaging::Connection::getAuthenticatedUsername() + +# Duration +qpid::messaging::Duration::Duration(uint64_t) +qpid::messaging::Duration::getMilliseconds() const +qpid::messaging::Duration::FOREVER +qpid::messaging::Duration::IMMEDIATE +qpid::messaging::Duration::SECOND +qpid::messaging::Duration::MINUTE + +qpid::messaging::operator*(qpid::messaging::Duration const&, uint64_t) +qpid::messaging::operator*(uint64_t, qpid::messaging::Duration const&) +qpid::messaging::operator==(qpid::messaging::Duration const&, qpid::messaging::Duration const&) +qpid::messaging::operator!=(qpid::messaging::Duration const&, qpid::messaging::Duration const&) + +# FailoverUpdates (this is a very strange class - more like a property of a Connection) +qpid::messaging::FailoverUpdates::FailoverUpdates(qpid::messaging::Connection&) +qpid::messaging::FailoverUpdates::~FailoverUpdates() + +# Message +qpid::messaging::Message::Message(std::string const&) +qpid::messaging::Message::Message(char const*, size_t) +qpid::messaging::Message::Message(qpid::messaging::Message const&) +qpid::messaging::Message::Message(qpid::types::Variant&) +qpid::messaging::Message::~Message() +qpid::messaging::Message::operator=(qpid::messaging::Message const&) +qpid::messaging::Message::setReplyTo(qpid::messaging::Address const&) +qpid::messaging::Message::getReplyTo() const +qpid::messaging::Message::setSubject(std::string const&) +qpid::messaging::Message::getSubject() const +qpid::messaging::Message::setContentType(std::string const&) +qpid::messaging::Message::getContentType() const +qpid::messaging::Message::setMessageId(std::string const&) +qpid::messaging::Message::getMessageId() const +qpid::messaging::Message::setUserId(std::string const&) +qpid::messaging::Message::getUserId() const +qpid::messaging::Message::setCorrelationId(std::string const&) +qpid::messaging::Message::getCorrelationId() const +qpid::messaging::Message::setPriority(uint8_t) +qpid::messaging::Message::getPriority() const +qpid::messaging::Message::setTtl(qpid::messaging::Duration) +qpid::messaging::Message::getTtl() const +qpid::messaging::Message::setDurable(bool) +qpid::messaging::Message::getDurable() const +qpid::messaging::Message::getRedelivered() const +qpid::messaging::Message::setRedelivered(bool) +qpid::messaging::Message::getProperties() const +qpid::messaging::Message::getProperties() +qpid::messaging::Message::setContent(std::string const&) +qpid::messaging::Message::setContent(char const*, size_t) +qpid::messaging::Message::getContent() const +qpid::messaging::Message::setContentBytes(std::string const&) +qpid::messaging::Message::getContentBytes() const +qpid::messaging::Message::setContentObject(qpid::types::Variant const&) +qpid::messaging::Message::getContentObject() +qpid::messaging::Message::getContentObject() const +qpid::messaging::Message::getContentPtr() const +qpid::messaging::Message::getContentSize() const +qpid::messaging::Message::setProperty(std::string const&, qpid::types::Variant const&) + +# Receiver +qpid::messaging::Receiver::Receiver(qpid::messaging::ReceiverImpl*) +qpid::messaging::Receiver::Receiver(qpid::messaging::Receiver const&) +qpid::messaging::Receiver::~Receiver() +qpid::messaging::Receiver::operator=(qpid::messaging::Receiver const&) +qpid::messaging::Receiver::get(qpid::messaging::Message&, qpid::messaging::Duration) +qpid::messaging::Receiver::get(qpid::messaging::Duration) +qpid::messaging::Receiver::fetch(qpid::messaging::Message&, qpid::messaging::Duration) +qpid::messaging::Receiver::fetch(qpid::messaging::Duration) +qpid::messaging::Receiver::setCapacity(uint32_t) +qpid::messaging::Receiver::getCapacity() +qpid::messaging::Receiver::getAvailable() +qpid::messaging::Receiver::getUnsettled() +qpid::messaging::Receiver::close() +qpid::messaging::Receiver::isClosed() const +qpid::messaging::Receiver::getName() const +qpid::messaging::Receiver::getSession() const +qpid::messaging::Receiver::getAddress() const + +# Sender +qpid::messaging::Sender::Sender(qpid::messaging::SenderImpl*) +qpid::messaging::Sender::Sender(qpid::messaging::Sender const&) +qpid::messaging::Sender::~Sender() +qpid::messaging::Sender::operator=(qpid::messaging::Sender const&) +qpid::messaging::Sender::send(qpid::messaging::Message const&, bool) +qpid::messaging::Sender::close() +qpid::messaging::Sender::setCapacity(uint32_t) +qpid::messaging::Sender::getCapacity() +qpid::messaging::Sender::getUnsettled() +qpid::messaging::Sender::getAvailable() +qpid::messaging::Sender::getName() const +qpid::messaging::Sender::getSession() const +qpid::messaging::Sender::getAddress() const + +# Session +qpid::messaging::Session::Session(qpid::messaging::SessionImpl*) +qpid::messaging::Session::Session(qpid::messaging::Session const&) +qpid::messaging::Session::~Session() +qpid::messaging::Session::operator=(qpid::messaging::Session const&) +qpid::messaging::Session::close() +qpid::messaging::Session::commit() +qpid::messaging::Session::rollback() +qpid::messaging::Session::acknowledge(bool) +qpid::messaging::Session::acknowledge(qpid::messaging::Message&, bool) +qpid::messaging::Session::acknowledgeUpTo(qpid::messaging::Message&, bool) +qpid::messaging::Session::reject(qpid::messaging::Message&) +qpid::messaging::Session::release(qpid::messaging::Message&) +qpid::messaging::Session::sync(bool) +qpid::messaging::Session::getReceivable() +qpid::messaging::Session::getUnsettledAcks() +qpid::messaging::Session::nextReceiver(qpid::messaging::Receiver&, qpid::messaging::Duration) +qpid::messaging::Session::nextReceiver(qpid::messaging::Duration) +qpid::messaging::Session::createSender(qpid::messaging::Address const&) +qpid::messaging::Session::createSender(std::string const&) +qpid::messaging::Session::createReceiver(qpid::messaging::Address const&) +qpid::messaging::Session::createReceiver(std::string const&) +qpid::messaging::Session::getSender(std::string const&) const +qpid::messaging::Session::getReceiver(std::string const&) const +qpid::messaging::Session::getConnection() const +qpid::messaging::Session::hasError() +qpid::messaging::Session::checkError() + +# Codec routines (properly superceded now by Messsage::setContentObject() +qpid::messaging::decode(qpid::messaging::Message const&, qpid::types::Variant::Map&, std::string const&) +qpid::messaging::decode(qpid::messaging::Message const&, qpid::types::Variant::List&, std::string const&) +qpid::messaging::encode(qpid::types::Variant::Map const&, qpid::messaging::Message&, std::string const&) +qpid::messaging::encode(qpid::types::Variant::List const&, qpid::messaging::Message&, std::string const&) + +# Exceptions +qpid::messaging::EncodingException::EncodingException(std::string const&) +qpid::messaging::EncodingException::~EncodingException() + +qpid::messaging::MessagingException::MessagingException(std::string const&) +qpid::messaging::MessagingException::~MessagingException() + +qpid::messaging::InvalidOptionString::InvalidOptionString(std::string const&) +qpid::messaging::InvalidOptionString::~InvalidOptionString() +qpid::messaging::KeyError::KeyError(std::string const&) +qpid::messaging::KeyError::~KeyError() +qpid::messaging::LinkError::LinkError(std::string const&) +qpid::messaging::LinkError::~LinkError() +qpid::messaging::AddressError::AddressError(std::string const&) +qpid::messaging::AddressError::~AddressError() +qpid::messaging::ResolutionError::ResolutionError(std::string const&) +qpid::messaging::ResolutionError::~ResolutionError() +qpid::messaging::AssertionFailed::AssertionFailed(std::string const&) +qpid::messaging::AssertionFailed::~AssertionFailed() +qpid::messaging::NotFound::NotFound(std::string const&) +qpid::messaging::NotFound::~NotFound() +qpid::messaging::MalformedAddress::MalformedAddress(std::string const&) +qpid::messaging::MalformedAddress::~MalformedAddress() +qpid::messaging::ReceiverError::ReceiverError(std::string const&) +qpid::messaging::ReceiverError::~ReceiverError() +qpid::messaging::FetchError::FetchError(std::string const&) +qpid::messaging::FetchError::~FetchError() +qpid::messaging::NoMessageAvailable::NoMessageAvailable() +qpid::messaging::NoMessageAvailable::~NoMessageAvailable() +qpid::messaging::SenderError::SenderError(std::string const&) +qpid::messaging::SenderError::~SenderError() +qpid::messaging::SendError::SendError(std::string const&) +qpid::messaging::SendError::~SendError() +qpid::messaging::TargetCapacityExceeded::TargetCapacityExceeded(std::string const&) +qpid::messaging::TargetCapacityExceeded::~TargetCapacityExceeded() +qpid::messaging::SessionError::SessionError(std::string const&) +qpid::messaging::SessionError::~SessionError() +qpid::messaging::TransactionError::TransactionError(std::string const&) +qpid::messaging::TransactionError::~TransactionError() +qpid::messaging::TransactionAborted::TransactionAborted(std::string const&) +qpid::messaging::TransactionAborted::~TransactionAborted() +qpid::messaging::UnauthorizedAccess::UnauthorizedAccess(std::string const&) +qpid::messaging::UnauthorizedAccess::~UnauthorizedAccess() +qpid::messaging::ConnectionError::ConnectionError(std::string const&) +qpid::messaging::ConnectionError::~ConnectionError() +qpid::messaging::TransportFailure::TransportFailure(std::string const&) +qpid::messaging::TransportFailure::~TransportFailure() + diff --git a/qpid/cpp/src/libqpidtypes-api-symbols.txt b/qpid/cpp/src/libqpidtypes-api-symbols.txt new file mode 100644 index 0000000000..5703ed7fb8 --- /dev/null +++ b/qpid/cpp/src/libqpidtypes-api-symbols.txt @@ -0,0 +1,122 @@ +# Uuid +qpid::types::Uuid::SIZE +qpid::types::Uuid::Uuid(bool) +qpid::types::Uuid::Uuid(qpid::types::Uuid const&) +qpid::types::Uuid::operator=(qpid::types::Uuid const&) +qpid::types::Uuid::Uuid(unsigned char const*) +qpid::types::Uuid::Uuid(char const*) +qpid::types::Uuid::generate() +qpid::types::Uuid::clear() +qpid::types::Uuid::isNull() const +qpid::types::Uuid::operator bool() const +qpid::types::Uuid::operator!() const +qpid::types::Uuid::str() const +qpid::types::Uuid::size() const +qpid::types::Uuid::data() const +qpid::types::Uuid::hash() const + +qpid::types::operator==(qpid::types::Uuid const&, qpid::types::Uuid const&) +qpid::types::operator!=(qpid::types::Uuid const&, qpid::types::Uuid const&) +qpid::types::operator<(qpid::types::Uuid const&, qpid::types::Uuid const&) +qpid::types::operator>(qpid::types::Uuid const&, qpid::types::Uuid const&) +qpid::types::operator<=(qpid::types::Uuid const&, qpid::types::Uuid const&) +qpid::types::operator>=(qpid::types::Uuid const&, qpid::types::Uuid const&) +qpid::types::operator<<(std::ostream&, qpid::types::Uuid) +qpid::types::operator>>(std::istream&, qpid::types::Uuid&) + +# VariantType +qpid::types::getTypeName(qpid::types::VariantType) +qpid::types::isIntegerType(qpid::types::VariantType) + +# Variant +qpid::types::Variant::Variant() +qpid::types::Variant::Variant(bool) +qpid::types::Variant::Variant(uint8_t) +qpid::types::Variant::Variant(uint16_t) +qpid::types::Variant::Variant(uint32_t) +qpid::types::Variant::Variant(uint64_t) +qpid::types::Variant::Variant(int8_t) +qpid::types::Variant::Variant(int16_t) +qpid::types::Variant::Variant(int32_t) +qpid::types::Variant::Variant(int64_t) +qpid::types::Variant::Variant(float) +qpid::types::Variant::Variant(double) +qpid::types::Variant::Variant(std::string const&) +qpid::types::Variant::Variant(char const*) +qpid::types::Variant::Variant(qpid::types::Variant::Map const&) +qpid::types::Variant::Variant(qpid::types::Variant::List const&) +qpid::types::Variant::Variant(qpid::types::Variant const&) +qpid::types::Variant::Variant(qpid::types::Uuid const&) +qpid::types::Variant::~Variant() +qpid::types::Variant::getType() const +qpid::types::Variant::isVoid() const +qpid::types::Variant::operator=(bool) +qpid::types::Variant::operator=(uint8_t) +qpid::types::Variant::operator=(uint16_t) +qpid::types::Variant::operator=(uint32_t) +qpid::types::Variant::operator=(uint64_t) +qpid::types::Variant::operator=(int8_t) +qpid::types::Variant::operator=(int16_t) +qpid::types::Variant::operator=(int32_t) +qpid::types::Variant::operator=(int64_t) +qpid::types::Variant::operator=(float) +qpid::types::Variant::operator=(double) +qpid::types::Variant::operator=(std::string const&) +qpid::types::Variant::operator=(char const*) +qpid::types::Variant::operator=(qpid::types::Variant::Map const&) +qpid::types::Variant::operator=(qpid::types::Variant::List const&) +qpid::types::Variant::operator=(qpid::types::Variant const&) +qpid::types::Variant::operator=(qpid::types::Uuid const&) +qpid::types::Variant::parse(std::string const&) +qpid::types::Variant::asBool() const +qpid::types::Variant::asUint8() const +qpid::types::Variant::asUint16() const +qpid::types::Variant::asUint32() const +qpid::types::Variant::asUint64() const +qpid::types::Variant::asInt8() const +qpid::types::Variant::asInt16() const +qpid::types::Variant::asInt32() const +qpid::types::Variant::asInt64() const +qpid::types::Variant::asFloat() const +qpid::types::Variant::asDouble() const +qpid::types::Variant::asString() const +qpid::types::Variant::asUuid() const +qpid::types::Variant::asMap() const +qpid::types::Variant::asMap() +qpid::types::Variant::asList() const +qpid::types::Variant::asList() +qpid::types::Variant::getString() const +qpid::types::Variant::getString() +qpid::types::Variant::setEncoding(std::string const&) +qpid::types::Variant::getEncoding() const +qpid::types::Variant::operator bool() const +qpid::types::Variant::operator uint8_t() const +qpid::types::Variant::operator uint16_t() const +qpid::types::Variant::operator uint32_t() const +qpid::types::Variant::operator uint64_t() const +qpid::types::Variant::operator int8_t() const +qpid::types::Variant::operator int16_t() const +qpid::types::Variant::operator int32_t() const +qpid::types::Variant::operator int64_t() const +qpid::types::Variant::operator float() const +qpid::types::Variant::operator double() const +qpid::types::Variant::operator std::string() const +qpid::types::Variant::operator qpid::types::Uuid() const +qpid::types::Variant::isEqualTo(qpid::types::Variant const&) const +qpid::types::Variant::reset() + +qpid::types::operator<<(std::ostream&, qpid::types::Variant const&) +qpid::types::operator<<(std::ostream&, qpid::types::Variant::Map const&) +qpid::types::operator<<(std::ostream&, qpid::types::Variant::List const&) +qpid::types::operator==(qpid::types::Variant const&, qpid::types::Variant const&) +qpid::types::operator!=(qpid::types::Variant const&, qpid::types::Variant const&) + +# Root of qpid::types Exception hierarchy +qpid::types::Exception::Exception(std::string const&) +qpid::types::Exception::~Exception() +qpid::types::Exception::what() const + +qpid::types::InvalidConversion::InvalidConversion(std::string const&) +qpid::types::InvalidConversion::~InvalidConversion() + + diff --git a/qpid/cpp/src/prof b/qpid/cpp/src/prof index acfbaff2d4..6276ff620a 100755 --- a/qpid/cpp/src/prof +++ b/qpid/cpp/src/prof @@ -32,8 +32,8 @@ opcontrol --start opcontrol --stop opcontrol --dump opcontrol --shutdown -opreport -l ./.libs/lt-qpidd > stats.txt -opannotate --source --output-dir=qpidd-prof ./.libs/lt-qpidd +opreport -l ./qpidd > stats.txt +opannotate --source --output-dir=qpidd-prof ./qpidd # clear the relusts #opcontrol --reset diff --git a/qpid/cpp/src/qmf.mk b/qpid/cpp/src/qmf.mk deleted file mode 100644 index 6a4bce4087..0000000000 --- a/qpid/cpp/src/qmf.mk +++ /dev/null @@ -1,177 +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. -# - -# -# qmf library makefile fragment, to be included in Makefile.am -# -lib_LTLIBRARIES += \ - libqmf.la \ - libqmfengine.la \ - libqmf2.la - -# -# Public headers for the QMF API -# -QMF_API = \ - ../include/qpid/agent/ManagementAgent.h \ - ../include/qpid/agent/QmfAgentImportExport.h \ - ../include/qmf/BrokerImportExport.h - -# -# Public headers for the QMF2 API -# -QMF2_API = \ - ../include/qmf/AgentEvent.h \ - ../include/qmf/Agent.h \ - ../include/qmf/AgentSession.h \ - ../include/qmf/ConsoleEvent.h \ - ../include/qmf/ConsoleSession.h \ - ../include/qmf/DataAddr.h \ - ../include/qmf/Data.h \ - ../include/qmf/posix/EventNotifier.h \ - ../include/qmf/exceptions.h \ - ../include/qmf/Handle.h \ - ../include/qmf/ImportExport.h \ - ../include/qmf/Query.h \ - ../include/qmf/Schema.h \ - ../include/qmf/SchemaId.h \ - ../include/qmf/SchemaMethod.h \ - ../include/qmf/SchemaProperty.h \ - ../include/qmf/SchemaTypes.h \ - ../include/qmf/Subscription.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) \ - $(QMF2_API) - -libqmf_la_SOURCES = \ - $(QMF_API) \ - qpid/agent/ManagementAgentImpl.cpp \ - qpid/agent/ManagementAgentImpl.h - -libqmf2_la_SOURCES = \ - $(QMF2_API) \ - qmf/agentCapability.h \ - qmf/Agent.cpp \ - qmf/AgentEvent.cpp \ - qmf/AgentEventImpl.h \ - qmf/AgentImpl.h \ - qmf/AgentSession.cpp \ - qmf/AgentSessionImpl.h \ - qmf/AgentSubscription.cpp \ - qmf/AgentSubscription.h \ - qmf/ConsoleEvent.cpp \ - qmf/ConsoleEventImpl.h \ - qmf/ConsoleSession.cpp \ - qmf/ConsoleSessionImpl.h \ - qmf/constants.cpp \ - qmf/constants.h \ - qmf/DataAddr.cpp \ - qmf/DataAddrImpl.h \ - qmf/Data.cpp \ - qmf/DataImpl.h \ - qmf/EventNotifierImpl.cpp \ - qmf/EventNotifierImpl.h \ - qmf/exceptions.cpp \ - qmf/Expression.cpp \ - qmf/Expression.h \ - qmf/Hash.cpp \ - qmf/Hash.h \ - qmf/PosixEventNotifier.cpp \ - qmf/PosixEventNotifierImpl.cpp \ - qmf/PosixEventNotifierImpl.h \ - qmf/PrivateImplRef.h \ - qmf/Query.cpp \ - qmf/QueryImpl.h \ - qmf/SchemaCache.cpp \ - qmf/SchemaCache.h \ - qmf/Schema.cpp \ - qmf/SchemaId.cpp \ - qmf/SchemaIdImpl.h \ - qmf/SchemaImpl.h \ - qmf/SchemaMethod.cpp \ - qmf/SchemaMethodImpl.h \ - qmf/SchemaProperty.cpp \ - qmf/SchemaPropertyImpl.h \ - qmf/Subscription.cpp \ - qmf/SubscriptionImpl.h - -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/EventImpl.cpp \ - qmf/engine/EventImpl.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 -libqmf2_la_LIBADD = libqpidmessaging.la libqpidtypes.la -libqmfengine_la_LIBADD = libqpidclient.la - -QMF_VERSION_INFO = 1:0:0 -QMF2_VERSION_INFO = 1:0:0 -QMFENGINE_VERSION_INFO = 1:1:0 - -libqmf_la_LDFLAGS = -version-info $(QMF_VERSION_INFO) -libqmf2_la_LDFLAGS = -version-info $(QMF2_VERSION_INFO) -libqmfengine_la_LDFLAGS = -version-info $(QMFENGINE_VERSION_INFO) - -pkgconfig_DATA += qmf2.pc diff --git a/qpid/cpp/src/qmf/engine/Agent.cpp b/qpid/cpp/src/qmf/engine/Agent.cpp deleted file mode 100644 index 1f08dded94..0000000000 --- a/qpid/cpp/src/qmf/engine/Agent.cpp +++ /dev/null @@ -1,915 +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/engine/Agent.h" -#include "qmf/engine/MessageImpl.h" -#include "qmf/engine/SchemaImpl.h" -#include "qmf/engine/Typecode.h" -#include "qmf/engine/EventImpl.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> -#include <qpid/framing/FieldValue.h> -#include <qpid/sys/Mutex.h> -#include <qpid/log/Statement.h> -#include <qpid/sys/Time.h> -#include <string.h> -#include <string> -#include <deque> -#include <map> -#include <iostream> -#include <fstream> -#include <boost/shared_ptr.hpp> -#include <boost/noncopyable.hpp> - -using namespace std; -using namespace qmf::engine; -using namespace qpid::framing; -using namespace qpid::sys; - -namespace qmf { -namespace engine { - - struct AgentEventImpl { - typedef boost::shared_ptr<AgentEventImpl> Ptr; - AgentEvent::EventKind kind; - uint32_t sequence; - string authUserId; - string authToken; - string name; - Object* object; - boost::shared_ptr<ObjectId> objectId; - boost::shared_ptr<Query> query; - boost::shared_ptr<Value> arguments; - string exchange; - string bindingKey; - const SchemaObjectClass* objectClass; - - AgentEventImpl(AgentEvent::EventKind k) : - kind(k), sequence(0), object(0), objectClass(0) {} - ~AgentEventImpl() {} - AgentEvent copy(); - }; - - struct AgentQueryContext { - typedef boost::shared_ptr<AgentQueryContext> Ptr; - uint32_t sequence; - string exchange; - string key; - const SchemaMethod* schemaMethod; - AgentQueryContext() : schemaMethod(0) {} - }; - - class AgentImpl : public boost::noncopyable { - public: - AgentImpl(char* label, bool internalStore); - ~AgentImpl(); - - void setStoreDir(const char* path); - void setTransferDir(const char* path); - void handleRcvMessage(Message& message); - bool getXmtMessage(Message& item) const; - void popXmt(); - bool getEvent(AgentEvent& event) const; - void popEvent(); - void newSession(); - void startProtocol(); - void heartbeat(); - void methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& arguments); - void queryResponse(uint32_t sequence, Object& object, bool prop, bool stat); - void queryComplete(uint32_t sequence); - void registerClass(SchemaObjectClass* cls); - void registerClass(SchemaEventClass* cls); - const ObjectId* addObject(Object& obj, uint64_t persistId); - const ObjectId* allocObjectId(uint64_t persistId); - const ObjectId* allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi); - void raiseEvent(Event& event); - - private: - mutable Mutex lock; - Mutex addLock; - string label; - string queueName; - string storeDir; - string transferDir; - bool internalStore; - uint64_t nextTransientId; - Uuid systemId; - uint32_t requestedBrokerBank; - uint32_t requestedAgentBank; - uint32_t assignedBrokerBank; - uint32_t assignedAgentBank; - AgentAttachment attachment; - uint16_t bootSequence; - uint64_t nextObjectId; - uint32_t nextContextNum; - deque<AgentEventImpl::Ptr> eventQueue; - deque<MessageImpl::Ptr> xmtQueue; - map<uint32_t, AgentQueryContext::Ptr> contextMap; - bool attachComplete; - - static const char* QMF_EXCHANGE; - static const char* DIR_EXCHANGE; - static const char* BROKER_KEY; - static const uint32_t MERR_UNKNOWN_METHOD = 2; - static const uint32_t MERR_UNKNOWN_PACKAGE = 8; - static const uint32_t MERR_UNKNOWN_CLASS = 9; - static const uint32_t MERR_INTERNAL_ERROR = 10; -# define MA_BUFFER_SIZE 65536 - char outputBuffer[MA_BUFFER_SIZE]; - - struct AgentClassKey { - string name; - uint8_t hash[16]; - AgentClassKey(const string& n, const uint8_t* h) : name(n) { - memcpy(hash, h, 16); - } - AgentClassKey(Buffer& buffer) { - buffer.getShortString(name); - buffer.getBin128(hash); - } - string repr() { - return name; - } - }; - - struct AgentClassKeyComp { - bool operator() (const AgentClassKey& lhs, const AgentClassKey& rhs) const - { - if (lhs.name != rhs.name) - return lhs.name < rhs.name; - else - for (int i = 0; i < 16; i++) - if (lhs.hash[i] != rhs.hash[i]) - return lhs.hash[i] < rhs.hash[i]; - return false; - } - }; - - typedef map<AgentClassKey, SchemaObjectClass*, AgentClassKeyComp> ObjectClassMap; - typedef map<AgentClassKey, SchemaEventClass*, AgentClassKeyComp> EventClassMap; - - struct ClassMaps { - ObjectClassMap objectClasses; - EventClassMap eventClasses; - }; - - map<string, ClassMaps> packages; - - AgentEventImpl::Ptr eventDeclareQueue(const string& queueName); - AgentEventImpl::Ptr eventBind(const string& exchange, const string& queue, const string& key); - AgentEventImpl::Ptr eventSetupComplete(); - AgentEventImpl::Ptr eventQuery(uint32_t num, const string& userId, const string& package, const string& cls, - 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, - const SchemaObjectClass* objectClass); - void sendBufferLH(Buffer& buf, const string& destination, const string& routingKey); - - void sendPackageIndicationLH(const string& packageName); - void sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key); - void sendCommandCompleteLH(const string& exchange, const string& key, uint32_t seq, - uint32_t code = 0, const string& text = "OK"); - void sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text=""); - void handleAttachResponse(Buffer& inBuffer); - void handlePackageRequest(Buffer& inBuffer); - void handleClassQuery(Buffer& inBuffer); - void handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, - const string& replyToExchange, const string& replyToKey); - void handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId); - void handleMethodRequest(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId); - void handleConsoleAddedIndication(); - }; -} -} - -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());} - -AgentEvent AgentEventImpl::copy() -{ - AgentEvent item; - - ::memset(&item, 0, sizeof(AgentEvent)); - item.kind = kind; - item.sequence = sequence; - item.object = object; - item.objectId = objectId.get(); - item.query = query.get(); - item.arguments = arguments.get(); - item.objectClass = objectClass; - - STRING_REF(authUserId); - STRING_REF(authToken); - STRING_REF(name); - STRING_REF(exchange); - STRING_REF(bindingKey); - - return item; -} - -AgentImpl::AgentImpl(char* _label, bool i) : - label(_label), queueName("qmfa-"), internalStore(i), nextTransientId(1), - requestedBrokerBank(0), requestedAgentBank(0), - assignedBrokerBank(0), assignedAgentBank(0), - bootSequence(1), nextObjectId(1), nextContextNum(1), attachComplete(false) -{ - queueName += Uuid(true).str(); -} - -AgentImpl::~AgentImpl() -{ -} - -void AgentImpl::setStoreDir(const char* path) -{ - Mutex::ScopedLock _lock(lock); - if (path) - storeDir = path; - else - storeDir.clear(); -} - -void AgentImpl::setTransferDir(const char* path) -{ - Mutex::ScopedLock _lock(lock); - if (path) - transferDir = path; - else - transferDir.clear(); -} - -void AgentImpl::handleRcvMessage(Message& message) -{ - Buffer inBuffer(message.body, message.length); - uint8_t opcode; - uint32_t sequence; - string replyToExchange(message.replyExchange ? message.replyExchange : ""); - string replyToKey(message.replyKey ? message.replyKey : ""); - string userId(message.userId ? message.userId : ""); - - while (Protocol::checkHeader(inBuffer, &opcode, &sequence)) { - if (opcode == Protocol::OP_ATTACH_RESPONSE) handleAttachResponse(inBuffer); - else if (opcode == Protocol::OP_SCHEMA_REQUEST) handleSchemaRequest(inBuffer, sequence, replyToExchange, replyToKey); - else if (opcode == Protocol::OP_CONSOLE_ADDED_INDICATION) handleConsoleAddedIndication(); - else if (opcode == Protocol::OP_GET_QUERY) handleGetQuery(inBuffer, sequence, replyToKey, userId); - else if (opcode == Protocol::OP_METHOD_REQUEST) handleMethodRequest(inBuffer, sequence, replyToKey, userId); - else { - QPID_LOG(error, "AgentImpl::handleRcvMessage invalid opcode=" << opcode); - break; - } - } -} - -bool AgentImpl::getXmtMessage(Message& item) const -{ - Mutex::ScopedLock _lock(lock); - if (xmtQueue.empty()) - return false; - item = xmtQueue.front()->copy(); - return true; -} - -void AgentImpl::popXmt() -{ - Mutex::ScopedLock _lock(lock); - if (!xmtQueue.empty()) - xmtQueue.pop_front(); -} - -bool AgentImpl::getEvent(AgentEvent& event) const -{ - Mutex::ScopedLock _lock(lock); - if (eventQueue.empty()) - return false; - event = eventQueue.front()->copy(); - return true; -} - -void AgentImpl::popEvent() -{ - Mutex::ScopedLock _lock(lock); - if (!eventQueue.empty()) - eventQueue.pop_front(); -} - -void AgentImpl::newSession() -{ - Mutex::ScopedLock _lock(lock); - eventQueue.clear(); - xmtQueue.clear(); - eventQueue.push_back(eventDeclareQueue(queueName)); - eventQueue.push_back(eventBind("amq.direct", queueName, queueName)); - eventQueue.push_back(eventSetupComplete()); -} - -void AgentImpl::startProtocol() -{ - Mutex::ScopedLock _lock(lock); - char rawbuffer[512]; - Buffer buffer(rawbuffer, 512); - - Protocol::encodeHeader(buffer, Protocol::OP_ATTACH_REQUEST); - buffer.putShortString(label); - systemId.encode(buffer); - buffer.putLong(requestedBrokerBank); - buffer.putLong(requestedAgentBank); - sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY); - QPID_LOG(trace, "SENT AttachRequest: reqBroker=" << requestedBrokerBank << - " reqAgent=" << requestedAgentBank); -} - -void AgentImpl::heartbeat() -{ - Mutex::ScopedLock _lock(lock); - Buffer buffer(outputBuffer, MA_BUFFER_SIZE); - - Protocol::encodeHeader(buffer, Protocol::OP_HEARTBEAT_INDICATION); - buffer.putLongLong(uint64_t(Duration(EPOCH, now()))); - stringstream key; - key << "console.heartbeat." << assignedBrokerBank << "." << assignedAgentBank; - sendBufferLH(buffer, QMF_EXCHANGE, key.str()); - QPID_LOG(trace, "SENT HeartbeatIndication"); -} - -void AgentImpl::methodResponse(uint32_t sequence, uint32_t status, char* text, const Value& argMap) -{ - Mutex::ScopedLock _lock(lock); - map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence); - if (iter == contextMap.end()) - return; - AgentQueryContext::Ptr context = iter->second; - contextMap.erase(iter); - - char* buf(outputBuffer); - uint32_t bufLen(114 + strlen(text)); // header(8) + status(4) + mstring(2 + size) + margin(100) - bool allocated(false); - - if (status == 0) { - 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()); - bufLen += val->impl->encodedSize(); - } else { - Value val(schemaArg->getType()); - bufLen += val.impl->encodedSize(); - } - } - } - } - - if (bufLen > MA_BUFFER_SIZE) { - buf = (char*) malloc(bufLen); - allocated = true; - } - - Buffer buffer(buf, bufLen); - Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, context->sequence); - buffer.putLong(status); - buffer.putMediumString(text); - if (status == 0) { - 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->getType()); - val.impl->encode(buffer); - } - } - } - } - sendBufferLH(buffer, context->exchange, context->key); - if (allocated) - free(buf); - QPID_LOG(trace, "SENT MethodResponse seq=" << context->sequence << " status=" << status << " text=" << text); -} - -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); - if (iter == contextMap.end()) - return; - AgentQueryContext::Ptr context = iter->second; - - Buffer buffer(outputBuffer, MA_BUFFER_SIZE); - Protocol::encodeHeader(buffer, Protocol::OP_OBJECT_INDICATION, context->sequence); - - object.impl->encodeSchemaKey(buffer); - object.impl->encodeManagedObjectData(buffer); - if (prop) - object.impl->encodeProperties(buffer); - if (stat) - object.impl->encodeStatistics(buffer); - - sendBufferLH(buffer, context->exchange, context->key); - QPID_LOG(trace, "SENT ContentIndication seq=" << context->sequence); -} - -void AgentImpl::queryComplete(uint32_t sequence) -{ - Mutex::ScopedLock _lock(lock); - map<uint32_t, AgentQueryContext::Ptr>::iterator iter = contextMap.find(sequence); - if (iter == contextMap.end()) - return; - - AgentQueryContext::Ptr context = iter->second; - contextMap.erase(iter); - sendCommandCompleteLH(context->exchange, context->key, context->sequence, 0, "OK"); -} - -void AgentImpl::registerClass(SchemaObjectClass* cls) -{ - Mutex::ScopedLock _lock(lock); - bool newPackage = false; - - map<string, ClassMaps>::iterator iter = packages.find(cls->getClassKey()->getPackageName()); - if (iter == packages.end()) { - packages[cls->getClassKey()->getPackageName()] = ClassMaps(); - iter = packages.find(cls->getClassKey()->getPackageName()); - newPackage = true; - } - - AgentClassKey key(cls->getClassKey()->getClassName(), cls->getClassKey()->getHash()); - iter->second.objectClasses[key] = cls; - - // Indicate this new schema if connected. - - if (attachComplete) { - - if (newPackage) { - sendPackageIndicationLH(iter->first); - } - sendClassIndicationLH(CLASS_OBJECT, iter->first, key); - } -} - -void AgentImpl::registerClass(SchemaEventClass* cls) -{ - Mutex::ScopedLock _lock(lock); - bool newPackage = false; - - map<string, ClassMaps>::iterator iter = packages.find(cls->getClassKey()->getPackageName()); - if (iter == packages.end()) { - packages[cls->getClassKey()->getPackageName()] = ClassMaps(); - iter = packages.find(cls->getClassKey()->getPackageName()); - newPackage = true; - } - - AgentClassKey key(cls->getClassKey()->getClassName(), cls->getClassKey()->getHash()); - iter->second.eventClasses[key] = cls; - - // Indicate this new schema if connected. - - if (attachComplete) { - - if (newPackage) { - sendPackageIndicationLH(iter->first); - } - sendClassIndicationLH(CLASS_EVENT, iter->first, key); - } -} - -const ObjectId* AgentImpl::addObject(Object&, uint64_t) -{ - Mutex::ScopedLock _lock(lock); - return 0; -} - -const ObjectId* AgentImpl::allocObjectId(uint64_t persistId) -{ - Mutex::ScopedLock _lock(lock); - uint16_t sequence = persistId ? 0 : bootSequence; - uint64_t objectNum = persistId ? persistId : nextObjectId++; - - ObjectId* oid = ObjectIdImpl::factory(&attachment, 0, sequence, objectNum); - return oid; -} - -const ObjectId* AgentImpl::allocObjectId(uint32_t persistIdLo, uint32_t persistIdHi) -{ - return allocObjectId(((uint64_t) persistIdHi) << 32 | (uint64_t) persistIdLo); -} - -void AgentImpl::raiseEvent(Event& event) -{ - Mutex::ScopedLock _lock(lock); - Buffer buffer(outputBuffer, MA_BUFFER_SIZE); - Protocol::encodeHeader(buffer, Protocol::OP_EVENT_INDICATION); - - event.impl->encodeSchemaKey(buffer); - buffer.putLongLong(uint64_t(Duration(EPOCH, now()))); - event.impl->encode(buffer); - string key(event.impl->getRoutingKey(assignedBrokerBank, assignedAgentBank)); - - sendBufferLH(buffer, QMF_EXCHANGE, key); - QPID_LOG(trace, "SENT EventIndication"); -} - -AgentEventImpl::Ptr AgentImpl::eventDeclareQueue(const string& name) -{ - AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::DECLARE_QUEUE)); - event->name = name; - - return event; -} - -AgentEventImpl::Ptr AgentImpl::eventBind(const string& exchange, const string& queue, - const string& key) -{ - AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::BIND)); - event->name = queue; - event->exchange = exchange; - event->bindingKey = key; - - return event; -} - -AgentEventImpl::Ptr AgentImpl::eventSetupComplete() -{ - AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::SETUP_COMPLETE)); - return event; -} - -AgentEventImpl::Ptr AgentImpl::eventQuery(uint32_t num, const string& userId, const string& package, - const string& cls, boost::shared_ptr<ObjectId> oid) -{ - AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::GET_QUERY)); - event->sequence = num; - event->authUserId = userId; - if (oid.get()) - event->query.reset(new Query(oid.get())); - else - event->query.reset(new Query(cls.c_str(), package.c_str())); - return event; -} - -AgentEventImpl::Ptr AgentImpl::eventMethod(uint32_t num, const string& userId, const string& method, - boost::shared_ptr<ObjectId> oid, boost::shared_ptr<Value> argMap, - const SchemaObjectClass* objectClass) -{ - AgentEventImpl::Ptr event(new AgentEventImpl(AgentEvent::METHOD_CALL)); - event->sequence = num; - event->authUserId = userId; - event->name = method; - event->objectId = oid; - event->arguments = argMap; - event->objectClass = objectClass; - return event; -} - -void AgentImpl::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 = "amq.direct"; - message->replyKey = queueName; - - xmtQueue.push_back(message); -} - -void AgentImpl::sendPackageIndicationLH(const string& packageName) -{ - Buffer buffer(outputBuffer, MA_BUFFER_SIZE); - Protocol::encodeHeader(buffer, Protocol::OP_PACKAGE_INDICATION); - buffer.putShortString(packageName); - sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY); - QPID_LOG(trace, "SENT PackageIndication: package_name=" << packageName); -} - -void AgentImpl::sendClassIndicationLH(ClassKind kind, const string& packageName, const AgentClassKey& key) -{ - Buffer buffer(outputBuffer, MA_BUFFER_SIZE); - Protocol::encodeHeader(buffer, Protocol::OP_CLASS_INDICATION); - buffer.putOctet((int) kind); - buffer.putShortString(packageName); - buffer.putShortString(key.name); - buffer.putBin128(const_cast<uint8_t*>(key.hash)); // const_cast needed for older Qpid libraries - sendBufferLH(buffer, QMF_EXCHANGE, BROKER_KEY); - QPID_LOG(trace, "SENT ClassIndication: package_name=" << packageName << " class_name=" << key.name); -} - -void AgentImpl::sendCommandCompleteLH(const string& exchange, const string& replyToKey, - uint32_t sequence, uint32_t code, const string& text) -{ - Buffer buffer(outputBuffer, MA_BUFFER_SIZE); - Protocol::encodeHeader(buffer, Protocol::OP_COMMAND_COMPLETE, sequence); - buffer.putLong(code); - buffer.putShortString(text); - sendBufferLH(buffer, exchange, replyToKey); - QPID_LOG(trace, "SENT CommandComplete: seq=" << sequence << " code=" << code << " text=" << text); -} - -void AgentImpl::sendMethodErrorLH(uint32_t sequence, const string& key, uint32_t code, const string& text) -{ - Buffer buffer(outputBuffer, MA_BUFFER_SIZE); - Protocol::encodeHeader(buffer, Protocol::OP_METHOD_RESPONSE, sequence); - buffer.putLong(code); - - string fulltext; - switch (code) { - case MERR_UNKNOWN_PACKAGE: fulltext = "Unknown Package"; break; - case MERR_UNKNOWN_CLASS: fulltext = "Unknown Class"; break; - case MERR_UNKNOWN_METHOD: fulltext = "Unknown Method"; break; - case MERR_INTERNAL_ERROR: fulltext = "Internal Error"; break; - default: fulltext = "Unspecified Error"; break; - } - - if (!text.empty()) { - fulltext += " ("; - fulltext += text; - fulltext += ")"; - } - - buffer.putMediumString(fulltext); - sendBufferLH(buffer, DIR_EXCHANGE, key); - QPID_LOG(trace, "SENT MethodResponse: errorCode=" << code << " text=" << fulltext); -} - -void AgentImpl::handleAttachResponse(Buffer& inBuffer) -{ - Mutex::ScopedLock _lock(lock); - - assignedBrokerBank = inBuffer.getLong(); - assignedAgentBank = inBuffer.getLong(); - - QPID_LOG(trace, "RCVD AttachResponse: broker=" << assignedBrokerBank << " agent=" << assignedAgentBank); - - if ((assignedBrokerBank != requestedBrokerBank) || - (assignedAgentBank != requestedAgentBank)) { - if (requestedAgentBank == 0) { - QPID_LOG(notice, "Initial object-id bank assigned: " << assignedBrokerBank << "." << - assignedAgentBank); - } else { - QPID_LOG(warning, "Collision in object-id! New bank assigned: " << assignedBrokerBank << - "." << assignedAgentBank); - } - //storeData(); // TODO - requestedBrokerBank = assignedBrokerBank; - requestedAgentBank = assignedAgentBank; - } - - attachment.setBanks(assignedBrokerBank, assignedAgentBank); - - // Bind to qpid.management to receive commands - stringstream key; - key << "agent." << assignedBrokerBank << "." << assignedAgentBank; - eventQueue.push_back(eventBind(QMF_EXCHANGE, queueName, key.str())); - - // Send package indications for all local packages - for (map<string, ClassMaps>::iterator pIter = packages.begin(); - pIter != packages.end(); - pIter++) { - sendPackageIndicationLH(pIter->first); - - // Send class indications for all local classes - ClassMaps cMap = pIter->second; - for (ObjectClassMap::iterator cIter = cMap.objectClasses.begin(); - cIter != cMap.objectClasses.end(); cIter++) - sendClassIndicationLH(CLASS_OBJECT, pIter->first, cIter->first); - for (EventClassMap::iterator cIter = cMap.eventClasses.begin(); - cIter != cMap.eventClasses.end(); cIter++) - sendClassIndicationLH(CLASS_EVENT, pIter->first, cIter->first); - } - - attachComplete = true; -} - -void AgentImpl::handlePackageRequest(Buffer&) -{ - Mutex::ScopedLock _lock(lock); -} - -void AgentImpl::handleClassQuery(Buffer&) -{ - Mutex::ScopedLock _lock(lock); -} - -void AgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, - const string& replyExchange, const string& replyKey) -{ - Mutex::ScopedLock _lock(lock); - string rExchange(replyExchange); - string rKey(replyKey); - string packageName; - inBuffer.getShortString(packageName); - AgentClassKey key(inBuffer); - - if (rExchange.empty()) - rExchange = QMF_EXCHANGE; - if (rKey.empty()) - rKey = BROKER_KEY; - - QPID_LOG(trace, "RCVD SchemaRequest: package=" << packageName << " class=" << key.name); - - map<string, ClassMaps>::iterator pIter = packages.find(packageName); - if (pIter == packages.end()) { - sendCommandCompleteLH(rExchange, rKey, sequence, 1, "package not found"); - return; - } - - ClassMaps cMap = pIter->second; - ObjectClassMap::iterator ocIter = cMap.objectClasses.find(key); - if (ocIter != cMap.objectClasses.end()) { - SchemaObjectClass* oImpl = ocIter->second; - Buffer buffer(outputBuffer, MA_BUFFER_SIZE); - Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence); - oImpl->impl->encode(buffer); - sendBufferLH(buffer, rExchange, rKey); - QPID_LOG(trace, "SENT SchemaResponse: (object) package=" << packageName << " class=" << key.name); - return; - } - - EventClassMap::iterator ecIter = cMap.eventClasses.find(key); - if (ecIter != cMap.eventClasses.end()) { - SchemaEventClass* eImpl = ecIter->second; - Buffer buffer(outputBuffer, MA_BUFFER_SIZE); - Protocol::encodeHeader(buffer, Protocol::OP_SCHEMA_RESPONSE, sequence); - eImpl->impl->encode(buffer); - sendBufferLH(buffer, rExchange, rKey); - QPID_LOG(trace, "SENT SchemaResponse: (event) package=" << packageName << " class=" << key.name); - return; - } - - sendCommandCompleteLH(rExchange, rKey, sequence, 1, "class not found"); -} - -void AgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, const string& replyTo, const string& userId) -{ - Mutex::ScopedLock _lock(lock); - FieldTable ft; - FieldTable::ValuePtr value; - map<string, ClassMaps>::const_iterator pIter = packages.end(); - string pname; - string cname; - string oidRepr; - boost::shared_ptr<ObjectId> oid; - - ft.decode(inBuffer); - - QPID_LOG(trace, "RCVD GetQuery: seq=" << sequence << " map=" << ft); - - value = ft.get("_package"); - if (value.get() && value->convertsTo<string>()) { - pname = value->get<string>(); - pIter = packages.find(pname); - if (pIter == packages.end()) { - sendCommandCompleteLH(DIR_EXCHANGE, replyTo, sequence); - return; - } - } - - value = ft.get("_class"); - if (value.get() && value->convertsTo<string>()) { - cname = value->get<string>(); - // TODO - check for validity of class (in package or any package) - if (pIter == packages.end()) { - } else { - - } - } - - value = ft.get("_objectid"); - if (value.get() && value->convertsTo<string>()) { - oidRepr = value->get<string>(); - oid.reset(new ObjectId()); - oid->impl->fromString(oidRepr); - } - - AgentQueryContext::Ptr context(new AgentQueryContext); - uint32_t contextNum = nextContextNum++; - context->sequence = sequence; - context->exchange = DIR_EXCHANGE; - context->key = replyTo; - contextMap[contextNum] = context; - - eventQueue.push_back(eventQuery(contextNum, userId, pname, cname, oid)); -} - -void AgentImpl::handleMethodRequest(Buffer& buffer, uint32_t sequence, const string& replyTo, const string& userId) -{ - Mutex::ScopedLock _lock(lock); - string pname; - string method; - boost::shared_ptr<ObjectId> oid(ObjectIdImpl::factory(buffer)); - buffer.getShortString(pname); - AgentClassKey classKey(buffer); - buffer.getShortString(method); - - QPID_LOG(trace, "RCVD MethodRequest seq=" << sequence << " method=" << method); - - map<string, ClassMaps>::const_iterator pIter = packages.find(pname); - if (pIter == packages.end()) { - sendMethodErrorLH(sequence, replyTo, MERR_UNKNOWN_PACKAGE, pname); - return; - } - - ObjectClassMap::const_iterator cIter = pIter->second.objectClasses.find(classKey); - if (cIter == pIter->second.objectClasses.end()) { - sendMethodErrorLH(sequence, replyTo, MERR_UNKNOWN_CLASS, classKey.repr()); - return; - } - - 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->impl->methods.end()) { - sendMethodErrorLH(sequence, replyTo, MERR_UNKNOWN_METHOD, method); - return; - } - - const SchemaMethod* schemaMethod = *mIter; - boost::shared_ptr<Value> argMap(new Value(TYPE_MAP)); - 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 = ValueImpl::factory(schemaArg->getType()); - argMap->insert(schemaArg->getName(), value); - } - - AgentQueryContext::Ptr context(new AgentQueryContext); - uint32_t contextNum = nextContextNum++; - context->sequence = sequence; - context->exchange = DIR_EXCHANGE; - context->key = replyTo; - context->schemaMethod = schemaMethod; - contextMap[contextNum] = context; - - eventQueue.push_back(eventMethod(contextNum, userId, method, oid, argMap, schema)); -} - -void AgentImpl::handleConsoleAddedIndication() -{ - Mutex::ScopedLock _lock(lock); -} - -//================================================================== -// Wrappers -//================================================================== - -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 deleted file mode 100644 index 5fc71979fd..0000000000 --- a/qpid/cpp/src/qmf/engine/BrokerProxyImpl.cpp +++ /dev/null @@ -1,827 +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/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::Address 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); - bool sent = false; - if (agent != 0) { - if (sendGetRequestLH(queryContext, query, agent)) - sent = true; - } 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++) { - if (sendGetRequestLH(queryContext, query, iter->second.get())) - sent = true; - } - } - - if (!sent) { - queryContext->reserve(); - queryContext->release(); - } -} - -bool BrokerProxyImpl::sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxy* agent) -{ - if (query.impl->singleAgent()) { - if (query.impl->agentBank() != agent->getAgentBank()) - return false; - } - 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()); - return true; -} - -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(); -} - -string BrokerProxyImpl::encodedSizeMethodArguments(const SchemaMethod* schema, const Value* argmap, uint32_t& size) -{ - 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(); - size += argVal->impl->encodedSize(); - } else { - Value defaultValue(arg->getType()); - size += defaultValue.impl->encodedSize(); - } - } - } - - 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; - char* buf(outputBuffer); - uint32_t bufLen(1024); - bool allocated(false); - - string argErrorString = encodedSizeMethodArguments(method, args, bufLen); - if (!argErrorString.empty()) { - MethodResponsePtr argError(MethodResponseImpl::factory(1, argErrorString)); - eventQueue.push_back(eventMethodResponse(userContext, argError)); - return; - } - - if (bufLen > MA_BUFFER_SIZE) { - buf = (char*) malloc(bufLen); - allocated = true; - } - - Buffer outBuffer(buf, bufLen); - 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); - - encodeMethodArguments(method, args, outBuffer); - key << "agent.1." << oid->impl->getAgentBank(); - sendBufferLH(outBuffer, QMF_EXCHANGE, key.str()); - QPID_LOG(trace, "SENT MethodRequest seq=" << sequence << " method=" << methodName << " key=" << key.str()); - - if (allocated) - free(buf); - - 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) -{ - auto_ptr<SchemaClassKey> classKey(SchemaClassKeyImpl::factory(inBuffer)); - const SchemaEventClass *schema = console.impl->getEventClass(classKey.get()); - if (schema == 0) { - QPID_LOG(trace, "No Schema Found for EventIndication. seq=" << seq << " key=" << classKey->impl->str()); - return; - } - - EventPtr eptr(EventImpl::factory(schema, inBuffer)); - - console.impl->eventEventReceived(eptr); - QPID_LOG(trace, "RCVD EventIndication seq=" << seq << " key=" << classKey->impl->str()); -} - -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(const AgentProxy& from) : impl(new AgentProxyImpl(*(from.impl))) {} -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 deleted file mode 100644 index 0542b67dbb..0000000000 --- a/qpid/cpp/src/qmf/engine/BrokerProxyImpl.h +++ /dev/null @@ -1,241 +0,0 @@ -#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/EventImpl.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); - bool sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxy* agent); - std::string encodeMethodArguments(const SchemaMethod* schema, const Value* args, qpid::framing::Buffer& buffer); - std::string encodedSizeMethodArguments(const SchemaMethod* schema, const Value* args, uint32_t& size); - 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/engine/ConnectionSettingsImpl.cpp b/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp deleted file mode 100644 index 22a65f28ca..0000000000 --- a/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.cpp +++ /dev/null @@ -1,278 +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/engine/ConnectionSettingsImpl.h" -#include "qmf/engine/Typecode.h" - -using namespace std; -using namespace qmf::engine; -using namespace qpid; - -const string attrProtocol("protocol"); -const string attrHost("host"); -const string attrPort("port"); -const string attrVirtualhost("virtualhost"); -const string attrUsername("username"); -const string attrPassword("password"); -const string attrMechanism("mechanism"); -const string attrLocale("locale"); -const string attrHeartbeat("heartbeat"); -const string attrMaxChannels("maxChannels"); -const string attrMaxFrameSize("maxFrameSize"); -const string attrBounds("bounds"); -const string attrTcpNoDelay("tcpNoDelay"); -const string attrService("service"); -const string attrMinSsf("minSsf"); -const string attrMaxSsf("maxSsf"); -const string attrRetryDelayMin("retryDelayMin"); -const string attrRetryDelayMax("retryDelayMax"); -const string attrRetryDelayFactor("retryDelayFactor"); -const string attrSendUserId("sendUserId"); - -ConnectionSettingsImpl::ConnectionSettingsImpl() : - retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2), sendUserId(true) -{ -} - -ConnectionSettingsImpl::ConnectionSettingsImpl(const string& /*url*/) : - retryDelayMin(1), retryDelayMax(64), retryDelayFactor(2), sendUserId(true) -{ - // TODO: Parse the URL -} - -bool ConnectionSettingsImpl::setAttr(const string& key, const Value& value) -{ - if (key == attrProtocol) clientSettings.protocol = value.asString(); - else if (key == attrHost) clientSettings.host = value.asString(); - else if (key == attrPort) clientSettings.port = value.asUint(); - else if (key == attrVirtualhost) clientSettings.virtualhost = value.asString(); - else if (key == attrUsername) clientSettings.username = value.asString(); - else if (key == attrPassword) clientSettings.password = value.asString(); - else if (key == attrMechanism) clientSettings.mechanism = value.asString(); - else if (key == attrLocale) clientSettings.locale = value.asString(); - else if (key == attrHeartbeat) clientSettings.heartbeat = value.asUint(); - else if (key == attrMaxChannels) clientSettings.maxChannels = value.asUint(); - else if (key == attrMaxFrameSize) clientSettings.maxFrameSize = value.asUint(); - else if (key == attrBounds) clientSettings.bounds = value.asUint(); - else if (key == attrTcpNoDelay) clientSettings.tcpNoDelay = value.asBool(); - else if (key == attrService) clientSettings.service = value.asString(); - else if (key == attrMinSsf) clientSettings.minSsf = value.asUint(); - else if (key == attrMaxSsf) clientSettings.maxSsf = value.asUint(); - - else if (key == attrRetryDelayMin) retryDelayMin = value.asUint(); - else if (key == attrRetryDelayMax) retryDelayMax = value.asUint(); - else if (key == attrRetryDelayFactor) retryDelayFactor = value.asUint(); - else if (key == attrSendUserId) sendUserId = value.asBool(); - else - return false; - return true; -} - -Value ConnectionSettingsImpl::getAttr(const string& key) const -{ - Value strval(TYPE_LSTR); - Value intval(TYPE_UINT32); - Value boolval(TYPE_BOOL); - - if (key == attrProtocol) { - strval.setString(clientSettings.protocol.c_str()); - return strval; - } - - if (key == attrHost) { - strval.setString(clientSettings.host.c_str()); - return strval; - } - - if (key == attrPort) { - intval.setUint(clientSettings.port); - return intval; - } - - if (key == attrVirtualhost) { - strval.setString(clientSettings.virtualhost.c_str()); - return strval; - } - - if (key == attrUsername) { - strval.setString(clientSettings.username.c_str()); - return strval; - } - - if (key == attrPassword) { - strval.setString(clientSettings.password.c_str()); - return strval; - } - - if (key == attrMechanism) { - strval.setString(clientSettings.mechanism.c_str()); - return strval; - } - - if (key == attrLocale) { - strval.setString(clientSettings.locale.c_str()); - return strval; - } - - if (key == attrHeartbeat) { - intval.setUint(clientSettings.heartbeat); - return intval; - } - - if (key == attrMaxChannels) { - intval.setUint(clientSettings.maxChannels); - return intval; - } - - if (key == attrMaxFrameSize) { - intval.setUint(clientSettings.maxFrameSize); - return intval; - } - - if (key == attrBounds) { - intval.setUint(clientSettings.bounds); - return intval; - } - - if (key == attrTcpNoDelay) { - boolval.setBool(clientSettings.tcpNoDelay); - return boolval; - } - - if (key == attrService) { - strval.setString(clientSettings.service.c_str()); - return strval; - } - - if (key == attrMinSsf) { - intval.setUint(clientSettings.minSsf); - return intval; - } - - if (key == attrMaxSsf) { - intval.setUint(clientSettings.maxSsf); - return intval; - } - - if (key == attrRetryDelayMin) { - intval.setUint(retryDelayMin); - return intval; - } - - if (key == attrRetryDelayMax) { - intval.setUint(retryDelayMax); - return intval; - } - - if (key == attrRetryDelayFactor) { - intval.setUint(retryDelayFactor); - return intval; - } - - if (key == attrSendUserId) { - boolval.setBool(sendUserId); - return boolval; - } - - return strval; -} - -const string& ConnectionSettingsImpl::getAttrString() const -{ - // TODO: build and return attribute string - return attrString; -} - -void ConnectionSettingsImpl::transportTcp(uint16_t port) -{ - clientSettings.protocol = "tcp"; - clientSettings.port = port; -} - -void ConnectionSettingsImpl::transportSsl(uint16_t port) -{ - clientSettings.protocol = "ssl"; - clientSettings.port = port; -} - -void ConnectionSettingsImpl::transportRdma(uint16_t port) -{ - clientSettings.protocol = "rdma"; - clientSettings.port = port; -} - -void ConnectionSettingsImpl::authAnonymous(const string& username) -{ - clientSettings.mechanism = "ANONYMOUS"; - clientSettings.username = username; -} - -void ConnectionSettingsImpl::authPlain(const string& username, const string& password) -{ - clientSettings.mechanism = "PLAIN"; - clientSettings.username = username; - clientSettings.password = password; -} - -void ConnectionSettingsImpl::authGssapi(const string& serviceName, uint32_t minSsf, uint32_t maxSsf) -{ - clientSettings.mechanism = "GSSAPI"; - clientSettings.service = serviceName; - clientSettings.minSsf = minSsf; - clientSettings.maxSsf = maxSsf; -} - -void ConnectionSettingsImpl::setRetry(int delayMin, int delayMax, int delayFactor) -{ - retryDelayMin = delayMin; - retryDelayMax = delayMax; - retryDelayFactor = delayFactor; -} - -const client::ConnectionSettings& ConnectionSettingsImpl::getClientSettings() const -{ - return clientSettings; -} - -void ConnectionSettingsImpl::getRetrySettings(int* min, int* max, int* factor) const -{ - *min = retryDelayMin; - *max = retryDelayMax; - *factor = retryDelayFactor; -} - -//================================================================== -// Wrappers -//================================================================== - -ConnectionSettings::ConnectionSettings(const ConnectionSettings& from) { impl = new ConnectionSettingsImpl(*from.impl); } -ConnectionSettings::ConnectionSettings() { impl = new ConnectionSettingsImpl(); } -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/engine/ConnectionSettingsImpl.h b/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.h deleted file mode 100644 index 98bf87868b..0000000000 --- a/qpid/cpp/src/qmf/engine/ConnectionSettingsImpl.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _QmfEngineConnectionSettingsImpl_ -#define _QmfEngineConnectionSettingsImpl_ - -/* - * 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/ConnectionSettings.h" -#include "qmf/engine/Value.h" -#include "qpid/client/ConnectionSettings.h" -#include <string> -#include <map> - -namespace qmf { -namespace engine { - - class ConnectionSettingsImpl { - qpid::client::ConnectionSettings clientSettings; - mutable std::string attrString; - int retryDelayMin; - int retryDelayMax; - int retryDelayFactor; - bool sendUserId; - - public: - ConnectionSettingsImpl(); - ConnectionSettingsImpl(const std::string& url); - ~ConnectionSettingsImpl() {} - 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); - void transportSsl(uint16_t port); - void transportRdma(uint16_t port); - void authAnonymous(const std::string& username); - void authPlain(const std::string& username, const std::string& password); - void authGssapi(const std::string& serviceName, uint32_t minSsf, uint32_t maxSsf); - void setRetry(int delayMin, int delayMax, int delayFactor); - - const qpid::client::ConnectionSettings& getClientSettings() const; - void getRetrySettings(int* delayMin, int* delayMax, int* delayFactor) const; - bool getSendUserId() const { return sendUserId; } - }; - -} -} - -#endif diff --git a/qpid/cpp/src/qmf/engine/ConsoleImpl.cpp b/qpid/cpp/src/qmf/engine/ConsoleImpl.cpp deleted file mode 100644 index 4a5da31bdc..0000000000 --- a/qpid/cpp/src/qmf/engine/ConsoleImpl.cpp +++ /dev/null @@ -1,458 +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/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.get(); - 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::bindEvent(const SchemaClassKey* classKey) -{ - bindEvent(classKey->getPackageName(), classKey->getClassName()); -} - -void ConsoleImpl::bindEvent(const char* packageName, const char* eventName) -{ - if (!settings.userBindings) throw qpid::Exception("Console not configured for userBindings."); - if (settings.rcvEvents) throw qpid::Exception("Console already configured to receive all events."); - - stringstream key; - key << "console.event.*.*." << packageName; - if (eventName && *eventName) { - key << "." << eventName << ".#"; - } else { - key << ".#"; - } - - 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); -} - - -void ConsoleImpl::eventEventReceived(EventPtr event) -{ - ConsoleEventImpl::Ptr console_event(new ConsoleEventImpl(ConsoleEvent::EVENT_RECEIVED)); - console_event->event = event; - Mutex::ScopedLock _lock(lock); - eventQueue.push_back(console_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::bindEvent(const SchemaClassKey *key) { impl->bindEvent(key); } -void Console::bindEvent(const char* packageName, const char* eventName) { impl->bindEvent(packageName, eventName); } - -//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 deleted file mode 100644 index 0c27fdabcd..0000000000 --- a/qpid/cpp/src/qmf/engine/ConsoleImpl.h +++ /dev/null @@ -1,148 +0,0 @@ -#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; - boost::shared_ptr<Event> event; - uint64_t timestamp; - bool hasProps; - bool hasStats; - - ConsoleEventImpl(ConsoleEvent::EventKind k) : - kind(k), classKey(0), context(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 bindEvent(const SchemaClassKey* key); - void bindEvent(const char* packageName, const char* eventName); - - /* - 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); - void eventEventReceived(boost::shared_ptr<Event> event); - }; -} -} - -#endif - diff --git a/qpid/cpp/src/qmf/engine/EventImpl.cpp b/qpid/cpp/src/qmf/engine/EventImpl.cpp deleted file mode 100644 index 4b034e8e83..0000000000 --- a/qpid/cpp/src/qmf/engine/EventImpl.cpp +++ /dev/null @@ -1,120 +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/engine/EventImpl.h> -#include <qmf/engine/ValueImpl.h> - -#include <sstream> - -using namespace std; -using namespace qmf::engine; -using qpid::framing::Buffer; - -EventImpl::EventImpl(const SchemaEventClass* type) : eventClass(type), timestamp(0), severity(0) -{ - int argCount = eventClass->getArgumentCount(); - int idx; - - for (idx = 0; idx < argCount; idx++) { - const SchemaArgument* arg = eventClass->getArgument(idx); - arguments[arg->getName()] = ValuePtr(new Value(arg->getType())); - } -} - - -EventImpl::EventImpl(const SchemaEventClass* type, Buffer& buffer) : - eventClass(type), timestamp(0), severity(0) -{ - int argCount = eventClass->getArgumentCount(); - int idx; - - timestamp = buffer.getLongLong(); - severity = buffer.getOctet(); - - for (idx = 0; idx < argCount; idx++) - { - const SchemaArgument *arg = eventClass->getArgument(idx); - Value* pval = ValueImpl::factory(arg->getType(), buffer); - arguments[arg->getName()] = ValuePtr(pval); - } -} - - -Event* EventImpl::factory(const SchemaEventClass* type, Buffer& buffer) -{ - EventImpl* impl(new EventImpl(type, buffer)); - return new Event(impl); -} - - -Value* EventImpl::getValue(const char* key) const -{ - map<string, ValuePtr>::const_iterator iter; - - iter = arguments.find(key); - if (iter != arguments.end()) - return iter->second.get(); - - return 0; -} - - -void EventImpl::encodeSchemaKey(Buffer& buffer) const -{ - buffer.putShortString(eventClass->getClassKey()->getPackageName()); - buffer.putShortString(eventClass->getClassKey()->getClassName()); - buffer.putBin128(const_cast<uint8_t*>(eventClass->getClassKey()->getHash())); -} - - -void EventImpl::encode(Buffer& buffer) const -{ - buffer.putOctet((uint8_t) eventClass->getSeverity()); - - int argCount = eventClass->getArgumentCount(); - for (int idx = 0; idx < argCount; idx++) { - const SchemaArgument* arg = eventClass->getArgument(idx); - ValuePtr value = arguments[arg->getName()]; - value->impl->encode(buffer); - } -} - - -string EventImpl::getRoutingKey(uint32_t brokerBank, uint32_t agentBank) const -{ - stringstream key; - - key << "console.event." << brokerBank << "." << agentBank << "." << - eventClass->getClassKey()->getPackageName() << "." << - eventClass->getClassKey()->getClassName(); - return key.str(); -} - - -//================================================================== -// Wrappers -//================================================================== - -Event::Event(const SchemaEventClass* type) : impl(new EventImpl(type)) {} -Event::Event(EventImpl* i) : impl(i) {} -Event::Event(const Event& from) : impl(new EventImpl(*(from.impl))) {} -Event::~Event() { delete impl; } -const SchemaEventClass* Event::getClass() const { return impl->getClass(); } -Value* Event::getValue(const char* key) const { return impl->getValue(key); } - diff --git a/qpid/cpp/src/qmf/engine/EventImpl.h b/qpid/cpp/src/qmf/engine/EventImpl.h deleted file mode 100644 index 4046e71ef9..0000000000 --- a/qpid/cpp/src/qmf/engine/EventImpl.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _QmfEngineEventImpl_ -#define _QmfEngineEventImpl_ - -/* - * 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/Event.h> -#include <qmf/engine/Schema.h> -#include <qpid/framing/Buffer.h> -#include <boost/shared_ptr.hpp> -#include <map> - -namespace qmf { -namespace engine { - - typedef boost::shared_ptr<Event> EventPtr; - - struct EventImpl { - typedef boost::shared_ptr<Value> ValuePtr; - const SchemaEventClass* eventClass; - uint64_t timestamp; - uint8_t severity; - mutable std::map<std::string, ValuePtr> arguments; - - EventImpl(const SchemaEventClass* type); - EventImpl(const SchemaEventClass* type, qpid::framing::Buffer& buffer); - static Event* factory(const SchemaEventClass* type, qpid::framing::Buffer& buffer); - - const SchemaEventClass* getClass() const { return eventClass; } - Value* getValue(const char* key) const; - - void encodeSchemaKey(qpid::framing::Buffer& buffer) const; - void encode(qpid::framing::Buffer& buffer) const; - std::string getRoutingKey(uint32_t brokerBank, uint32_t agentBank) const; - }; - -} -} - -#endif - diff --git a/qpid/cpp/src/qmf/engine/ObjectIdImpl.cpp b/qpid/cpp/src/qmf/engine/ObjectIdImpl.cpp deleted file mode 100644 index 9216f7bac0..0000000000 --- a/qpid/cpp/src/qmf/engine/ObjectIdImpl.cpp +++ /dev/null @@ -1,210 +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/engine/ObjectIdImpl.h" -#include <stdlib.h> -#include <sstream> - -using namespace std; -using namespace qmf::engine; -using qpid::framing::Buffer; - -void AgentAttachment::setBanks(uint32_t broker, uint32_t agent) -{ - first = - ((uint64_t) (broker & 0x000fffff)) << 28 | - ((uint64_t) (agent & 0x0fffffff)); -} - -ObjectIdImpl::ObjectIdImpl(Buffer& buffer) : agent(0) -{ - decode(buffer); -} - -ObjectIdImpl::ObjectIdImpl(AgentAttachment* a, uint8_t flags, uint16_t seq, uint64_t object) : agent(a) -{ - first = - ((uint64_t) (flags & 0x0f)) << 60 | - ((uint64_t) (seq & 0x0fff)) << 48; - 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(); - second = buffer.getLongLong(); -} - -void ObjectIdImpl::encode(Buffer& buffer) const -{ - if (agent == 0) - buffer.putLongLong(first); - else - buffer.putLongLong(first | agent->first); - buffer.putLongLong(second); -} - -void ObjectIdImpl::fromString(const std::string& repr) -{ -#define FIELDS 5 -#if defined (_WIN32) && !defined (atoll) -# define atoll(X) _atoi64(X) -#endif - - std::string copy(repr.c_str()); - char* cText; - char* field[FIELDS]; - bool atFieldStart = true; - int idx = 0; - - cText = const_cast<char*>(copy.c_str()); - for (char* cursor = cText; *cursor; cursor++) { - if (atFieldStart) { - if (idx >= FIELDS) - return; // TODO error - field[idx++] = cursor; - atFieldStart = false; - } else { - if (*cursor == '-') { - *cursor = '\0'; - atFieldStart = true; - } - } - } - - if (idx != FIELDS) - return; // TODO error - - first = (atoll(field[0]) << 60) + - (atoll(field[1]) << 48) + - (atoll(field[2]) << 28) + - atoll(field[3]); - second = atoll(field[4]); - agent = 0; -} - -const string& ObjectIdImpl::asString() const -{ - stringstream val; - - val << (int) getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" << - getAgentBank() << "-" << getObjectNum(); - repr = val.str(); - return repr; -} - -#define ACTUAL_FIRST (agent == 0 ? first : first | agent->first) -#define ACTUAL_OTHER (other.agent == 0 ? other.first : other.first | other.agent->first) - -uint8_t ObjectIdImpl::getFlags() const -{ - return (ACTUAL_FIRST & 0xF000000000000000LL) >> 60; -} - -uint16_t ObjectIdImpl::getSequence() const -{ - return (ACTUAL_FIRST & 0x0FFF000000000000LL) >> 48; -} - -uint32_t ObjectIdImpl::getBrokerBank() const -{ - return (ACTUAL_FIRST & 0x0000FFFFF0000000LL) >> 28; -} - -uint32_t ObjectIdImpl::getAgentBank() const -{ - return ACTUAL_FIRST & 0x000000000FFFFFFFLL; -} - -uint64_t ObjectIdImpl::getObjectNum() const -{ - return second; -} - -uint32_t ObjectIdImpl::getObjectNumHi() const -{ - return (uint32_t) (second >> 32); -} - -uint32_t ObjectIdImpl::getObjectNumLo() const -{ - return (uint32_t) (second & 0x00000000FFFFFFFFLL); -} - -bool ObjectIdImpl::operator==(const ObjectIdImpl& other) const -{ - return ACTUAL_FIRST == ACTUAL_OTHER && second == other.second; -} - -bool ObjectIdImpl::operator<(const ObjectIdImpl& other) const -{ - return (ACTUAL_FIRST < ACTUAL_OTHER) || ((ACTUAL_FIRST == ACTUAL_OTHER) && (second < other.second)); -} - -bool ObjectIdImpl::operator>(const ObjectIdImpl& other) const -{ - return (ACTUAL_FIRST > ACTUAL_OTHER) || ((ACTUAL_FIRST == ACTUAL_OTHER) && (second > other.second)); -} - - -//================================================================== -// Wrappers -//================================================================== - -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::operator=(const ObjectId& other) { - ObjectIdImpl *old; - if (this != &other) { - old = impl; - impl = new ObjectIdImpl(*(other.impl)); - if (old) - delete old; - } - return *this; -} - diff --git a/qpid/cpp/src/qmf/engine/ObjectIdImpl.h b/qpid/cpp/src/qmf/engine/ObjectIdImpl.h deleted file mode 100644 index d70c8efff4..0000000000 --- a/qpid/cpp/src/qmf/engine/ObjectIdImpl.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _QmfEngineObjectIdImpl_ -#define _QmfEngineObjectIdImpl_ - -/* - * 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/ObjectId.h> -#include <qpid/framing/Buffer.h> - -namespace qmf { -namespace engine { - - struct AgentAttachment { - uint64_t first; - - AgentAttachment() : first(0) {} - void setBanks(uint32_t broker, uint32_t bank); - uint64_t getFirst() const { return first; } - }; - - struct ObjectIdImpl { - AgentAttachment* agent; - uint64_t first; - uint64_t second; - mutable std::string repr; - - 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); - const std::string& asString() const; - uint8_t getFlags() const; - uint16_t getSequence() const; - uint32_t getBrokerBank() const; - uint32_t getAgentBank() const; - uint64_t getObjectNum() const; - uint32_t getObjectNumHi() const; - uint32_t getObjectNumLo() const; - bool isDurable() const { return getSequence() == 0; } - void setValue(uint64_t f, uint64_t s) { first = f; second = s; agent = 0; } - - bool operator==(const ObjectIdImpl& other) const; - bool operator<(const ObjectIdImpl& other) const; - bool operator>(const ObjectIdImpl& other) const; - }; -} -} - -#endif - diff --git a/qpid/cpp/src/qmf/engine/ObjectImpl.cpp b/qpid/cpp/src/qmf/engine/ObjectImpl.cpp deleted file mode 100644 index 45925cb804..0000000000 --- a/qpid/cpp/src/qmf/engine/ObjectImpl.cpp +++ /dev/null @@ -1,232 +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/engine/ObjectImpl.h" -#include "qmf/engine/ValueImpl.h" -#include "qmf/engine/BrokerProxyImpl.h" -#include <qpid/sys/Time.h> - -using namespace std; -using namespace qmf::engine; -using namespace qpid::sys; -using qpid::framing::Buffer; - -ObjectImpl::ObjectImpl(const SchemaObjectClass* type) : objectClass(type), broker(0), createTime(uint64_t(Duration(EPOCH, now()))), destroyTime(0), lastUpdatedTime(createTime) -{ - int propCount = objectClass->getPropertyCount(); - int statCount = objectClass->getStatisticCount(); - int idx; - - for (idx = 0; idx < propCount; idx++) { - const SchemaProperty* prop = objectClass->getProperty(idx); - properties[prop->getName()] = ValuePtr(new Value(prop->getType())); - } - - for (idx = 0; idx < statCount; idx++) { - const SchemaStatistic* stat = objectClass->getStatistic(idx); - statistics[stat->getName()] = ValuePtr(new Value(stat->getType())); - } -} - -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; - - if (managed) { - lastUpdatedTime = buffer.getLongLong(); - createTime = buffer.getLongLong(); - destroyTime = buffer.getLongLong(); - objectId.reset(ObjectIdImpl::factory(buffer)); - } - - if (prop) { - int propCount = objectClass->getPropertyCount(); - set<string> excludes; - parsePresenceMasks(buffer, excludes); - for (idx = 0; idx < propCount; idx++) { - const SchemaProperty* prop = objectClass->getProperty(idx); - if (excludes.count(prop->getName()) != 0) { - properties[prop->getName()] = ValuePtr(new Value(prop->getType())); - } else { - Value* pval = ValueImpl::factory(prop->getType(), buffer); - properties[prop->getName()] = ValuePtr(pval); - } - } - } - - if (stat) { - int statCount = objectClass->getStatisticCount(); - for (idx = 0; idx < statCount; idx++) { - const SchemaStatistic* stat = objectClass->getStatistic(idx); - 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() -{ -} - -void ObjectImpl::destroy() -{ - destroyTime = uint64_t(Duration(EPOCH, now())); - // TODO - flag deletion -} - -Value* ObjectImpl::getValue(const string& key) const -{ - map<string, ValuePtr>::const_iterator iter; - - iter = properties.find(key); - if (iter != properties.end()) - return iter->second.get(); - - iter = statistics.find(key); - if (iter != statistics.end()) - return iter->second.get(); - - 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(); - excludeList.clear(); - uint8_t bit = 0; - uint8_t mask = 0; - - for (int idx = 0; idx < propCount; idx++) { - const SchemaProperty* prop = objectClass->getProperty(idx); - if (prop->isOptional()) { - if (bit == 0) { - mask = buffer.getOctet(); - bit = 1; - } - if ((mask & bit) == 0) - excludeList.insert(string(prop->getName())); - if (bit == 0x80) - bit = 0; - else - bit = bit << 1; - } - } -} - -void ObjectImpl::encodeSchemaKey(qpid::framing::Buffer& buffer) const -{ - buffer.putShortString(objectClass->getClassKey()->getPackageName()); - buffer.putShortString(objectClass->getClassKey()->getClassName()); - buffer.putBin128(const_cast<uint8_t*>(objectClass->getClassKey()->getHash())); -} - -void ObjectImpl::encodeManagedObjectData(qpid::framing::Buffer& buffer) const -{ - buffer.putLongLong(lastUpdatedTime); - buffer.putLongLong(createTime); - buffer.putLongLong(destroyTime); - objectId->impl->encode(buffer); -} - -void ObjectImpl::encodeProperties(qpid::framing::Buffer& buffer) const -{ - int propCount = objectClass->getPropertyCount(); - uint8_t bit = 0; - uint8_t mask = 0; - ValuePtr value; - - for (int idx = 0; idx < propCount; idx++) { - const SchemaProperty* prop = objectClass->getProperty(idx); - if (prop->isOptional()) { - value = properties[prop->getName()]; - if (bit == 0) - bit = 1; - if (!value->isNull()) - mask |= bit; - if (bit == 0x80) { - buffer.putOctet(mask); - bit = 0; - mask = 0; - } else - bit = bit << 1; - } - } - if (bit != 0) { - buffer.putOctet(mask); - } - - for (int idx = 0; idx < propCount; idx++) { - const SchemaProperty* prop = objectClass->getProperty(idx); - value = properties[prop->getName()]; - if (!prop->isOptional() || !value->isNull()) { - value->impl->encode(buffer); - } - } -} - -void ObjectImpl::encodeStatistics(qpid::framing::Buffer& buffer) const -{ - int statCount = objectClass->getStatisticCount(); - for (int idx = 0; idx < statCount; idx++) { - const SchemaStatistic* stat = objectClass->getStatistic(idx); - ValuePtr value = statistics[stat->getName()]; - value->impl->encode(buffer); - } -} - -//================================================================== -// Wrappers -//================================================================== - -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; } -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(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/engine/ObjectImpl.h b/qpid/cpp/src/qmf/engine/ObjectImpl.h deleted file mode 100644 index 6f25867004..0000000000 --- a/qpid/cpp/src/qmf/engine/ObjectImpl.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef _QmfEngineObjectImpl_ -#define _QmfEngineObjectImpl_ - -/* - * 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/Object.h> -#include <qmf/engine/ObjectIdImpl.h> -#include <map> -#include <set> -#include <string> -#include <qpid/framing/Buffer.h> -#include <boost/shared_ptr.hpp> -#include <qpid/sys/Mutex.h> - -namespace qmf { -namespace engine { - - class BrokerProxyImpl; - - typedef boost::shared_ptr<Object> ObjectPtr; - - struct ObjectImpl { - typedef boost::shared_ptr<Value> ValuePtr; - const SchemaObjectClass* objectClass; - 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(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(); } - void setObjectId(ObjectId* oid) { objectId.reset(new ObjectId(*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; - void encodeManagedObjectData(qpid::framing::Buffer& buffer) const; - void encodeProperties(qpid::framing::Buffer& buffer) const; - void encodeStatistics(qpid::framing::Buffer& buffer) const; - }; -} -} - -#endif - diff --git a/qpid/cpp/src/qmf/engine/Protocol.cpp b/qpid/cpp/src/qmf/engine/Protocol.cpp deleted file mode 100644 index 9e5f490604..0000000000 --- a/qpid/cpp/src/qmf/engine/Protocol.cpp +++ /dev/null @@ -1,52 +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/engine/Protocol.h" -#include "qpid/framing/Buffer.h" - -using namespace std; -using namespace qmf::engine; -using namespace qpid::framing; - - -bool Protocol::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq) -{ - if (buf.available() < 8) - return false; - - uint8_t h1 = buf.getOctet(); - uint8_t h2 = buf.getOctet(); - uint8_t h3 = buf.getOctet(); - - *opcode = buf.getOctet(); - *seq = buf.getLong(); - - return h1 == 'A' && h2 == 'M' && h3 == '2'; -} - -void Protocol::encodeHeader(qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq) -{ - buf.putOctet('A'); - buf.putOctet('M'); - buf.putOctet('2'); - buf.putOctet(opcode); - buf.putLong (seq); -} - - diff --git a/qpid/cpp/src/qmf/engine/Protocol.h b/qpid/cpp/src/qmf/engine/Protocol.h deleted file mode 100644 index 1cdfa60c84..0000000000 --- a/qpid/cpp/src/qmf/engine/Protocol.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _QmfEngineProtocol_ -#define _QmfEngineProtocol_ - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include <qpid/sys/IntegerTypes.h> - -namespace qpid { - namespace framing { - class Buffer; - } -} - -namespace qmf { -namespace engine { - - class Protocol { - public: - static bool checkHeader(qpid::framing::Buffer& buf, uint8_t *opcode, uint32_t *seq); - static void encodeHeader(qpid::framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0); - - const static uint8_t OP_ATTACH_REQUEST = 'A'; - const static uint8_t OP_ATTACH_RESPONSE = 'a'; - - const static uint8_t OP_BROKER_REQUEST = 'B'; - const static uint8_t OP_BROKER_RESPONSE = 'b'; - - const static uint8_t OP_CONSOLE_ADDED_INDICATION = 'x'; - const static uint8_t OP_COMMAND_COMPLETE = 'z'; - const static uint8_t OP_HEARTBEAT_INDICATION = 'h'; - - const static uint8_t OP_PACKAGE_REQUEST = 'P'; - const static uint8_t OP_PACKAGE_INDICATION = 'p'; - const static uint8_t OP_CLASS_QUERY = 'Q'; - const static uint8_t OP_CLASS_INDICATION = 'q'; - const static uint8_t OP_SCHEMA_REQUEST = 'S'; - const static uint8_t OP_SCHEMA_RESPONSE = 's'; - - const static uint8_t OP_METHOD_REQUEST = 'M'; - const static uint8_t OP_METHOD_RESPONSE = 'm'; - const static uint8_t OP_GET_QUERY = 'G'; - const static uint8_t OP_OBJECT_INDICATION = 'g'; - const static uint8_t OP_PROPERTY_INDICATION = 'c'; - const static uint8_t OP_STATISTIC_INDICATION = 'i'; - const static uint8_t OP_EVENT_INDICATION = 'e'; - }; - -} -} - -#endif - diff --git a/qpid/cpp/src/qmf/engine/QueryImpl.cpp b/qpid/cpp/src/qmf/engine/QueryImpl.cpp deleted file mode 100644 index 6f2beeee87..0000000000 --- a/qpid/cpp/src/qmf/engine/QueryImpl.cpp +++ /dev/null @@ -1,103 +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/engine/QueryImpl.h" -#include "qmf/engine/ObjectIdImpl.h" -#include "qpid/framing/Buffer.h" -#include "qpid/framing/FieldTable.h" - -using namespace std; -using namespace qmf::engine; -using namespace qpid::framing; - -bool QueryElementImpl::evaluate(const Object* /*object*/) const -{ - // TODO: Implement this - return false; -} - -bool QueryExpressionImpl::evaluate(const Object* /*object*/) const -{ - // TODO: Implement this - return false; -} - -QueryImpl::QueryImpl(Buffer& buffer) -{ - FieldTable ft; - ft.decode(buffer); - // TODO -} - -Query* QueryImpl::factory(Buffer& buffer) -{ - QueryImpl* impl(new QueryImpl(buffer)); - return new Query(impl); -} - -void QueryImpl::encode(Buffer& buffer) const -{ - FieldTable ft; - - if (oid.get() != 0) { - ft.setString("_objectid", oid->impl->asString()); - } else { - if (!packageName.empty()) - ft.setString("_package", packageName); - ft.setString("_class", className); - } - - ft.encode(buffer); -} - - -//================================================================== -// Wrappers -//================================================================== - -QueryElement::QueryElement(const char* attrName, const Value* value, ValueOper oper) : impl(new QueryElementImpl(attrName, value, oper)) {} -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); } -void Query::setOrderBy(const char* attrName, bool decreasing) { impl->setOrderBy(attrName, decreasing); } -const char* Query::getPackage() const { return impl->getPackage().c_str(); } -const char* Query::getClass() const { return impl->getClass().c_str(); } -const ObjectId* Query::getObjectId() const { return impl->getObjectId(); } -bool Query::haveSelect() const { return impl->haveSelect(); } -bool Query::haveLimit() const { return impl->haveLimit(); } -bool Query::haveOrderBy() const { return impl->haveOrderBy(); } -const QueryOperand* Query::getSelect() const { return impl->getSelect(); } -uint32_t Query::getLimit() const { return impl->getLimit(); } -const char* Query::getOrderBy() const { return impl->getOrderBy().c_str(); } -bool Query::getDecreasing() const { return impl->getDecreasing(); } - diff --git a/qpid/cpp/src/qmf/engine/QueryImpl.h b/qpid/cpp/src/qmf/engine/QueryImpl.h deleted file mode 100644 index 8ebe0d932f..0000000000 --- a/qpid/cpp/src/qmf/engine/QueryImpl.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef _QmfEngineQueryImpl_ -#define _QmfEngineQueryImpl_ - -/* - * 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/Query.h" -#include "qmf/engine/Schema.h" -#include <string> -#include <boost/shared_ptr.hpp> - -namespace qpid { - namespace framing { - class Buffer; - } -} - -namespace qmf { -namespace engine { - - struct QueryElementImpl { - QueryElementImpl(const std::string& a, const Value* v, ValueOper o) : attrName(a), value(v), oper(o) {} - ~QueryElementImpl() {} - bool evaluate(const Object* object) const; - - std::string attrName; - const Value* value; - ValueOper oper; - }; - - struct QueryExpressionImpl { - QueryExpressionImpl(ExprOper o, const QueryOperand* operand1, const QueryOperand* operand2) : oper(o), left(operand1), right(operand2) {} - ~QueryExpressionImpl() {} - bool evaluate(const Object* object) const; - - ExprOper oper; - const QueryOperand* left; - const QueryOperand* right; - }; - - struct QueryImpl { - // 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; } - void setOrderBy(const std::string& attrName, bool decreasing) { - orderBy = attrName; orderDecreasing = decreasing; - } - - const std::string& getPackage() const { return packageName; } - const std::string& getClass() const { return className; } - const ObjectId* getObjectId() const { return oid.get(); } - - bool haveSelect() const { return select != 0; } - bool haveLimit() const { return resultLimit > 0; } - bool haveOrderBy() const { return !orderBy.empty(); } - const QueryOperand* getSelect() const { return select; } - uint32_t getLimit() const { return resultLimit; } - const std::string& getOrderBy() const { return orderBy; } - bool getDecreasing() const { return orderDecreasing; } - - void encode(qpid::framing::Buffer& buffer) const; - bool singleAgent() const { return oid.get() != 0; } - uint32_t agentBank() const { return singleAgent() ? oid->getAgentBank() : 0; } - - std::string packageName; - std::string className; - boost::shared_ptr<ObjectId> oid; - const QueryOperand* select; - uint32_t resultLimit; - std::string orderBy; - bool orderDecreasing; - }; -} -} - -#endif diff --git a/qpid/cpp/src/qmf/engine/ResilientConnection.cpp b/qpid/cpp/src/qmf/engine/ResilientConnection.cpp deleted file mode 100644 index 851193ccc1..0000000000 --- a/qpid/cpp/src/qmf/engine/ResilientConnection.cpp +++ /dev/null @@ -1,512 +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/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> -#include <qpid/client/SubscriptionManager.h> -#include <qpid/client/Message.h> -#include <qpid/sys/Thread.h> -#include <qpid/sys/Runnable.h> -#include <qpid/sys/Mutex.h> -#include <qpid/sys/Condition.h> -#include <qpid/sys/Time.h> -#include <qpid/log/Statement.h> -#include <qpid/RefCounted.h> -#include <boost/bind.hpp> -#include <string> -#include <deque> -#include <vector> -#include <set> -#include <boost/intrusive_ptr.hpp> -#include <boost/noncopyable.hpp> -#include <unistd.h> -#include <fcntl.h> - -using namespace std; -using namespace qmf::engine; -using namespace qpid; -using qpid::sys::Mutex; - -namespace qmf { -namespace engine { - struct ResilientConnectionEventImpl { - ResilientConnectionEvent::EventKind kind; - void* sessionContext; - string errorText; - MessageImpl message; - - ResilientConnectionEventImpl(ResilientConnectionEvent::EventKind k, - const MessageImpl& m = MessageImpl()) : - kind(k), sessionContext(0), message(m) {} - ResilientConnectionEvent copy(); - }; - - struct RCSession : public client::MessageListener, public qpid::sys::Runnable, public qpid::RefCounted { - typedef boost::intrusive_ptr<RCSession> Ptr; - ResilientConnectionImpl& connImpl; - string name; - 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); - ~RCSession(); - void received(client::Message& msg); - void run(); - void stop(); - }; - - class ResilientConnectionImpl : public qpid::sys::Runnable, public boost::noncopyable { - public: - ResilientConnectionImpl(const ConnectionSettings& settings); - ~ResilientConnectionImpl(); - - bool isConnected() const; - bool getEvent(ResilientConnectionEvent& event); - void popEvent(); - bool createSession(const char* name, void* sessionContext, SessionHandle& handle); - void destroySession(SessionHandle handle); - 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); - void unbind(SessionHandle handle, char* exchange, char* queue, char* key); - void setNotifyFd(int fd); - void notify(); - - void run(); - void failure(); - void sessionClosed(RCSession* sess); - - void EnqueueEvent(ResilientConnectionEvent::EventKind kind, - void* sessionContext = 0, - const MessageImpl& message = MessageImpl(), - const string& errorText = ""); - - private: - int notifyFd; - bool connected; - bool shutdown; - string lastError; - const ConnectionSettings settings; - client::Connection connection; - mutable qpid::sys::Mutex lock; - int delayMin; - int delayMax; - int delayFactor; - qpid::sys::Condition cond; - deque<ResilientConnectionEventImpl> eventQueue; - set<RCSession::Ptr> sessions; - qpid::sys::Thread connThread; - }; -} -} - -ResilientConnectionEvent ResilientConnectionEventImpl::copy() -{ - ResilientConnectionEvent item; - - ::memset(&item, 0, sizeof(ResilientConnectionEvent)); - item.kind = kind; - item.sessionContext = sessionContext; - item.message = message.copy(); - item.errorText = const_cast<char*>(errorText.c_str()); - - 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(); - thread.join(); - session.close(); - delete subscriptions; -} - -void RCSession::run() -{ - try { - subscriptions->run(); - } catch (exception& /*e*/) { - connImpl.sessionClosed(this); - } -} - -void RCSession::stop() -{ - subscriptions->stop(); -} - -void RCSession::received(client::Message& msg) -{ - MessageImpl qmsg; - qmsg.body = msg.getData(); - - 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 (mp.hasUserId()) { - qmsg.userId = mp.getUserId(); - } - - connImpl.EnqueueEvent(ResilientConnectionEvent::RECV, userContext, qmsg); -} - -ResilientConnectionImpl::ResilientConnectionImpl(const ConnectionSettings& _settings) : - notifyFd(-1), connected(false), shutdown(false), settings(_settings), delayMin(1), connThread(*this) -{ - connection.registerFailureCallback(boost::bind(&ResilientConnectionImpl::failure, this)); - settings.impl->getRetrySettings(&delayMin, &delayMax, &delayFactor); -} - -ResilientConnectionImpl::~ResilientConnectionImpl() -{ - shutdown = true; - connected = false; - cond.notify(); - connThread.join(); - connection.close(); -} - -bool ResilientConnectionImpl::isConnected() const -{ - Mutex::ScopedLock _lock(lock); - return connected; -} - -bool ResilientConnectionImpl::getEvent(ResilientConnectionEvent& event) -{ - Mutex::ScopedLock _lock(lock); - if (eventQueue.empty()) - return false; - event = eventQueue.front().copy(); - return true; -} - -void ResilientConnectionImpl::popEvent() -{ - Mutex::ScopedLock _lock(lock); - if (!eventQueue.empty()) - eventQueue.pop_front(); -} - -bool ResilientConnectionImpl::createSession(const char* name, void* sessionContext, - SessionHandle& handle) -{ - Mutex::ScopedLock _lock(lock); - if (!connected) - return false; - - RCSession::Ptr sess = RCSession::Ptr(new RCSession(*this, name, connection, sessionContext)); - - handle.impl = (void*) sess.get(); - sessions.insert(sess); - - return true; -} - -void ResilientConnectionImpl::destroySession(SessionHandle handle) -{ - Mutex::ScopedLock _lock(lock); - RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl); - set<RCSession::Ptr>::iterator iter = sessions.find(sess); - if (iter != sessions.end()) { - for (vector<string>::iterator dIter = sess->dests.begin(); dIter != sess->dests.end(); dIter++) - sess->subscriptions->cancel(dIter->c_str()); - sess->subscriptions->stop(); - sess->subscriptions->wait(); - - sessions.erase(iter); - return; - } -} - -void ResilientConnectionImpl::sendMessage(SessionHandle handle, qmf::engine::Message& message) -{ - Mutex::ScopedLock _lock(lock); - RCSession::Ptr sess = RCSession::Ptr((RCSession*) handle.impl); - set<RCSession::Ptr>::iterator iter = sessions.find(sess); - qpid::client::Message msg; - string data(message.body, message.length); - 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 { - sess->session.messageTransfer(client::arg::content=msg, client::arg::destination=message.destination); - } catch(exception& e) { - QPID_LOG(error, "Session Exception during message-transfer: " << e.what()); - sessions.erase(iter); - EnqueueEvent(ResilientConnectionEvent::SESSION_CLOSED, (*iter)->userContext); - } -} - -void ResilientConnectionImpl::declareQueue(SessionHandle handle, char* queue) -{ - Mutex::ScopedLock _lock(lock); - RCSession* sess = (RCSession*) handle.impl; - - sess->session.queueDeclare(client::arg::queue=queue, client::arg::autoDelete=true, client::arg::exclusive=true); - sess->subscriptions->setAcceptMode(client::ACCEPT_MODE_NONE); - sess->subscriptions->setAcquireMode(client::ACQUIRE_MODE_PRE_ACQUIRED); - sess->subscriptions->subscribe(*sess, queue, queue); - sess->subscriptions->setFlowControl(queue, client::FlowControl::unlimited()); - sess->dests.push_back(string(queue)); -} - -void ResilientConnectionImpl::deleteQueue(SessionHandle handle, char* queue) -{ - Mutex::ScopedLock _lock(lock); - RCSession* sess = (RCSession*) handle.impl; - - sess->session.queueDelete(client::arg::queue=queue); - for (vector<string>::iterator iter = sess->dests.begin(); - iter != sess->dests.end(); iter++) - if (*iter == queue) { - sess->subscriptions->cancel(queue); - sess->dests.erase(iter); - break; - } -} - -void ResilientConnectionImpl::bind(SessionHandle handle, - char* exchange, char* queue, char* key) -{ - Mutex::ScopedLock _lock(lock); - RCSession* sess = (RCSession*) handle.impl; - - sess->session.exchangeBind(client::arg::exchange=exchange, client::arg::queue=queue, client::arg::bindingKey=key); -} - -void ResilientConnectionImpl::unbind(SessionHandle handle, - char* exchange, char* queue, char* key) -{ - Mutex::ScopedLock _lock(lock); - RCSession* sess = (RCSession*) handle.impl; - - sess->session.exchangeUnbind(client::arg::exchange=exchange, client::arg::queue=queue, client::arg::bindingKey=key); -} - -void ResilientConnectionImpl::notify() -{ - if (notifyFd != -1) - { - if (::write(notifyFd, ".", 1)) {} - } -} - - -void ResilientConnectionImpl::setNotifyFd(int fd) -{ - notifyFd = fd; - if (notifyFd > 0) { - int original = fcntl(notifyFd, F_GETFL); - fcntl(notifyFd, F_SETFL, O_NONBLOCK | original); - } -} - -void ResilientConnectionImpl::run() -{ - int delay(delayMin); - - while (true) { - try { - QPID_LOG(trace, "Trying to open connection..."); - connection.open(settings.impl->getClientSettings()); - { - Mutex::ScopedLock _lock(lock); - connected = true; - EnqueueEvent(ResilientConnectionEvent::CONNECTED); - - while (connected) - cond.wait(lock); - delay = delayMin; - - while (!sessions.empty()) { - set<RCSession::Ptr>::iterator iter = sessions.begin(); - RCSession::Ptr sess = *iter; - sessions.erase(iter); - EnqueueEvent(ResilientConnectionEvent::SESSION_CLOSED, sess->userContext); - Mutex::ScopedUnlock _u(lock); - sess->stop(); - - // Nullify the intrusive pointer within the scoped unlock, otherwise, - // the reference is held until overwritted above (under lock) which causes - // the session destructor to be called with the lock held. - sess = 0; - } - - EnqueueEvent(ResilientConnectionEvent::DISCONNECTED); - - if (shutdown) - return; - } - connection.close(); - } catch (exception &e) { - QPID_LOG(debug, "connection.open exception: " << e.what()); - Mutex::ScopedLock _lock(lock); - lastError = e.what(); - if (delay < delayMax) - delay *= delayFactor; - } - - ::qpid::sys::sleep(delay); - } -} - -void ResilientConnectionImpl::failure() -{ - Mutex::ScopedLock _lock(lock); - - connected = false; - lastError = "Closed by Peer"; - cond.notify(); -} - -void ResilientConnectionImpl::sessionClosed(RCSession*) -{ - Mutex::ScopedLock _lock(lock); - connected = false; - lastError = "Closed due to Session failure"; - cond.notify(); -} - -void ResilientConnectionImpl::EnqueueEvent(ResilientConnectionEvent::EventKind kind, - void* sessionContext, - const MessageImpl& message, - const string& errorText) -{ - { - Mutex::ScopedLock _lock(lock); - ResilientConnectionEventImpl event(kind, message); - - event.sessionContext = sessionContext; - event.errorText = errorText; - - eventQueue.push_back(event); - } - - if (notifyFd != -1) - { - if (::write(notifyFd, ".", 1)) {} - } -} - - -//================================================================== -// Wrappers -//================================================================== - -ResilientConnection::ResilientConnection(const ConnectionSettings& settings) -{ - impl = new ResilientConnectionImpl(settings); -} - -ResilientConnection::~ResilientConnection() -{ - delete impl; -} - -bool ResilientConnection::isConnected() const -{ - return impl->isConnected(); -} - -bool ResilientConnection::getEvent(ResilientConnectionEvent& event) -{ - return impl->getEvent(event); -} - -void ResilientConnection::popEvent() -{ - impl->popEvent(); -} - -bool ResilientConnection::createSession(const char* name, void* sessionContext, SessionHandle& handle) -{ - return impl->createSession(name, sessionContext, handle); -} - -void ResilientConnection::destroySession(SessionHandle handle) -{ - impl->destroySession(handle); -} - -void ResilientConnection::sendMessage(SessionHandle handle, qmf::engine::Message& message) -{ - impl->sendMessage(handle, message); -} - -void ResilientConnection::declareQueue(SessionHandle handle, char* queue) -{ - impl->declareQueue(handle, queue); -} - -void ResilientConnection::deleteQueue(SessionHandle handle, char* queue) -{ - impl->deleteQueue(handle, queue); -} - -void ResilientConnection::bind(SessionHandle handle, char* exchange, char* queue, char* key) -{ - impl->bind(handle, exchange, queue, key); -} - -void ResilientConnection::unbind(SessionHandle handle, char* exchange, char* queue, char* key) -{ - impl->unbind(handle, exchange, queue, key); -} - -void ResilientConnection::setNotifyFd(int fd) -{ - impl->setNotifyFd(fd); -} - -void ResilientConnection::notify() -{ - impl->notify(); -} - diff --git a/qpid/cpp/src/qmf/engine/SchemaImpl.cpp b/qpid/cpp/src/qmf/engine/SchemaImpl.cpp deleted file mode 100644 index 9d363d3012..0000000000 --- a/qpid/cpp/src/qmf/engine/SchemaImpl.cpp +++ /dev/null @@ -1,610 +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/engine/SchemaImpl.h" -#include <qpid/framing/Buffer.h> -#include <qpid/framing/FieldTable.h> -#include <qpid/framing/Uuid.h> -#include <string.h> -#include <string> -#include <vector> -#include <sstream> - -using namespace std; -using namespace qmf::engine; -using qpid::framing::Buffer; -using qpid::framing::FieldTable; -using qpid::framing::Uuid; - -SchemaHash::SchemaHash() -{ - for (int idx = 0; idx < 16; idx++) - hash.b[idx] = 0x5A; -} - -void SchemaHash::encode(Buffer& buffer) const -{ - buffer.putBin128(hash.b); -} - -void SchemaHash::decode(Buffer& buffer) -{ - buffer.getBin128(hash.b); -} - -void SchemaHash::update(uint8_t data) -{ - update((char*) &data, 1); -} - -void SchemaHash::update(const char* data, uint32_t len) -{ - uint64_t* first = &hash.q[0]; - uint64_t* second = &hash.q[1]; - for (uint32_t idx = 0; idx < len; idx++) { - *first = *first ^ (uint64_t) data[idx]; - *second = *second << 1; - *second |= ((*first & 0x8000000000000000LL) >> 63); - *first = *first << 1; - *first = *first ^ *second; - } -} - -bool SchemaHash::operator==(const SchemaHash& other) const -{ - return ::memcmp(&hash, &other.hash, 16) == 0; -} - -bool SchemaHash::operator<(const SchemaHash& other) const -{ - return ::memcmp(&hash, &other.hash, 16) < 0; -} - -bool SchemaHash::operator>(const SchemaHash& other) const -{ - return ::memcmp(&hash, &other.hash, 16) > 0; -} - -SchemaArgumentImpl::SchemaArgumentImpl(Buffer& buffer) -{ - FieldTable map; - map.decode(buffer); - - name = map.getAsString("name"); - typecode = (Typecode) map.getAsInt("type"); - unit = map.getAsString("unit"); - description = map.getAsString("desc"); - - dir = DIR_IN; - string dstr(map.getAsString("dir")); - if (dstr == "O") - dir = DIR_OUT; - else if (dstr == "IO") - 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; - - map.setString("name", name); - map.setInt("type", (int) typecode); - if (dir == DIR_IN) - map.setString("dir", "I"); - else if (dir == DIR_OUT) - map.setString("dir", "O"); - else - map.setString("dir", "IO"); - if (!unit.empty()) - map.setString("unit", unit); - if (!description.empty()) - map.setString("desc", description); - - map.encode(buffer); -} - -void SchemaArgumentImpl::updateHash(SchemaHash& hash) const -{ - hash.update(name); - hash.update(typecode); - hash.update(dir); - hash.update(unit); - hash.update(description); -} - -SchemaMethodImpl::SchemaMethodImpl(Buffer& buffer) -{ - FieldTable map; - int argCount; - - map.decode(buffer); - name = map.getAsString("name"); - argCount = map.getAsInt("argCount"); - description = map.getAsString("desc"); - - for (int idx = 0; idx < argCount; idx++) { - 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; - - map.setString("name", name); - map.setInt("argCount", arguments.size()); - if (!description.empty()) - map.setString("desc", description); - map.encode(buffer); - - for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); - iter != arguments.end(); iter++) - (*iter)->impl->encode(buffer); -} - -void SchemaMethodImpl::addArgument(const SchemaArgument* argument) -{ - arguments.push_back(argument); -} - -const SchemaArgument* SchemaMethodImpl::getArgument(int idx) const -{ - int count = 0; - for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); - iter != arguments.end(); iter++, count++) - if (idx == count) - return (*iter); - return 0; -} - -void SchemaMethodImpl::updateHash(SchemaHash& hash) const -{ - hash.update(name); - hash.update(description); - for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); - iter != arguments.end(); iter++) - (*iter)->impl->updateHash(hash); -} - -SchemaPropertyImpl::SchemaPropertyImpl(Buffer& buffer) -{ - FieldTable map; - map.decode(buffer); - - name = map.getAsString("name"); - typecode = (Typecode) map.getAsInt("type"); - access = (Access) map.getAsInt("access"); - index = map.getAsInt("index") != 0; - optional = map.getAsInt("optional") != 0; - unit = map.getAsString("unit"); - 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; - - map.setString("name", name); - map.setInt("type", (int) typecode); - map.setInt("access", (int) access); - map.setInt("index", index ? 1 : 0); - map.setInt("optional", optional ? 1 : 0); - if (!unit.empty()) - map.setString("unit", unit); - if (!description.empty()) - map.setString("desc", description); - - map.encode(buffer); -} - -void SchemaPropertyImpl::updateHash(SchemaHash& hash) const -{ - hash.update(name); - hash.update(typecode); - hash.update(access); - hash.update(index); - hash.update(optional); - hash.update(unit); - hash.update(description); -} - -SchemaStatisticImpl::SchemaStatisticImpl(Buffer& buffer) -{ - FieldTable map; - map.decode(buffer); - - name = map.getAsString("name"); - typecode = (Typecode) map.getAsInt("type"); - unit = map.getAsString("unit"); - 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; - - map.setString("name", name); - map.setInt("type", (int) typecode); - if (!unit.empty()) - map.setString("unit", unit); - if (!description.empty()) - map.setString("desc", description); - - map.encode(buffer); -} - -void SchemaStatisticImpl::updateHash(SchemaHash& hash) const -{ - hash.update(name); - hash.update(typecode); - hash.update(unit); - hash.update(description); -} - -SchemaClassKeyImpl::SchemaClassKeyImpl(const string& p, const string& n, const SchemaHash& h) : package(p), name(n), hash(h) {} - -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 -{ - buffer.putShortString(package); - buffer.putShortString(name); - hash.encode(buffer); -} - -bool SchemaClassKeyImpl::operator==(const SchemaClassKeyImpl& other) const -{ - return package == other.package && - name == other.name && - hash == other.hash; -} - -bool SchemaClassKeyImpl::operator<(const SchemaClassKeyImpl& other) const -{ - if (package < other.package) return true; - if (package > other.package) return false; - if (name < other.name) return true; - if (name > other.name) return false; - return hash < other.hash; -} - -const string& SchemaClassKeyImpl::str() const -{ - Uuid printableHash(hash.get()); - stringstream str; - str << package << ":" << name << "(" << printableHash << ")"; - repr = str.str(); - return repr; -} - -SchemaObjectClassImpl::SchemaObjectClassImpl(Buffer& buffer) : hasHash(true), classKey(SchemaClassKeyImpl::factory(package, name, hash)) -{ - buffer.getShortString(package); - buffer.getShortString(name); - hash.decode(buffer); - - uint16_t propCount = buffer.getShort(); - uint16_t statCount = buffer.getShort(); - uint16_t methodCount = buffer.getShort(); - - for (uint16_t idx = 0; idx < propCount; idx++) { - const SchemaProperty* property = SchemaPropertyImpl::factory(buffer); - addProperty(property); - } - - for (uint16_t idx = 0; idx < statCount; idx++) { - const SchemaStatistic* statistic = SchemaStatisticImpl::factory(buffer); - addStatistic(statistic); - } - - for (uint16_t idx = 0; idx < methodCount; idx++) { - 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); - buffer.putShortString(package); - buffer.putShortString(name); - hash.encode(buffer); - //buffer.putOctet(0); // No parent class - buffer.putShort((uint16_t) properties.size()); - buffer.putShort((uint16_t) statistics.size()); - buffer.putShort((uint16_t) methods.size()); - - for (vector<const SchemaProperty*>::const_iterator iter = properties.begin(); - iter != properties.end(); iter++) - (*iter)->impl->encode(buffer); - for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin(); - iter != statistics.end(); iter++) - (*iter)->impl->encode(buffer); - for (vector<const SchemaMethod*>::const_iterator iter = methods.begin(); - iter != methods.end(); iter++) - (*iter)->impl->encode(buffer); -} - -const SchemaClassKey* SchemaObjectClassImpl::getClassKey() const -{ - if (!hasHash) { - hasHash = true; - hash.update(package); - hash.update(name); - for (vector<const SchemaProperty*>::const_iterator iter = properties.begin(); - iter != properties.end(); iter++) - (*iter)->impl->updateHash(hash); - for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin(); - iter != statistics.end(); iter++) - (*iter)->impl->updateHash(hash); - for (vector<const SchemaMethod*>::const_iterator iter = methods.begin(); - iter != methods.end(); iter++) - (*iter)->impl->updateHash(hash); - } - - return classKey.get(); -} - -void SchemaObjectClassImpl::addProperty(const SchemaProperty* property) -{ - properties.push_back(property); -} - -void SchemaObjectClassImpl::addStatistic(const SchemaStatistic* statistic) -{ - statistics.push_back(statistic); -} - -void SchemaObjectClassImpl::addMethod(const SchemaMethod* method) -{ - methods.push_back(method); -} - -const SchemaProperty* SchemaObjectClassImpl::getProperty(int idx) const -{ - int count = 0; - for (vector<const SchemaProperty*>::const_iterator iter = properties.begin(); - iter != properties.end(); iter++, count++) - if (idx == count) - return *iter; - return 0; -} - -const SchemaStatistic* SchemaObjectClassImpl::getStatistic(int idx) const -{ - int count = 0; - for (vector<const SchemaStatistic*>::const_iterator iter = statistics.begin(); - iter != statistics.end(); iter++, count++) - if (idx == count) - return *iter; - return 0; -} - -const SchemaMethod* SchemaObjectClassImpl::getMethod(int idx) const -{ - int count = 0; - for (vector<const SchemaMethod*>::const_iterator iter = methods.begin(); - iter != methods.end(); iter++, count++) - if (idx == count) - return *iter; - return 0; -} - -SchemaEventClassImpl::SchemaEventClassImpl(Buffer& buffer) : hasHash(true), classKey(SchemaClassKeyImpl::factory(package, name, hash)) -{ - buffer.getShortString(package); - buffer.getShortString(name); - hash.decode(buffer); - - uint16_t argCount = buffer.getShort(); - - for (uint16_t idx = 0; idx < argCount; idx++) { - 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); - buffer.putShortString(package); - buffer.putShortString(name); - hash.encode(buffer); - buffer.putShort((uint16_t) arguments.size()); - - for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); - iter != arguments.end(); iter++) - (*iter)->impl->encode(buffer); -} - -const SchemaClassKey* SchemaEventClassImpl::getClassKey() const -{ - if (!hasHash) { - hasHash = true; - hash.update(package); - hash.update(name); - for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); - iter != arguments.end(); iter++) - (*iter)->impl->updateHash(hash); - } - return classKey.get(); -} - -void SchemaEventClassImpl::addArgument(const SchemaArgument* argument) -{ - arguments.push_back(argument); -} - -const SchemaArgument* SchemaEventClassImpl::getArgument(int idx) const -{ - int count = 0; - for (vector<const SchemaArgument*>::const_iterator iter = arguments.begin(); - iter != arguments.end(); iter++, count++) - if (idx == count) - return (*iter); - return 0; -} - - -//================================================================== -// Wrappers -//================================================================== - -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); } -void SchemaArgument::setDesc(const char* desc) { impl->setDesc(desc); } -const char* SchemaArgument::getName() const { return impl->getName().c_str(); } -Typecode SchemaArgument::getType() const { return impl->getType(); } -Direction SchemaArgument::getDirection() const { return impl->getDirection(); } -const char* SchemaArgument::getUnit() const { return impl->getUnit().c_str(); } -const char* SchemaArgument::getDesc() const { return impl->getDesc().c_str(); } - -SchemaMethod::SchemaMethod(const char* name) : impl(new SchemaMethodImpl(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::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(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); } -void SchemaProperty::setOptional(bool val) { impl->setOptional(val); } -void SchemaProperty::setUnit(const char* val) { impl->setUnit(val); } -void SchemaProperty::setDesc(const char* desc) { impl->setDesc(desc); } -const char* SchemaProperty::getName() const { return impl->getName().c_str(); } -Typecode SchemaProperty::getType() const { return impl->getType(); } -Access SchemaProperty::getAccess() const { return impl->getAccess(); } -bool SchemaProperty::isIndex() const { return impl->isIndex(); } -bool SchemaProperty::isOptional() const { return impl->isOptional(); } -const char* SchemaProperty::getUnit() const { return impl->getUnit().c_str(); } -const char* SchemaProperty::getDesc() const { return impl->getDesc().c_str(); } - -SchemaStatistic::SchemaStatistic(const char* name, Typecode typecode) : impl(new SchemaStatisticImpl(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); } -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(); } -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); } -const SchemaClassKey* SchemaObjectClass::getClassKey() const { return impl->getClassKey(); } -int SchemaObjectClass::getPropertyCount() const { return impl->getPropertyCount(); } -int SchemaObjectClass::getStatisticCount() const { return impl->getStatisticCount(); } -int SchemaObjectClass::getMethodCount() const { return impl->getMethodCount(); } -const SchemaProperty* SchemaObjectClass::getProperty(int idx) const { return impl->getProperty(idx); } -const SchemaStatistic* SchemaObjectClass::getStatistic(int idx) const { return impl->getStatistic(idx); } -const SchemaMethod* SchemaObjectClass::getMethod(int idx) const { return impl->getMethod(idx); } - -SchemaEventClass::SchemaEventClass(const char* package, const char* name, Severity s) : impl(new SchemaEventClassImpl(package, name, s)) {} -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::setDesc(const char* desc) { impl->setDesc(desc); } -const SchemaClassKey* SchemaEventClass::getClassKey() const { return impl->getClassKey(); } -Severity SchemaEventClass::getSeverity() const { return impl->getSeverity(); } -int SchemaEventClass::getArgumentCount() const { return impl->getArgumentCount(); } -const SchemaArgument* SchemaEventClass::getArgument(int idx) const { return impl->getArgument(idx); } - diff --git a/qpid/cpp/src/qmf/engine/SchemaImpl.h b/qpid/cpp/src/qmf/engine/SchemaImpl.h deleted file mode 100644 index 683fb6f8f0..0000000000 --- a/qpid/cpp/src/qmf/engine/SchemaImpl.h +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef _QmfEngineSchemaImpl_ -#define _QmfEngineSchemaImpl_ - -/* - * 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/Schema.h" -#include "qpid/framing/Buffer.h" - -#include <string> -#include <vector> -#include <memory> - -namespace qmf { -namespace engine { - - // TODO: Destructors for schema classes - // TODO: Add "frozen" attribute for schema classes so they can't be modified after - // they've been registered. - - class SchemaHash { - union h { - uint8_t b[16]; - uint64_t q[2]; - } hash; - public: - SchemaHash(); - void encode(qpid::framing::Buffer& buffer) const; - void decode(qpid::framing::Buffer& buffer); - void update(const char* data, uint32_t len); - void update(uint8_t data); - void update(const std::string& data) { update(data.c_str(), data.size()); } - void update(Typecode t) { update((uint8_t) t); } - void update(Direction d) { update((uint8_t) d); } - void update(Access a) { update((uint8_t) a); } - void update(bool b) { update((uint8_t) (b ? 1 : 0)); } - const uint8_t* get() const { return hash.b; } - bool operator==(const SchemaHash& other) const; - bool operator<(const SchemaHash& other) const; - bool operator>(const SchemaHash& other) const; - }; - - struct SchemaArgumentImpl { - std::string name; - Typecode typecode; - Direction dir; - std::string unit; - std::string description; - - 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; } - void setDesc(const char* desc) { description = desc; } - const std::string& getName() const { return name; } - Typecode getType() const { return typecode; } - Direction getDirection() const { return dir; } - const std::string& getUnit() const { return unit; } - const std::string& getDesc() const { return description; } - void updateHash(SchemaHash& hash) const; - }; - - struct SchemaMethodImpl { - std::string name; - std::string description; - std::vector<const SchemaArgument*> arguments; - - 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 setDesc(const char* desc) { description = desc; } - const std::string& getName() const { return name; } - const std::string& getDesc() const { return description; } - int getArgumentCount() const { return arguments.size(); } - const SchemaArgument* getArgument(int idx) const; - void updateHash(SchemaHash& hash) const; - }; - - struct SchemaPropertyImpl { - std::string name; - Typecode typecode; - Access access; - bool index; - bool optional; - std::string unit; - std::string description; - - 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; } - void setOptional(bool val) { optional = val; } - void setUnit(const char* val) { unit = val; } - void setDesc(const char* desc) { description = desc; } - const std::string& getName() const { return name; } - Typecode getType() const { return typecode; } - Access getAccess() const { return access; } - bool isIndex() const { return index; } - bool isOptional() const { return optional; } - const std::string& getUnit() const { return unit; } - const std::string& getDesc() const { return description; } - void updateHash(SchemaHash& hash) const; - }; - - struct SchemaStatisticImpl { - std::string name; - Typecode typecode; - std::string unit; - std::string description; - - 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; } - const std::string& getName() const { return name; } - Typecode getType() const { return typecode; } - const std::string& getUnit() const { return unit; } - const std::string& getDesc() const { return description; } - void updateHash(SchemaHash& hash) const; - }; - - struct SchemaClassKeyImpl { - 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. - std::string packageContainer; - std::string nameContainer; - SchemaHash hashContainer; - - 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; } - const uint8_t* getHash() const { return hash.get(); } - - void encode(qpid::framing::Buffer& buffer) const; - bool operator==(const SchemaClassKeyImpl& other) const; - bool operator<(const SchemaClassKeyImpl& other) const; - const std::string& str() const; - }; - - struct SchemaObjectClassImpl { - std::string package; - std::string name; - mutable SchemaHash hash; - mutable bool hasHash; - std::auto_ptr<SchemaClassKey> classKey; - std::vector<const SchemaProperty*> properties; - std::vector<const SchemaStatistic*> statistics; - std::vector<const SchemaMethod*> methods; - - 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); - - const SchemaClassKey* getClassKey() const; - int getPropertyCount() const { return properties.size(); } - int getStatisticCount() const { return statistics.size(); } - int getMethodCount() const { return methods.size(); } - const SchemaProperty* getProperty(int idx) const; - const SchemaStatistic* getStatistic(int idx) const; - const SchemaMethod* getMethod(int idx) const; - }; - - struct SchemaEventClassImpl { - std::string package; - std::string name; - mutable SchemaHash hash; - mutable bool hasHash; - std::auto_ptr<SchemaClassKey> classKey; - std::string description; - Severity severity; - std::vector<const SchemaArgument*> arguments; - - SchemaEventClassImpl(const char* p, const char* n, Severity sev) : - package(p), name(n), hasHash(false), classKey(SchemaClassKeyImpl::factory(package, name, hash)), severity(sev) {} - 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 setDesc(const char* desc) { description = desc; } - - const SchemaClassKey* getClassKey() const; - Severity getSeverity() const { return severity; } - int getArgumentCount() const { return arguments.size(); } - const SchemaArgument* getArgument(int idx) const; - }; -} -} - -#endif - diff --git a/qpid/cpp/src/qmf/engine/SequenceManager.cpp b/qpid/cpp/src/qmf/engine/SequenceManager.cpp deleted file mode 100644 index 4a4644a8b9..0000000000 --- a/qpid/cpp/src/qmf/engine/SequenceManager.cpp +++ /dev/null @@ -1,96 +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/engine/SequenceManager.h" - -using namespace std; -using namespace qmf::engine; -using namespace qpid::sys; - -SequenceManager::SequenceManager() : nextSequence(1) {} - -void SequenceManager::setUnsolicitedContext(SequenceContext::Ptr ctx) -{ - unsolicitedContext = ctx; -} - -uint32_t SequenceManager::reserve(SequenceContext::Ptr ctx) -{ - Mutex::ScopedLock _lock(lock); - if (ctx.get() == 0) - ctx = unsolicitedContext; - uint32_t seq = nextSequence; - while (contextMap.find(seq) != contextMap.end()) - seq = seq < 0xFFFFFFFF ? seq + 1 : 1; - nextSequence = seq < 0xFFFFFFFF ? seq + 1 : 1; - contextMap[seq] = ctx; - ctx->reserve(); - return seq; -} - -void SequenceManager::release(uint32_t sequence) -{ - Mutex::ScopedLock _lock(lock); - - if (sequence == 0) { - if (unsolicitedContext.get() != 0) - unsolicitedContext->release(); - return; - } - - map<uint32_t, SequenceContext::Ptr>::iterator iter = contextMap.find(sequence); - if (iter != contextMap.end()) { - if (iter->second != 0) - iter->second->release(); - contextMap.erase(iter); - } -} - -void SequenceManager::releaseAll() -{ - Mutex::ScopedLock _lock(lock); - contextMap.clear(); -} - -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, routingKey, buffer); - if (done) - unsolicitedContext->release(); - } - return; - } - - map<uint32_t, SequenceContext::Ptr>::iterator iter = contextMap.find(sequence); - if (iter != contextMap.end()) { - if (iter->second != 0) { - done = iter->second->handleMessage(opcode, sequence, routingKey, buffer); - if (done) { - iter->second->release(); - contextMap.erase(iter); - } - } - } -} - diff --git a/qpid/cpp/src/qmf/engine/SequenceManager.h b/qpid/cpp/src/qmf/engine/SequenceManager.h deleted file mode 100644 index 9e47e38610..0000000000 --- a/qpid/cpp/src/qmf/engine/SequenceManager.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _QmfEngineSequenceManager_ -#define _QmfEngineSequenceManager_ - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "qpid/sys/Mutex.h" -#include <boost/shared_ptr.hpp> -#include <map> - -namespace qpid { - namespace framing { - class Buffer; - } -} - -namespace qmf { -namespace engine { - - class SequenceContext { - public: - typedef boost::shared_ptr<SequenceContext> Ptr; - SequenceContext() {} - virtual ~SequenceContext() {} - - virtual void reserve() = 0; - virtual bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer) = 0; - virtual void release() = 0; - }; - - class SequenceManager { - public: - SequenceManager(); - - void setUnsolicitedContext(SequenceContext::Ptr ctx); - uint32_t reserve(SequenceContext::Ptr ctx = SequenceContext::Ptr()); - void release(uint32_t sequence); - void releaseAll(); - void dispatch(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer); - - private: - mutable qpid::sys::Mutex lock; - uint32_t nextSequence; - SequenceContext::Ptr unsolicitedContext; - std::map<uint32_t, SequenceContext::Ptr> contextMap; - }; - -} -} - -#endif - diff --git a/qpid/cpp/src/qmf/engine/ValueImpl.cpp b/qpid/cpp/src/qmf/engine/ValueImpl.cpp deleted file mode 100644 index f9ebbf5028..0000000000 --- a/qpid/cpp/src/qmf/engine/ValueImpl.cpp +++ /dev/null @@ -1,571 +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/engine/ValueImpl.h" -#include <qpid/framing/FieldValue.h> -#include <qpid/framing/FieldTable.h> -#include <qpid/framing/List.h> -#include <qpid/log/Statement.h> - -using namespace std; -using namespace qmf::engine; -//using qpid::framing::Buffer; -//using qpid::framing::FieldTable; -//using qpid::framing::FieldValue; -using namespace qpid::framing; - -ValueImpl::ValueImpl(Typecode t, Buffer& buf) : typecode(t) -{ - uint64_t first; - uint64_t second; - FieldTable ft; - List fl; - - switch (typecode) { - case TYPE_UINT8 : value.u32 = (uint32_t) buf.getOctet(); break; - case TYPE_UINT16 : value.u32 = (uint32_t) buf.getShort(); break; - case TYPE_UINT32 : value.u32 = (uint32_t) buf.getLong(); break; - case TYPE_UINT64 : value.u64 = buf.getLongLong(); break; - case TYPE_SSTR : buf.getShortString(stringVal); break; - case TYPE_LSTR : buf.getMediumString(stringVal); break; - case TYPE_ABSTIME : value.s64 = buf.getLongLong(); break; - case TYPE_DELTATIME : value.u64 = buf.getLongLong(); break; - 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) ((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; - case TYPE_REF: - first = buf.getLongLong(); - second = buf.getLongLong(); - refVal.impl->setValue(first, second); - break; - - case TYPE_MAP: - ft.decode(buf); - initMap(ft); - break; - - case TYPE_LIST: - fl.decode(buf); - initList(fl); - break; - - case TYPE_ARRAY: - case TYPE_OBJECT: - default: - break; - } -} - -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() -{ -} - -void ValueImpl::initMap(const FieldTable& ft) -{ - for (FieldTable::ValueMap::const_iterator iter = ft.begin(); - iter != ft.end(); iter++) { - const string& name(iter->first); - const FieldValue& fvalue(*iter->second); - uint8_t amqType = fvalue.getType(); - - if (amqType == 0x32) { - Value* subval(new Value(TYPE_UINT64)); - subval->setUint64(fvalue.get<int64_t>()); - insert(name.c_str(), subval); - } else if ((amqType & 0xCF) == 0x02) { - Value* subval(new Value(TYPE_UINT32)); - switch (amqType) { - case 0x02 : subval->setUint(fvalue.get<int>()); break; - case 0x12 : subval->setUint(fvalue.get<int>()); break; - case 0x22 : subval->setUint(fvalue.get<int>()); break; - } - insert(name.c_str(), subval); - } else if (amqType == 0x31) { // int64 - Value* subval(new Value(TYPE_INT64)); - subval->setInt64(fvalue.get<int64_t>()); - insert(name.c_str(), subval); - } else if ((amqType & 0xCF) == 0x01) { // 0x01:int8, 0x11:int16, 0x21:int21 - Value* subval(new Value(TYPE_INT32)); - subval->setInt((int32_t)fvalue.get<int>()); - insert(name.c_str(), subval); - } else if (amqType == 0x85 || amqType == 0x95) { - Value* subval(new Value(TYPE_LSTR)); - subval->setString(fvalue.get<string>().c_str()); - insert(name.c_str(), subval); - } else if (amqType == 0x23 || amqType == 0x33) { - Value* subval(new Value(TYPE_DOUBLE)); - subval->setDouble(fvalue.get<double>()); - insert(name.c_str(), subval); - } else if (amqType == 0xa8) { - FieldTable subFt; - bool valid = qpid::framing::getEncodedValue<FieldTable>(iter->second, subFt); - if (valid) { - Value* subval(new Value(TYPE_MAP)); - subval->impl->initMap(subFt); - insert(name.c_str(), subval); - } - } else if (amqType == 0xa9) { - List subList; - bool valid = qpid::framing::getEncodedValue<List>(iter->second, subList); - if (valid) { - Value* subval(new Value(TYPE_LIST)); - subval->impl->initList(subList); - insert(name.c_str(), subval); - } - } else if (amqType == 0x08) { - Value* subval(new Value(TYPE_BOOL)); - subval->setBool(fvalue.get<int>() ? true : false); - insert(name.c_str(), subval); - } else { - QPID_LOG(error, "Unable to decode unsupported AMQP typecode=" << amqType << " map index=" << name); - } - } -} - -void ValueImpl::mapToFieldTable(FieldTable& ft) const -{ - FieldTable subFt; - - for (map<string, Value>::const_iterator iter = mapVal.begin(); - iter != mapVal.end(); iter++) { - const string& name(iter->first); - const Value& subval(iter->second); - - switch (subval.getType()) { - case TYPE_UINT8: - case TYPE_UINT16: - case TYPE_UINT32: - ft.setUInt64(name, (uint64_t) subval.asUint()); - break; - case TYPE_UINT64: - case TYPE_DELTATIME: - ft.setUInt64(name, subval.asUint64()); - break; - case TYPE_SSTR: - case TYPE_LSTR: - ft.setString(name, subval.asString()); - break; - case TYPE_INT64: - case TYPE_ABSTIME: - ft.setInt64(name, subval.asInt64()); - break; - case TYPE_BOOL: - ft.set(name, FieldTable::ValuePtr(new BoolValue(subval.asBool()))); - break; - case TYPE_FLOAT: - ft.setFloat(name, subval.asFloat()); - break; - case TYPE_DOUBLE: - ft.setDouble(name, subval.asDouble()); - break; - case TYPE_INT8: - case TYPE_INT16: - case TYPE_INT32: - ft.setInt(name, subval.asInt()); - break; - case TYPE_MAP: - subFt.clear(); - subval.impl->mapToFieldTable(subFt); - ft.setTable(name, subFt); - break; - case TYPE_LIST: - { - List subList; - subval.impl->listToFramingList(subList); - ft.set(name, - ::qpid::framing::FieldTable::ValuePtr( - new ListValue( - subList))); - } break; - case TYPE_ARRAY: - case TYPE_OBJECT: - case TYPE_UUID: - case TYPE_REF: - default: - break; - } - } - } - - -void ValueImpl::initList(const List& fl) -{ - for (List::const_iterator iter = fl.begin(); - iter != fl.end(); iter++) { - const FieldValue& fvalue(*iter->get()); - uint8_t amqType = fvalue.getType(); - - if (amqType == 0x32) { - Value* subval(new Value(TYPE_UINT64)); - subval->setUint64(fvalue.get<int64_t>()); - appendToList(subval); - } else if ((amqType & 0xCF) == 0x02) { - Value* subval(new Value(TYPE_UINT32)); - switch (amqType) { - case 0x02 : subval->setUint(fvalue.get<int>()); break; // uint8 - case 0x12 : subval->setUint(fvalue.get<int>()); break; // uint16 - case 0x22 : subval->setUint(fvalue.get<int>()); break; // uint32 - } - appendToList(subval); - } else if (amqType == 0x31) { // int64 - Value* subval(new Value(TYPE_INT64)); - subval->setInt64(fvalue.get<int64_t>()); - appendToList(subval); - } else if ((amqType & 0xCF) == 0x01) { // 0x01:int8, 0x11:int16, 0x21:int32 - Value* subval(new Value(TYPE_INT32)); - subval->setInt((int32_t)fvalue.get<int>()); - appendToList(subval); - } else if (amqType == 0x85 || amqType == 0x95) { - Value* subval(new Value(TYPE_LSTR)); - subval->setString(fvalue.get<string>().c_str()); - appendToList(subval); - } else if (amqType == 0x23 || amqType == 0x33) { - Value* subval(new Value(TYPE_DOUBLE)); - subval->setDouble(fvalue.get<double>()); - appendToList(subval); - } else if (amqType == 0xa8) { - FieldTable subFt; - bool valid = qpid::framing::getEncodedValue<FieldTable>(*iter, subFt); - if (valid) { - Value* subval(new Value(TYPE_MAP)); - subval->impl->initMap(subFt); - appendToList(subval); - } - } else if (amqType == 0xa9) { - List subList; - bool valid = qpid::framing::getEncodedValue<List>(*iter, subList); - if (valid) { - Value *subVal(new Value(TYPE_LIST)); - subVal->impl->initList(subList); - appendToList(subVal); - } - } else if (amqType == 0x08) { - Value* subval(new Value(TYPE_BOOL)); - subval->setBool(fvalue.get<int>() ? true : false); - appendToList(subval); - } else { - QPID_LOG(error, "Unable to decode unsupported AMQP typecode =" << amqType); - } - } -} - -void ValueImpl::listToFramingList(List& fl) const -{ - for (vector<Value>::const_iterator iter = vectorVal.begin(); - iter != vectorVal.end(); iter++) { - const Value& subval(*iter); - - switch (subval.getType()) { - case TYPE_UINT8: - case TYPE_UINT16: - case TYPE_UINT32: - fl.push_back(List::ValuePtr(new Unsigned64Value((uint64_t) subval.asUint()))); - break; - case TYPE_UINT64: - case TYPE_DELTATIME: - fl.push_back(List::ValuePtr(new Unsigned64Value(subval.asUint64()))); - break; - case TYPE_SSTR: - case TYPE_LSTR: - fl.push_back(List::ValuePtr(new Str16Value(subval.asString()))); - break; - case TYPE_INT64: - case TYPE_ABSTIME: - fl.push_back(List::ValuePtr(new Integer64Value(subval.asInt64()))); - break; - case TYPE_BOOL: - fl.push_back(List::ValuePtr(new BoolValue(subval.asBool() ? 1 : 0))); - break; - case TYPE_FLOAT: - fl.push_back(List::ValuePtr(new FloatValue(subval.asFloat()))); - break; - case TYPE_DOUBLE: - fl.push_back(List::ValuePtr(new DoubleValue(subval.asDouble()))); - break; - case TYPE_INT8: - case TYPE_INT16: - case TYPE_INT32: - fl.push_back(List::ValuePtr(new IntegerValue(subval.asInt()))); - break; - case TYPE_MAP: - { - FieldTable subFt; - subval.impl->mapToFieldTable(subFt); - fl.push_back(List::ValuePtr(new FieldTableValue(subFt))); - - } break; - case TYPE_LIST: - { - List subList; - subval.impl->listToFramingList(subList); - fl.push_back(List::ValuePtr(new ListValue(subList))); - } break; - - case TYPE_ARRAY: - case TYPE_OBJECT: - case TYPE_UUID: - case TYPE_REF: - default: - break; - } - } - } - - - -void ValueImpl::encode(Buffer& buf) const -{ - FieldTable ft; - List fl; - - switch (typecode) { - case TYPE_UINT8 : buf.putOctet((uint8_t) value.u32); break; - case TYPE_UINT16 : buf.putShort((uint16_t) value.u32); break; - case TYPE_UINT32 : buf.putLong(value.u32); break; - case TYPE_UINT64 : buf.putLongLong(value.u64); break; - case TYPE_SSTR : buf.putShortString(stringVal); break; - case TYPE_LSTR : buf.putMediumString(stringVal); break; - case TYPE_ABSTIME : buf.putLongLong(value.s64); break; - case TYPE_DELTATIME : buf.putLongLong(value.u64); break; - case TYPE_BOOL : buf.putOctet(value.boolVal ? 1 : 0); break; - case TYPE_FLOAT : buf.putFloat(value.floatVal); break; - case TYPE_DOUBLE : buf.putDouble(value.doubleVal); break; - case TYPE_INT8 : buf.putOctet((uint8_t) value.s32); break; - case TYPE_INT16 : buf.putShort((uint16_t) value.s32); break; - case TYPE_INT32 : buf.putLong(value.s32); break; - case TYPE_INT64 : buf.putLongLong(value.s64); break; - case TYPE_UUID : buf.putBin128(value.uuidVal); break; - case TYPE_REF : refVal.impl->encode(buf); break; - case TYPE_MAP: - mapToFieldTable(ft); - ft.encode(buf); - break; - case TYPE_LIST: - listToFramingList(fl); - fl.encode(buf); - break; - - case TYPE_ARRAY: - case TYPE_OBJECT: - default: - break; - } -} - -uint32_t ValueImpl::encodedSize() const -{ - FieldTable ft; - List fl; - - switch (typecode) { - case TYPE_UINT8 : - case TYPE_BOOL : - case TYPE_INT8 : return 1; - - case TYPE_UINT16 : - case TYPE_INT16 : return 2; - - case TYPE_UINT32 : - case TYPE_INT32 : - case TYPE_FLOAT : return 4; - - case TYPE_UINT64 : - case TYPE_INT64 : - case TYPE_DOUBLE : - case TYPE_ABSTIME : - case TYPE_DELTATIME : return 8; - - case TYPE_UUID : - case TYPE_REF : return 16; - - case TYPE_SSTR : return 1 + stringVal.size(); - case TYPE_LSTR : return 2 + stringVal.size(); - case TYPE_MAP: - mapToFieldTable(ft); - return ft.encodedSize(); - - case TYPE_LIST: - listToFramingList(fl); - return fl.encodedSize(); - - case TYPE_ARRAY: - case TYPE_OBJECT: - default: - break; - } - - return 0; -} - -bool ValueImpl::keyInMap(const char* key) const -{ - return typecode == TYPE_MAP && mapVal.count(key) > 0; -} - -Value* ValueImpl::byKey(const char* key) -{ - if (keyInMap(key)) { - map<string, Value>::iterator iter = mapVal.find(key); - if (iter != mapVal.end()) - return &iter->second; - } - return 0; -} - -const Value* ValueImpl::byKey(const char* key) const -{ - if (keyInMap(key)) { - map<string, Value>::const_iterator iter = mapVal.find(key); - if (iter != mapVal.end()) - return &iter->second; - } - return 0; -} - -void ValueImpl::deleteKey(const char* key) -{ - mapVal.erase(key); -} - -void ValueImpl::insert(const char* key, Value* val) -{ - pair<string, Value> entry(key, *val); - mapVal.insert(entry); -} - -const char* ValueImpl::key(uint32_t idx) const -{ - map<string, Value>::const_iterator iter = mapVal.begin(); - for (uint32_t i = 0; i < idx; i++) { - if (iter == mapVal.end()) - break; - iter++; - } - - if (iter == mapVal.end()) - return 0; - else - return iter->first.c_str(); -} - -Value* ValueImpl::arrayItem(uint32_t) -{ - return 0; -} - -void ValueImpl::appendToArray(Value*) -{ -} - -void ValueImpl::deleteArrayItem(uint32_t) -{ -} - - -//================================================================== -// Wrappers -//================================================================== - -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/engine/ValueImpl.h b/qpid/cpp/src/qmf/engine/ValueImpl.h deleted file mode 100644 index 8de8c5329f..0000000000 --- a/qpid/cpp/src/qmf/engine/ValueImpl.h +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef _QmfEngineValueImpl_ -#define _QmfEngineValueImpl_ - -/* - * 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/Value.h> -#include <qmf/engine/ObjectIdImpl.h> -#include <qmf/engine/Object.h> -#include <qpid/framing/Buffer.h> -#include <string> -#include <string.h> -#include <map> -#include <vector> -#include <boost/shared_ptr.hpp> - -namespace qpid { -namespace framing { - class FieldTable; - class List; -} -} - -namespace qmf { -namespace engine { - - // TODO: set valid flag on all value settors - // TODO: add a modified flag and accessors - - struct ValueImpl { - const Typecode typecode; - bool valid; - - ObjectId refVal; - std::string stringVal; - std::auto_ptr<Object> objectVal; - std::map<std::string, Value> mapVal; - std::vector<Value> vectorVal; - Typecode arrayTypecode; - - union { - uint32_t u32; - uint64_t u64; - int32_t s32; - int64_t s64; - bool boolVal; - float floatVal; - double doubleVal; - uint8_t uuidVal[16]; - } value; - - 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; - uint32_t encodedSize() const; - - Typecode getType() const { return typecode; } - bool isNull() const { return !valid; } - void setNull() { valid = false; } - - bool isObjectId() const { return typecode == TYPE_REF; } - const ObjectId& asObjectId() const { return refVal; } - void setObjectId(const ObjectId& o) { refVal = o; } // TODO - - bool isUint() const { return typecode >= TYPE_UINT8 && typecode <= TYPE_UINT32; } - uint32_t asUint() const { return value.u32; } - void setUint(uint32_t val) { value.u32 = val; } - - bool isInt() const { return typecode >= TYPE_INT8 && typecode <= TYPE_INT32; } - int32_t asInt() const { return value.s32; } - void setInt(int32_t val) { value.s32 = val; } - - bool isUint64() const { return typecode == TYPE_UINT64 || typecode == TYPE_DELTATIME; } - uint64_t asUint64() const { return value.u64; } - void setUint64(uint64_t val) { value.u64 = val; } - - bool isInt64() const { return typecode == TYPE_INT64 || typecode == TYPE_ABSTIME; } - int64_t asInt64() const { return value.s64; } - void setInt64(int64_t val) { value.s64 = val; } - - bool isString() const { return typecode == TYPE_SSTR || typecode == TYPE_LSTR; } - const char* asString() const { return stringVal.c_str(); } - void setString(const char* val) { stringVal = val; } - - bool isBool() const { return typecode == TYPE_BOOL; } - bool asBool() const { return value.boolVal; } - void setBool(bool val) { value.boolVal = val; } - - bool isFloat() const { return typecode == TYPE_FLOAT; } - float asFloat() const { return value.floatVal; } - void setFloat(float val) { value.floatVal = val; } - - bool isDouble() const { return typecode == TYPE_DOUBLE; } - double asDouble() const { return value.doubleVal; } - void setDouble(double val) { value.doubleVal = val; } - - bool isUuid() const { return typecode == TYPE_UUID; } - const uint8_t* asUuid() const { return value.uuidVal; } - void setUuid(const uint8_t* val) { ::memcpy(value.uuidVal, val, 16); } - - bool isObject() const { return typecode == TYPE_OBJECT; } - Object* asObject() const { return objectVal.get(); } - void setObject(Object* val) { objectVal.reset(val); } - - bool isMap() const { return typecode == TYPE_MAP; } - bool keyInMap(const char* key) const; - Value* byKey(const char* key); - const Value* byKey(const char* key) const; - void deleteKey(const char* key); - void insert(const char* key, Value* val); - uint32_t keyCount() const { return mapVal.size(); } - const char* key(uint32_t idx) const; - - bool isList() const { return typecode == TYPE_LIST; } - uint32_t listItemCount() const { return vectorVal.size(); } - Value* listItem(uint32_t idx) { return idx < listItemCount() ? &vectorVal[idx] : 0; } - const Value* listItem(uint32_t idx) const { return idx < listItemCount() ? &vectorVal[idx] : 0; } - void appendToList(Value* val) { vectorVal.push_back(*val); } - void deleteListItem(uint32_t idx) { if (idx < listItemCount()) vectorVal.erase(vectorVal.begin()+idx); } - - bool isArray() const { return typecode == TYPE_ARRAY; } - Typecode arrayType() const { return arrayTypecode; } - uint32_t arrayItemCount() const { return 0; } - Value* arrayItem(uint32_t idx); - void appendToArray(Value* val); - void deleteArrayItem(uint32_t idx); - - private: - void mapToFieldTable(qpid::framing::FieldTable& ft) const; - void initMap(const qpid::framing::FieldTable& ft); - - void listToFramingList(qpid::framing::List& fl) const; - void initList(const qpid::framing::List& fl); - }; -} -} - -#endif - diff --git a/qpid/cpp/src/qmfc.mk b/qpid/cpp/src/qmfc.mk deleted file mode 100644 index e445a538a1..0000000000 --- a/qpid/cpp/src/qmfc.mk +++ /dev/null @@ -1,57 +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. -# - -# -# qmf console library makefile fragment, to be included in Makefile.am -# -lib_LTLIBRARIES += libqmfconsole.la - -# Public header files. -nobase_include_HEADERS += \ - ../include/qpid/console/Agent.h \ - ../include/qpid/console/Broker.h \ - ../include/qpid/console/ClassKey.h \ - ../include/qpid/console/ConsoleImportExport.h \ - ../include/qpid/console/ConsoleListener.h \ - ../include/qpid/console/Event.h \ - ../include/qpid/console/Object.h \ - ../include/qpid/console/ObjectId.h \ - ../include/qpid/console/Package.h \ - ../include/qpid/console/Schema.h \ - ../include/qpid/console/SequenceManager.h \ - ../include/qpid/console/SessionManager.h \ - ../include/qpid/console/Value.h - -libqmfconsole_la_SOURCES = \ - qpid/console/Agent.cpp \ - qpid/console/Broker.cpp \ - qpid/console/ClassKey.cpp \ - qpid/console/Event.cpp \ - qpid/console/Object.cpp \ - qpid/console/ObjectId.cpp \ - qpid/console/Package.cpp \ - qpid/console/Schema.cpp \ - qpid/console/SequenceManager.cpp \ - qpid/console/SessionManager.cpp \ - qpid/console/Value.cpp - -libqmfconsole_la_LIBADD = libqpidclient.la - -QMFCONSOLE_VERSION_INFO = 2:0:0 -libqmfconsole_la_LDFLAGS = -version-info $(QMFCONSOLE_VERSION_INFO) diff --git a/qpid/cpp/src/qpid.linkmap b/qpid/cpp/src/qpid.linkmap new file mode 100644 index 0000000000..4556985b1b --- /dev/null +++ b/qpid/cpp/src/qpid.linkmap @@ -0,0 +1,10 @@ +{ + global: + extern "C++" { + typeinfo*qpid::*; + vtable*qpid::*; + qpid::*; + qpid::*operator*qpid::*; + }; + local: *; +}; diff --git a/qpid/cpp/src/qpid/Address.h b/qpid/cpp/src/qpid/Address.h new file mode 100755 index 0000000000..fe43f3847d --- /dev/null +++ b/qpid/cpp/src/qpid/Address.h @@ -0,0 +1,56 @@ +#ifndef QPID_ADDRESS_H +#define QPID_ADDRESS_H + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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 <iosfwd> +#include <string> + +namespace qpid { +namespace client { struct ConnectionSettings; } + + +/** + * Contains the protocol address of an AMQP broker. + */ +struct Address { +public: + QPID_COMMON_EXTERN static const std::string TCP; // Default TCP protocol tag. + QPID_COMMON_EXTERN static const uint16_t AMQP_PORT=5672; // Default AMQP port. + + QPID_COMMON_INLINE_EXTERN explicit Address( + const std::string& protocol_=std::string(), + const std::string& host_=std::string(), + uint16_t port_=0 + ) : protocol(protocol_), host(host_), port(port_) {} + + std::string protocol; + std::string host; + uint16_t port; +}; + +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const Address& addr); +QPID_COMMON_EXTERN bool operator==(const Address& x, const Address& y); +QPID_COMMON_EXTERN bool operator!=(const Address& x, const Address& y); + +} // namespace qpid + +#endif /*!QPID_ADDRESS_H*/ diff --git a/qpid/cpp/src/qpid/CommonImportExport.h b/qpid/cpp/src/qpid/CommonImportExport.h new file mode 100644 index 0000000000..dd2b900b73 --- /dev/null +++ b/qpid/cpp/src/qpid/CommonImportExport.h @@ -0,0 +1,35 @@ +#ifndef QPID_COMMON_IMPORT_EXPORT_H +#define QPID_COMMON_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. + */ + +#include "qpid/ImportExport.h" + +#if defined(COMMON_EXPORT) || defined (qpidcommon_EXPORTS) +# define QPID_COMMON_EXTERN QPID_EXPORT +# define QPID_COMMON_CLASS_EXTERN QPID_CLASS_EXPORT +# define QPID_COMMON_INLINE_EXTERN QPID_INLINE_EXPORT +#else +# define QPID_COMMON_EXTERN QPID_IMPORT +# define QPID_COMMON_CLASS_EXTERN QPID_CLASS_IMPORT +# define QPID_COMMON_INLINE_EXTERN QPID_INLINE_IMPORT +#endif + +#endif diff --git a/qpid/cpp/src/qpid/Exception.h b/qpid/cpp/src/qpid/Exception.h new file mode 100644 index 0000000000..cbd175214d --- /dev/null +++ b/qpid/cpp/src/qpid/Exception.h @@ -0,0 +1,91 @@ +#ifndef _Exception_ +#define _Exception_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/framing/amqp_types.h" +#include "qpid/framing/constants.h" +#include "qpid/framing/enum.h" +#include "qpid/sys/StrError.h" +#include "qpid/CommonImportExport.h" +#include <string> +#include <errno.h> + +namespace qpid +{ + +/** + * Base class for Qpid runtime exceptions. + */ +class QPID_COMMON_CLASS_EXTERN Exception : public std::exception +{ + public: + QPID_COMMON_EXTERN explicit Exception(const std::string& message=std::string()) throw(); + QPID_COMMON_EXTERN virtual ~Exception() throw(); + QPID_COMMON_EXTERN virtual const char* what() const throw(); // prefix: message + QPID_COMMON_EXTERN virtual std::string getMessage() const; // Unprefixed message + QPID_COMMON_EXTERN virtual std::string getPrefix() const; // Prefix + + private: + std::string message; + mutable std::string whatStr; +}; + +/** Exception that includes an errno message. */ +struct QPID_COMMON_CLASS_EXTERN ErrnoException : public Exception { + ErrnoException(const std::string& msg, int err) : Exception(msg+": "+qpid::sys::strError(err)) {} + ErrnoException(const std::string& msg) : Exception(msg+": "+qpid::sys::strError(errno)) {} +}; + +struct QPID_COMMON_CLASS_EXTERN SessionException : public Exception { + const framing::execution::ErrorCode code; + SessionException(framing::execution::ErrorCode code_, const std::string& message) + : Exception(message), code(code_) {} +}; + +struct QPID_COMMON_CLASS_EXTERN ChannelException : public Exception { + const framing::session::DetachCode code; + ChannelException(framing::session::DetachCode _code, const std::string& message) + : Exception(message), code(_code) {} +}; + +struct QPID_COMMON_CLASS_EXTERN ConnectionException : public Exception { + const framing::connection::CloseCode code; + ConnectionException(framing::connection::CloseCode _code, const std::string& message) + : Exception(message), code(_code) {} +}; + +struct QPID_COMMON_CLASS_EXTERN ClosedException : public Exception { + QPID_COMMON_EXTERN ClosedException(const std::string& msg=std::string()); + QPID_COMMON_EXTERN std::string getPrefix() const; +}; + +/** + * Exception representing transport failure + */ +struct TransportFailure : public Exception { + TransportFailure(const std::string& msg=std::string()) : Exception(msg) {} +}; + +} // namespace qpid + +#endif /*!_Exception_*/ diff --git a/qpid/cpp/src/qpid/InlineAllocator.h b/qpid/cpp/src/qpid/InlineAllocator.h new file mode 100644 index 0000000000..2502545dcb --- /dev/null +++ b/qpid/cpp/src/qpid/InlineAllocator.h @@ -0,0 +1,101 @@ +#ifndef QPID_INLINEALLOCATOR_H +#define QPID_INLINEALLOCATOR_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 <memory> +#include <assert.h> +#include <boost/type_traits/type_with_alignment.hpp> +#include <boost/type_traits/alignment_of.hpp> + +namespace qpid { + +template <typename RequestedType, typename InlineType, typename BaseAllocator, size_t Max> +struct InlineRebind; + + +/** + * An allocator that has inline storage for up to Max objects + * of type BaseAllocator::value_type. + */ +template <class BaseAllocator, size_t Max> +class InlineAllocator : public BaseAllocator { + public: + typedef typename BaseAllocator::pointer pointer; + typedef typename BaseAllocator::size_type size_type; + typedef typename BaseAllocator::value_type value_type; + + InlineAllocator() : allocated(false) {} + InlineAllocator(const InlineAllocator& x) : BaseAllocator(x), allocated(false) {} + + pointer allocate(size_type n) { + if (n <= Max && !allocated) { + allocated=true; + return reinterpret_cast<value_type*>(address()); + } + else + return BaseAllocator::allocate(n, 0); + } + + void deallocate(pointer p, size_type n) { + if (p == address()) { + assert(allocated); + allocated=false; + } + else + BaseAllocator::deallocate(p, n); + } + + template<typename T1> + struct rebind { + typedef typename InlineRebind<T1, value_type, BaseAllocator, Max>::other other; + }; + + private: + // POD object with alignment and size to hold Max value_types. + static const size_t ALIGNMENT=boost::alignment_of<value_type>::value; + typedef typename boost::type_with_alignment<ALIGNMENT>::type Aligner; + union Store { + Aligner aligner_; + char sizer_[sizeof(value_type)*Max]; + } store; + value_type* address() { return reinterpret_cast<value_type*>(&store); } + bool allocated; +}; + + +// Rebind: if RequestedType == InlineType, use the InlineAllocator, +// otherwise, use the BaseAllocator without any inlining. + +template <typename RequestedType, typename InlineType, typename BaseAllocator, size_t Max> +struct InlineRebind { + typedef typename BaseAllocator::template rebind<RequestedType>::other other; +}; + +template <typename T, typename BaseAllocator, size_t Max> +struct InlineRebind<T, T, BaseAllocator, Max> { + typedef typename qpid::InlineAllocator<BaseAllocator, Max> other; +}; + +} // namespace qpid + +#endif /*!QPID_INLINEALLOCATOR_H*/ diff --git a/qpid/cpp/src/qpid/InlineVector.h b/qpid/cpp/src/qpid/InlineVector.h new file mode 100644 index 0000000000..c55db295f3 --- /dev/null +++ b/qpid/cpp/src/qpid/InlineVector.h @@ -0,0 +1,68 @@ +#ifndef QPID_INLINEVECTOR_H +#define QPID_INLINEVECTOR_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/InlineAllocator.h" +#include <vector> + +namespace qpid { + +/** + * A vector that stores up to Max elements in inline storage, + * otherwise uses normal vector allocation. + * + * NOTE: depends on some non-standard but highly probably assumptions + * about how std::vector uses its allocator, they are true for g++. + * - default constructor does not allocate. + * - reserve(N) does not allocate more than N elements. + * - vector never re-allocates when size() < capacity() + */ +template <class T, size_t Max, class Alloc=std::allocator<T> > +class InlineVector : public std::vector<T, InlineAllocator<Alloc, Max> > +{ + typedef std::vector<T, InlineAllocator<Alloc, Max> > Base; + public: + typedef typename Base::allocator_type allocator_type; + typedef typename Base::value_type value_type; + typedef typename Base::size_type size_type; + + explicit InlineVector(const allocator_type& a=allocator_type()) : Base(a) { + this->reserve(Max); + } + + explicit InlineVector(size_type n, const value_type& x = value_type(), + const allocator_type& a=allocator_type()) : Base(a) + { + this->reserve(std::max(n, Max)); + this->insert(this->end(), n, x); + } + + InlineVector(const InlineVector& x) : Base() { + this->reserve(std::max(x.size(), Max)); + *this = x; + } +}; + +} // namespace qpid + +#endif /*!QPID_INLINEVECTOR_H*/ diff --git a/qpid/cpp/src/qpid/Msg.h b/qpid/cpp/src/qpid/Msg.h new file mode 100644 index 0000000000..5f0b11bc60 --- /dev/null +++ b/qpid/cpp/src/qpid/Msg.h @@ -0,0 +1,79 @@ +#ifndef QPID_MSG_H +#define QPID_MSG_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 <sstream> +#include <iostream> +#include "qpid/types/ImportExport.h" + +namespace qpid { + +/** A simple wrapper for std::ostringstream that allows + * in place construction of a message and automatic conversion + * to string. + * E.g. + *@code + * void foo(const std::string&); + * foo(Msg() << "hello " << 32); + *@endcode + * Will construct the string "hello 32" and pass it to foo() + */ +struct Msg { + std::ostringstream os; + Msg() {} + Msg(const Msg& m) : os(m.str()) {} + std::string str() const { return os.str(); } + operator std::string() const { return str(); } + + Msg& operator<<(long n) { os << n; return *this; } + Msg& operator<<(unsigned long n) { os << n; return *this; } + Msg& operator<<(bool n) { os << n; return *this; } + Msg& operator<<(short n) { os << n; return *this; } + Msg& operator<<(unsigned short n) { os << n; return *this; } + Msg& operator<<(int n) { os << n; return *this; } + Msg& operator<<(unsigned int n) { os << n; return *this; } +#ifdef _GLIBCXX_USE_LONG_LONG + Msg& operator<<(long long n) { os << n; return *this; } + Msg& operator<<(unsigned long long n) { os << n; return *this; } +#endif + Msg& operator<<(double n) { os << n; return *this; } + Msg& operator<<(float n) { os << n; return *this; } + Msg& operator<<(long double n) { os << n; return *this; } + + template <class T> Msg& operator<<(const T& t) { os <<t; return *this; } +}; + + + +inline std::ostream& operator<<(std::ostream& o, const Msg& m) { + return o << m.str(); +} + +/** Construct a message using operator << and append (file:line) */ +#define QUOTE_(x) #x +#define QUOTE(x) QUOTE_(x) +#define QPID_MSG(message) (::qpid::Msg() << message << " (" __FILE__ ":" QUOTE(__LINE__) ")") + +} // namespace qpid + +#endif /*!QPID_MSG_H*/ diff --git a/qpid/cpp/src/tests/ConsoleTest.cpp b/qpid/cpp/src/qpid/NullSaslClient.cpp index 107472ed9e..d1f2706f50 100644 --- a/qpid/cpp/src/tests/ConsoleTest.cpp +++ b/qpid/cpp/src/qpid/NullSaslClient.cpp @@ -18,29 +18,37 @@ * under the License. * */ - -#include "qpid/console/Package.h" -#include "qpid/console/ClassKey.h" -#include "unit_test.h" +#include "NullSaslClient.h" +#include "qpid/sys/SecurityLayer.h" +#include "Exception.h" namespace qpid { -namespace tests { - -QPID_AUTO_TEST_SUITE(ConsoleTestSuite) - -using namespace qpid::framing; -using namespace qpid::console; - -QPID_AUTO_TEST_CASE(testClassKey) { - uint8_t hash[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; - ClassKey k("com.redhat.test", "class", hash); - - BOOST_CHECK_EQUAL(k.getPackageName(), "com.redhat.test"); - BOOST_CHECK_EQUAL(k.getClassName(), "class"); - BOOST_CHECK_EQUAL(k.getHashString(), "00010203-04050607-08090a0b-0c0d0e0f"); - BOOST_CHECK_EQUAL(k.str(), "com.redhat.test:class(00010203-04050607-08090a0b-0c0d0e0f)"); +namespace { +const std::string ANONYMOUS("ANONYMOUS"); } -QPID_AUTO_TEST_SUITE_END() - -}} // namespace qpid::tests +bool NullSaslClient::start(const std::string& mechanisms, std::string&, + const qpid::sys::SecuritySettings*) +{ + if (mechanisms.find(ANONYMOUS) == std::string::npos) { + throw qpid::Exception("No suitable mechanism!"); + } + return false; +} +std::string NullSaslClient::step(const std::string&) +{ + return std::string(); +} +std::string NullSaslClient::getMechanism() +{ + return ANONYMOUS; +} +std::string NullSaslClient::getUserId() +{ + return ANONYMOUS; +} +std::auto_ptr<qpid::sys::SecurityLayer> NullSaslClient::getSecurityLayer(uint16_t) +{ + return std::auto_ptr<qpid::sys::SecurityLayer>(); +} +} // namespace qpid diff --git a/qpid/cpp/src/qpid/NullSaslClient.h b/qpid/cpp/src/qpid/NullSaslClient.h new file mode 100644 index 0000000000..b0a63a8ecb --- /dev/null +++ b/qpid/cpp/src/qpid/NullSaslClient.h @@ -0,0 +1,41 @@ +#ifndef QPID_NULLSASLCLIENT_H +#define QPID_NULLSASLCLIENT_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 "Sasl.h" + +namespace qpid { + +class NullSaslClient : public Sasl +{ + public: + bool start(const std::string& mechanisms, std::string& response, + const qpid::sys::SecuritySettings* externalSecuritySettings = 0); + std::string step(const std::string& challenge); + std::string getMechanism(); + std::string getUserId(); + std::auto_ptr<qpid::sys::SecurityLayer> getSecurityLayer(uint16_t maxFrameSize); + private: +}; +} // namespace qpid + +#endif /*!QPID_NULLSASLCLIENT_H*/ diff --git a/qpid/cpp/src/qpid/NullSaslServer.h b/qpid/cpp/src/qpid/NullSaslServer.h index 810defe574..22a1b293a3 100644 --- a/qpid/cpp/src/qpid/NullSaslServer.h +++ b/qpid/cpp/src/qpid/NullSaslServer.h @@ -21,6 +21,7 @@ * under the License. * */ +#include "qpid/CommonImportExport.h" #include "qpid/SaslServer.h" namespace qpid { @@ -34,7 +35,7 @@ namespace qpid { class NullSaslServer : public SaslServer { public: - NullSaslServer(const std::string& realm); + QPID_COMMON_EXTERN NullSaslServer(const std::string& realm); Status start(const std::string& mechanism, const std::string* response, std::string& challenge); Status step(const std::string* response, std::string& challenge); std::string getMechanisms(); diff --git a/qpid/cpp/src/qpid/Options.h b/qpid/cpp/src/qpid/Options.h new file mode 100644 index 0000000000..6c908518b8 --- /dev/null +++ b/qpid/cpp/src/qpid/Options.h @@ -0,0 +1,193 @@ +#ifndef QPID_COMMONOPTIONS_H +#define QPID_COMMONOPTIONS_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/Exception.h" + +// Disable warnings triggered by boost. +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4251 4275) +#endif + +#include <boost/program_options.hpp> +#include <boost/format.hpp> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#include <sstream> +#include <iterator> +#include <algorithm> +#include <string> +#include "qpid/CommonImportExport.h" + +namespace qpid { +namespace po=boost::program_options; + + + +///@internal +QPID_COMMON_EXTERN std::string prettyArg(const std::string&, const std::string&); + +/** @internal Normally only constructed by optValue() */ +template <class T> +class OptionValue : public po::typed_value<T> { + public: + OptionValue(T& value, const std::string& arg) + : po::typed_value<T>(&value), argName(arg) {} + std::string name() const { return argName; } + + private: + std::string argName; +}; + + +/** Create an option value. + * name, value appear after the option name in help like this: + * <name> (=<value>) + * T must support operator <<. + *@see Options for example of use. + */ +template<class T> +po::value_semantic* optValue(T& value, const char* name) { + std::string valstr(boost::lexical_cast<std::string>(value)); + return new OptionValue<T>(value, prettyArg(name, valstr)); +} + +/** Create a vector value. Multiple occurences of the option are + * accumulated into the vector + */ +template <class T> +po::value_semantic* optValue(std::vector<T>& value, const char* name) { + std::ostringstream os; + std::copy(value.begin(), value.end(), std::ostream_iterator<T>(os, " ")); + std::string val=os.str(); + if (!val.empty()) + val.erase(val.end()-1); // Remove trailing " " + return (new OptionValue<std::vector<T> >(value, prettyArg(name, val))); +} + +/** Create a boolean switch value. Presence of the option sets the value. */ +inline po::value_semantic* optValue(bool& value) { +#if (BOOST_VERSION >= 103500) + return (new OptionValue<bool>(value, ""))->implicit_value(true); +#else + return po::bool_switch(&value); +#endif +} + +inline po::value_semantic* pure_switch(bool& value) { + return po::bool_switch(&value); +} + +/** + * Base class for options. + * Example of use: + @code + struct MySubOptions : public Options { + int x; + string y; + MySubOptions() : Options("Sub options") { + addOptions() + ("x", optValue(x,"XUNIT"), "Option X") + ("y", optValue(y, "YUNIT"), "Option Y"); + } + }; + + struct MyOptions : public Options { + bool z; + vector<string> foo; + MySubOptions subOptions; + MyOptions() : Options("My Options") { + addOptions() + ("z", boolSwitch(z), "Option Z") + ("foo", optValue(foo), "Multiple option foo"); + add(subOptions); + } + + main(int argc, char** argv) { + Options opts; + opts.parse(argc, char** argv); + // Use values + dosomething(opts.subOptions.x); + if (error) + cout << opts << end; // Help message. + } + + @endcode + */ + + + + +struct Options : public po::options_description { + + struct Exception : public qpid::Exception { + Exception(const std::string& msg) : qpid::Exception(msg) {} + }; + + QPID_COMMON_EXTERN Options(const std::string& name=std::string()); + + /** + * Parses options from argc/argv, environment variables and config file. + * Note the filename argument can reference an options variable that + * is updated by argc/argv or environment variable parsing. + */ + QPID_COMMON_EXTERN void parse(int argc, char const* const* argv, + const std::string& configfile=std::string(), + bool allowUnknown = false); + + /** + * Tests for presence of argc/argv switch + */ + QPID_COMMON_EXTERN bool findArg(int argc, char const* const* argv, + const std::string& theArg); + + boost::program_options::options_description_easy_init addOptions() { + return add_options(); + } +}; + + + +/** + * Standard options for configuration + */ +struct CommonOptions : public Options { + QPID_COMMON_EXTERN CommonOptions(const std::string& name=std::string(), + const std::string& configfile=std::string(), + const std::string& clientConfigFile=std::string()); + bool help; + bool version; + std::string config; + std::string clientConfig; +}; + + + + +} // namespace qpid + +#endif /*!QPID_COMMONOPTIONS_H*/ diff --git a/qpid/cpp/src/qpid/RangeSet.h b/qpid/cpp/src/qpid/RangeSet.h new file mode 100644 index 0000000000..ef0ad032da --- /dev/null +++ b/qpid/cpp/src/qpid/RangeSet.h @@ -0,0 +1,328 @@ +#ifndef QPID_RANGESET_H +#define QPID_RANGESET_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/InlineVector.h" +#include <boost/iterator/iterator_facade.hpp> +#include <boost/operators.hpp> +#include <boost/bind.hpp> +#include <algorithm> +#include <numeric> + +namespace qpid { + +/** A range of values, used in RangeSet. + * Range(begin, end) includes begin but excludes end. + * Range::makeClosed(first,last) includes both first and last. + */ +template <class T> +class Range { + public: + static Range makeClosed(const T& first, T last) { return Range(first, ++last); } + + Range() : begin_(), end_() {} + explicit Range(const T& t) : begin_(t), end_(t) { ++end_; } + Range(const T& b, const T& e) : begin_(b), end_(e) { assert(b <= e); } + + T begin() const { return begin_; } + /** End of _open_ range, i.e. !contains(end()) */ + T end() const { return end_; } + + T first() const { assert(!empty()); return begin_; } + /** Last in closed range, i.e. contains(end()) */ + T last() const { assert(!empty()); T ret=end_; return --ret; } + + void begin(const T& t) { begin_ = t; } + void end(const T& t) { end_ = t; } + size_t size() const { return end_ - begin_; } + bool empty() const { return begin_ == end_; } + + bool contains(const T& x) const { return begin_ <= x && x < end_; } + bool contains(const Range& r) const { return begin_ <= r.begin_ && r.end_ <= end_; } + bool strictContains(const Range& r) const { return begin_ < r.begin_ && r.end_ < end_; } + + bool operator==(const Range& x) { return begin_ == x.begin_ && end_== x.end_; } + + bool operator<(const T& t) const { return end_ < t; } + bool operator<(const Range<T>& r) const { return end_ < r.begin_; } + + /** touching ranges can be merged into a single range. */ + bool touching(const Range& r) const { + return std::max(begin_, r.begin_) <= std::min(end_, r.end_); + } + + /** @pre touching */ + void merge(const Range& r) { + assert(touching(r)); + begin_ = std::min(begin_, r.begin_); + end_ = std::max(end_, r.end_); + } + + operator bool() const { return !empty(); } + + template <class S> void serialize(S& s) { s(begin_)(end_); } + + private: + T begin_, end_; +}; + + +/** + * A set implemented as a list of [begin, end) ranges. + * T must be LessThanComparable and Incrementable. + * RangeSet only provides const iterators. + */ +template <class T> +class RangeSet + : boost::additive1<RangeSet<T>, + boost::additive2<RangeSet<T>, Range<T>, + boost::additive2<RangeSet<T>, T> > > +{ + typedef InlineVector<Range<T>, 3> Ranges; // TODO aconway 2008-04-21: what's the optimial inlined value? + + public: + + class iterator : public boost::iterator_facade< + iterator, + const T, + boost::forward_traversal_tag> + { + public: + iterator() : ranges(), iter(), value() {} + + private: + typedef typename Ranges::const_iterator RangesIter; + iterator(const Ranges& r, const RangesIter& i, const T& t) + : ranges(&r), iter(i), value(t) {} + + void increment(); + bool equal(const iterator& i) const; + const T& dereference() const { return value; } + + const Ranges* ranges; + RangesIter iter; + T value; + + friend class RangeSet<T>; + friend class boost::iterator_core_access; + }; + + typedef iterator const_iterator; + + RangeSet() {} + explicit RangeSet(const Range<T>& r) { *this += r; } + RangeSet(const T& a, const T& b) { *this += Range<T>(a,b); } + + bool contiguous() const { return ranges.size() <= 1; } + + bool contains(const T& t) const; + bool contains(const Range<T>&) const; + + /**@pre contiguous() */ + Range<T> toRange() const; + + bool operator==(const RangeSet<T>&) const; + + void addRange (const Range<T>&); + void addSet (const RangeSet<T>&); + + RangeSet<T>& operator+=(const T& t) { return *this += Range<T>(t); } + RangeSet<T>& operator+=(const Range<T>& r) { addRange(r); return *this; } + RangeSet<T>& operator+=(const RangeSet<T>& s) { addSet(s); return *this; } + + void removeRange (const Range<T>&); + void removeSet (const RangeSet<T>&); + + RangeSet<T>& operator-=(const T& t) { return *this -= Range<T>(t); } + RangeSet<T>& operator-=(const Range<T>& r) { removeRange(r); return *this; } + RangeSet<T>& operator-=(const RangeSet<T>& s) { removeSet(s); return *this; } + + T front() const { return ranges.front().begin(); } + T back() const { return ranges.back().end(); } + + // Iterate over elements in the set. + iterator begin() const; + iterator end() const; + + // Iterate over ranges in the set. + typedef typename Ranges::const_iterator RangeIterator; + RangeIterator rangesBegin() const { return ranges.begin(); } + RangeIterator rangesEnd() const { return ranges.end(); } + size_t rangesSize() const { return ranges.size(); } + + // The difference between the start and end of this range set + uint32_t span() const; + + size_t size() const; + bool empty() const { return ranges.empty(); } + void clear() { ranges.clear(); } + + /** Return the largest contiguous range containing x. + * Returns the empty range [x,x) if x is not in the set. + */ + Range<T> rangeContaining(const T&) const; + + template <class S> void serialize(S& s) { s.split(*this); s(ranges.begin(), ranges.end()); } + template <class S> void encode(S& s) const { s(uint16_t(ranges.size()*sizeof(Range<T>))); } + template <class S> void decode(S& s) { uint16_t sz; s(sz); ranges.resize(sz/sizeof(Range<T>)); } + + private: + static size_t accumulateSize(size_t s, const Range<T>& r) { return s+r.size(); } + Ranges ranges; + + template <class U> friend std::ostream& operator<<(std::ostream& o, const RangeSet<U>& r); + + friend class iterator; +}; + +template <class T> +std::ostream& operator<<(std::ostream& o, const Range<T>& r) { + return o << "[" << r.begin() << "," << r.end() << ")"; +} + +template <class T> +std::ostream& operator<<(std::ostream& o, const RangeSet<T>& rs) { + std::ostream_iterator<Range<T> > i(o, " "); + o << "{ "; + std::copy(rs.ranges.begin(), rs.ranges.end(), i); + return o << "}"; +} + +template <class T> +bool RangeSet<T>::contains(const T& t) const { + typename Ranges::const_iterator i = + std::lower_bound(ranges.begin(), ranges.end(), Range<T>(t)); + return i != ranges.end() && i->contains(t); +} + +template <class T> +bool RangeSet<T>::contains(const Range<T>& r) const { + typename Ranges::const_iterator i = + std::lower_bound(ranges.begin(), ranges.end(), r); + return i != ranges.end() && i->contains(r); +} + +template <class T> void RangeSet<T>::addRange(const Range<T>& r) { + if (r.empty()) return; + typename Ranges::iterator i = std::lower_bound(ranges.begin(), ranges.end(), r); + if (i == ranges.end() || !i->touching(r)) + ranges.insert(i, r); // No overlap + else { + i->merge(r); + typename Ranges::iterator j = i; + while (++j != ranges.end() && i->touching(*j)) + i->merge(*j); + ranges.erase(i+1,j); + } +} + + +template <class T> void RangeSet<T>::addSet(const RangeSet<T>& s) { + typedef RangeSet<T>& (RangeSet<T>::*RangeSetRangeOp)(const Range<T>&); + std::for_each(s.ranges.begin(), s.ranges.end(), + boost::bind((RangeSetRangeOp)&RangeSet<T>::operator+=, this, _1)); +} + +template <class T> void RangeSet<T>::removeRange(const Range<T>& r) { + if (r.empty()) return; + typename Ranges::iterator i,j; + i = std::lower_bound(ranges.begin(), ranges.end(), r); + if (i == ranges.end() || i->begin() >= r.end()) + return; // Outside of set + if (*i == r) // Erase i + ranges.erase(i); + else if (i->strictContains(r)) { // Split i + Range<T> i1(i->begin(), r.begin()); + Range<T> i2(r.end(), i->end()); + *i = i2; + ranges.insert(i, i1); + } else { + if (i->begin() < r.begin()) { // Truncate i + i->end(r.begin()); + ++i; + } + for (j = i; j != ranges.end() && r.contains(*j); ++j) + ; // Ranges to erase. + if (j != ranges.end() && r.end() > j->begin()) + j->begin(r.end()); // Truncate j + ranges.erase(i,j); + } +} + +template <class T> void RangeSet<T>::removeSet(const RangeSet<T>& r) { + std::for_each( + r.ranges.begin(), r.ranges.end(), + boost::bind(&RangeSet<T>::removeRange, this, _1)); +} + +template <class T> Range<T> RangeSet<T>::toRange() const { + assert(contiguous()); + return empty() ? Range<T>() : ranges.front(); +} + +template <class T> void RangeSet<T>::iterator::increment() { + assert(ranges && iter != ranges->end()); + if (!iter->contains(++value)) { + ++iter; + if (iter == ranges->end()) + *this=iterator(); // end() iterator + else + value=iter->begin(); + } +} + +template <class T> bool RangeSet<T>::operator==(const RangeSet<T>& r) const { + return ranges.size() == r.ranges.size() && std::equal(ranges.begin(), ranges.end(), r.ranges.begin()); +} + +template <class T> typename RangeSet<T>::iterator RangeSet<T>::begin() const { + return empty() ? end() : iterator(ranges, ranges.begin(), front()); +} + +template <class T> typename RangeSet<T>::iterator RangeSet<T>::end() const { + return iterator(); +} + +template <class T> bool RangeSet<T>::iterator::equal(const iterator& i) const { + return ranges==i.ranges && (ranges==0 || value==i.value); +} + +template <class T> Range<T> RangeSet<T>::rangeContaining(const T& t) const { + typename Ranges::const_iterator i = + std::lower_bound(ranges.begin(), ranges.end(), Range<T>(t)); + return (i != ranges.end() && i->contains(t)) ? *i : Range<T>(t,t); +} + +template <class T> uint32_t RangeSet<T>::span() const { + if (ranges.empty()) return 0; + return ranges.back().last() - ranges.front().first(); +} + +template <class T> size_t RangeSet<T>::size() const { + return std::accumulate(rangesBegin(), rangesEnd(), 0, &RangeSet<T>::accumulateSize); +} + +} // namespace qpid + + +#endif /*!QPID_RANGESET_H*/ diff --git a/qpid/cpp/src/qpid/Sasl.h b/qpid/cpp/src/qpid/Sasl.h index efda92d718..1164fb5ec3 100644 --- a/qpid/cpp/src/qpid/Sasl.h +++ b/qpid/cpp/src/qpid/Sasl.h @@ -24,6 +24,7 @@ #include <memory> #include <string> +#include "qpid/CommonImportExport.h" #include "qpid/sys/IntegerTypes.h" namespace qpid { @@ -53,7 +54,7 @@ class Sasl virtual std::string getMechanism() = 0; virtual std::string getUserId() = 0; virtual std::auto_ptr<qpid::sys::SecurityLayer> getSecurityLayer(uint16_t maxFrameSize) = 0; - virtual ~Sasl() {} + QPID_COMMON_EXTERN virtual ~Sasl() {} }; } // namespace qpid diff --git a/qpid/cpp/src/qpid/SaslFactory.cpp b/qpid/cpp/src/qpid/SaslFactory.cpp index 97e1d6e18a..bd771fc920 100644 --- a/qpid/cpp/src/qpid/SaslFactory.cpp +++ b/qpid/cpp/src/qpid/SaslFactory.cpp @@ -20,6 +20,7 @@ */ #include "qpid/SaslFactory.h" #include "qpid/SaslServer.h" +#include "qpid/NullSaslClient.h" #include "qpid/NullSaslServer.h" #include <map> #include <string.h> @@ -48,7 +49,8 @@ SaslFactory& SaslFactory::getInstance() std::auto_ptr<Sasl> SaslFactory::create( const std::string &, const std::string &, const std::string &, const std::string &, int, int, bool ) { - return std::auto_ptr<Sasl>(); + std::auto_ptr<Sasl> client(new NullSaslClient); + return client; } std::auto_ptr<SaslServer> SaslFactory::createServer(const std::string& realm, bool /*encryptionRequired*/, const qpid::sys::SecuritySettings&) diff --git a/qpid/cpp/src/qpid/SaslFactory.h b/qpid/cpp/src/qpid/SaslFactory.h index da7e892f1d..5d99bd2e51 100644 --- a/qpid/cpp/src/qpid/SaslFactory.h +++ b/qpid/cpp/src/qpid/SaslFactory.h @@ -21,6 +21,7 @@ * under the License. * */ +#include "qpid/CommonImportExport.h" #include "qpid/Sasl.h" #include "qpid/sys/Mutex.h" #include <memory> diff --git a/qpid/cpp/src/qpid/SaslServer.h b/qpid/cpp/src/qpid/SaslServer.h index a707a468eb..88909c69a9 100644 --- a/qpid/cpp/src/qpid/SaslServer.h +++ b/qpid/cpp/src/qpid/SaslServer.h @@ -35,7 +35,7 @@ class SaslServer { public: typedef enum {OK, FAIL, CHALLENGE} Status; - virtual ~SaslServer() {} + QPID_COMMON_EXTERN virtual ~SaslServer() {} virtual Status start(const std::string& mechanism, const std::string* response, std::string& challenge) = 0; virtual Status step(const std::string* response, std::string& challenge) = 0; virtual std::string getMechanisms() = 0; diff --git a/qpid/cpp/src/qpid/SessionId.h b/qpid/cpp/src/qpid/SessionId.h new file mode 100644 index 0000000000..e18b360999 --- /dev/null +++ b/qpid/cpp/src/qpid/SessionId.h @@ -0,0 +1,60 @@ +#ifndef QPID_SESSIONID_H +#define QPID_SESSIONID_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 <boost/operators.hpp> +#include <string> +#include <qpid/CommonImportExport.h> + +namespace qpid { + +/** Identifier for a session. + * There are two parts to a session identifier: + * + * getUserId() returns the authentication principal associated with + * the session's connection. + * + * getName() returns the session name. + * + * The name must be unique among sessions with the same authentication + * principal. + */ +class SessionId : boost::totally_ordered1<SessionId> { + std::string userId; + std::string name; + public: + QPID_COMMON_EXTERN SessionId(const std::string& userId=std::string(), const std::string& name=std::string()); + std::string getUserId() const { return userId; } + std::string getName() const { return name; } + QPID_COMMON_EXTERN bool operator<(const SessionId&) const ; + QPID_COMMON_EXTERN bool operator==(const SessionId& id) const; + // Convert to a string + QPID_COMMON_EXTERN std::string str() const; +}; + +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SessionId&); + + +} // namespace qpid + +#endif /*!QPID_SESSIONID_H*/ diff --git a/qpid/cpp/src/qpid/Url.h b/qpid/cpp/src/qpid/Url.h new file mode 100644 index 0000000000..f9ed87c24b --- /dev/null +++ b/qpid/cpp/src/qpid/Url.h @@ -0,0 +1,96 @@ +#ifndef QPID_URL_H +#define QPID_URL_H + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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/Address.h" +#include "qpid/Exception.h" +#include <string> +#include <vector> +#include <new> +#include <ostream> +#include "qpid/CommonImportExport.h" + +namespace qpid { + +/** An AMQP URL contains a list of addresses */ +struct Url : public std::vector<Address> { + + struct Invalid : public Exception { QPID_COMMON_EXTERN Invalid(const std::string& s); }; + + /** Convert to string form. */ + QPID_COMMON_EXTERN std::string str() const; + + /** Empty URL. */ + Url() {} + + /** URL containing a single address */ + explicit Url(const Address& addr) { push_back(addr); } + + /** Parse url, throw Invalid if invalid. */ + explicit Url(const std::string& url) { parse(url.c_str()); } + /** Parse url, throw Invalid if invalid. */ + explicit Url(const std::string& url, const std::string& defaultProtocol) { parse(url.c_str(), defaultProtocol); } + + /** Parse url, throw Invalid if invalid. */ + explicit Url(const char* url) { parse(url); } + + Url& operator=(const char* s) { parse(s); return *this; } + Url& operator=(const std::string& s) { parse(s); return *this; } + + /** Throw Invalid if the URL does not contain any addresses. */ + QPID_COMMON_EXTERN void throwIfEmpty() const; + + /** Replace contents with parsed url + *@exception Invalid if the url is invalid. + */ + QPID_COMMON_EXTERN void parse(const char* url); + QPID_COMMON_EXTERN void parse(const char* url, const std::string& defaultProtocol); + QPID_COMMON_INLINE_EXTERN void parse(const std::string& url) { parse(url.c_str()); } + + /** Replace contesnts with parsed URL. Replace with empty URL if invalid. */ + QPID_COMMON_EXTERN void parseNoThrow(const char* url); + QPID_COMMON_EXTERN void parseNoThrow(const char* url, const std::string& defaultProtocol); + + /** Add a protocol tag to be recognzed in URLs. + * Only for use by protcol plug-in initializers. + */ + QPID_COMMON_EXTERN static void addProtocol(const std::string& tag); + + QPID_COMMON_EXTERN void setUser(const std::string&); + QPID_COMMON_EXTERN void setPass(const std::string&); + QPID_COMMON_EXTERN std::string getUser() const; + QPID_COMMON_EXTERN std::string getPass() const; + + private: + mutable std::string cache; // cache string form for efficiency. + std::string user, pass; + + friend class UrlParser; +}; + +inline bool operator==(const Url& a, const Url& b) { return a.str()==b.str(); } +inline bool operator!=(const Url& a, const Url& b) { return a.str()!=b.str(); } + +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const Url& url); +QPID_COMMON_EXTERN std::istream& operator>>(std::istream& is, Url& url); + +} // namespace qpid + +#endif /*!QPID_URL_H*/ diff --git a/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp b/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp index 3d703066b4..7a5d0ab53d 100644 --- a/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp +++ b/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp @@ -102,10 +102,12 @@ bool ConnectionCounter::countConnectionLH( if (eRef != theMap.end()) { count = (uint16_t)(*eRef).second + 1; (*eRef).second = count; - result = (enforceLimit ? count <= theLimit : true); } else { theMap[theName] = count = 1; } + if (enforceLimit) { + result = count <= theLimit; + } if (emitLog) { QPID_LOG(trace, "ACL ConnectionApprover user=" << theName << " limit=" << theLimit diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp deleted file mode 100644 index a48789973a..0000000000 --- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp +++ /dev/null @@ -1,1434 +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 "qpid/management/Manageable.h" -#include "qpid/management/ManagementObject.h" -#include "qpid/log/Statement.h" -#include "qpid/agent/ManagementAgentImpl.h" -#include "qpid/amqp_0_10/Codecs.h" -#include <list> -#include <string.h> -#include <stdlib.h> -#include <sys/types.h> -#include <iostream> -#include <fstream> -#include <boost/lexical_cast.hpp> - -namespace qpid { -namespace management { - -using namespace qpid::client; -using namespace qpid::framing; -using namespace qpid::sys; -using namespace std; -using std::stringstream; -using std::ofstream; -using std::ifstream; -using std::string; -using std::endl; -using qpid::types::Variant; -using qpid::amqp_0_10::MapCodec; -using qpid::amqp_0_10::ListCodec; - -namespace { - qpid::sys::Mutex lock; - bool disabled = false; - ManagementAgent* agent = 0; - int refCount = 0; - - const string defaultVendorName("vendor"); - const string defaultProductName("product"); - - // Create a valid binding key substring by - // replacing all '.' chars with '_' - const string keyifyNameStr(const string& name) - { - string n2 = name; - - size_t pos = n2.find('.'); - while (pos != n2.npos) { - n2.replace(pos, 1, "_"); - pos = n2.find('.', pos); - } - return n2; - } -} - -ManagementAgent::Singleton::Singleton(bool disableManagement) -{ - sys::Mutex::ScopedLock _lock(lock); - if (disableManagement && !disabled) { - disabled = true; - assert(refCount == 0); // can't disable after agent has been allocated - } - if (refCount == 0 && !disabled) - agent = new ManagementAgentImpl(); - refCount++; -} - -ManagementAgent::Singleton::~Singleton() -{ - sys::Mutex::ScopedLock _lock(lock); - refCount--; - if (refCount == 0 && !disabled) { - delete agent; - agent = 0; - } -} - -ManagementAgent* ManagementAgent::Singleton::getInstance() -{ - return agent; -} - -const string ManagementAgentImpl::storeMagicNumber("MA02"); - -ManagementAgentImpl::ManagementAgentImpl() : - interval(10), extThread(false), pipeHandle(0), notifyCallback(0), notifyContext(0), - notifyable(0), inCallback(false), - initialized(false), connected(false), useMapMsg(false), lastFailure("never connected"), - topicExchange("qmf.default.topic"), directExchange("qmf.default.direct"), - schemaTimestamp(Duration(EPOCH, now())), - publishAllData(true), requestedBrokerBank(0), requestedAgentBank(0), - assignedBrokerBank(0), assignedAgentBank(0), bootSequence(0), - maxV2ReplyObjs(10), // KAG todo: make this a tuneable parameter - connThreadBody(*this), connThread(connThreadBody), - pubThreadBody(*this), pubThread(pubThreadBody) -{ -} - -ManagementAgentImpl::~ManagementAgentImpl() -{ - // shutdown & cleanup all threads - connThreadBody.close(); - pubThreadBody.close(); - - connThread.join(); - pubThread.join(); - - if (pipeHandle) { - delete pipeHandle; - pipeHandle = 0; - } -} - -void ManagementAgentImpl::setName(const string& vendor, const string& product, const string& instance) -{ - if (vendor.find(':') != vendor.npos) { - throw Exception("vendor string cannot contain a ':' character."); - } - if (product.find(':') != product.npos) { - throw Exception("product string cannot contain a ':' character."); - } - - attrMap["_vendor"] = vendor; - attrMap["_product"] = product; - if (!instance.empty()) { - attrMap["_instance"] = instance; - } -} - - -void ManagementAgentImpl::getName(string& vendor, string& product, string& instance) -{ - vendor = std::string(attrMap["_vendor"]); - product = std::string(attrMap["_product"]); - instance = std::string(attrMap["_instance"]); -} - - -const std::string& ManagementAgentImpl::getAddress() -{ - return name_address; -} - - -void ManagementAgentImpl::init(const string& brokerHost, - uint16_t brokerPort, - uint16_t intervalSeconds, - bool useExternalThread, - const string& _storeFile, - const string& uid, - const string& pwd, - const string& mech, - const string& proto) -{ - management::ConnectionSettings settings; - settings.protocol = proto; - settings.host = brokerHost; - settings.port = brokerPort; - settings.username = uid; - settings.password = pwd; - settings.mechanism = mech; - settings.heartbeat = 10; - init(settings, intervalSeconds, useExternalThread, _storeFile); -} - -void ManagementAgentImpl::init(const qpid::management::ConnectionSettings& settings, - uint16_t intervalSeconds, - bool useExternalThread, - const string& _storeFile) -{ - std::string cfgVendor, cfgProduct, cfgInstance; - - interval = intervalSeconds; - extThread = useExternalThread; - storeFile = _storeFile; - nextObjectId = 1; - - // - // Convert from management::ConnectionSettings to client::ConnectionSettings - // - connectionSettings.protocol = settings.protocol; - connectionSettings.host = settings.host; - connectionSettings.port = settings.port; - connectionSettings.virtualhost = settings.virtualhost; - connectionSettings.username = settings.username; - connectionSettings.password = settings.password; - connectionSettings.mechanism = settings.mechanism; - connectionSettings.locale = settings.locale; - connectionSettings.heartbeat = settings.heartbeat; - connectionSettings.maxChannels = settings.maxChannels; - connectionSettings.maxFrameSize = settings.maxFrameSize; - connectionSettings.bounds = settings.bounds; - connectionSettings.tcpNoDelay = settings.tcpNoDelay; - connectionSettings.service = settings.service; - connectionSettings.minSsf = settings.minSsf; - connectionSettings.maxSsf = settings.maxSsf; - - retrieveData(cfgVendor, cfgProduct, cfgInstance); - - bootSequence++; - if ((bootSequence & 0xF000) != 0) - bootSequence = 1; - - // setup the agent's name. The name may be set via a call to setName(). If setName() - // has not been called, the name can be read from the configuration file. If there is - // no name in the configuration file, a unique default name is provided. - if (attrMap.empty()) { - // setName() never called by application, so use names retrieved from config, otherwise defaults. - setName(cfgVendor.empty() ? defaultVendorName : cfgVendor, - cfgProduct.empty() ? defaultProductName : cfgProduct, - cfgInstance.empty() ? qpid::types::Uuid(true).str() : cfgInstance); - } else if (attrMap.find("_instance") == attrMap.end()) { - // setName() called, but instance was not specified, use config or generate a uuid - setName(attrMap["_vendor"].asString(), attrMap["_product"].asString(), - cfgInstance.empty() ? qpid::types::Uuid(true).str() : cfgInstance); - } - - name_address = attrMap["_vendor"].asString() + ":" + attrMap["_product"].asString() + ":" + attrMap["_instance"].asString(); - vendorNameKey = keyifyNameStr(attrMap["_vendor"].asString()); - productNameKey = keyifyNameStr(attrMap["_product"].asString()); - instanceNameKey = keyifyNameStr(attrMap["_instance"].asString()); - attrMap["_name"] = name_address; - - storeData(true); - - QPID_LOG(info, "QMF Agent Initialized: broker=" << settings.host << ":" << settings.port << - " interval=" << intervalSeconds << " storeFile=" << _storeFile << " name=" << name_address); - - initialized = true; -} - -void ManagementAgentImpl::registerClass(const string& packageName, - const string& className, - uint8_t* md5Sum, - ManagementObject::writeSchemaCall_t schemaCall) -{ - sys::Mutex::ScopedLock lock(agentLock); - PackageMap::iterator pIter = findOrAddPackage(packageName); - addClassLocal(ManagementItem::CLASS_KIND_TABLE, pIter, className, md5Sum, schemaCall); -} - -void ManagementAgentImpl::registerEvent(const string& packageName, - const string& eventName, - uint8_t* md5Sum, - ManagementObject::writeSchemaCall_t schemaCall) -{ - sys::Mutex::ScopedLock lock(agentLock); - PackageMap::iterator pIter = findOrAddPackage(packageName); - addClassLocal(ManagementItem::CLASS_KIND_EVENT, pIter, eventName, md5Sum, schemaCall); -} - -// old-style add object: 64bit id - deprecated -ObjectId ManagementAgentImpl::addObject(ManagementObject* object, - uint64_t persistId) -{ - std::string key; - if (persistId) { - key = boost::lexical_cast<std::string>(persistId); - } - return addObject(object, key, persistId != 0); -} - - -// new style add object - use this approach! -ObjectId ManagementAgentImpl::addObject(ManagementObject* object, - const std::string& key, - bool persistent) -{ - sys::Mutex::ScopedLock lock(addLock); - - uint16_t sequence = persistent ? 0 : bootSequence; - - ObjectId objectId(&attachment, 0, sequence); - if (key.empty()) - objectId.setV2Key(*object); // let object generate the key - else - objectId.setV2Key(key); - objectId.setAgentName(name_address); - - object->setObjectId(objectId); - newManagementObjects[objectId] = boost::shared_ptr<ManagementObject>(object); - return objectId; -} - - -void ManagementAgentImpl::raiseEvent(const ManagementEvent& event, severity_t severity) -{ - static const std::string severityStr[] = { - "emerg", "alert", "crit", "error", "warn", - "note", "info", "debug" - }; - string content; - stringstream key; - Variant::Map headers; - - { - sys::Mutex::ScopedLock lock(agentLock); - Buffer outBuffer(eventBuffer, MA_BUFFER_SIZE); - uint8_t sev = (severity == SEV_DEFAULT) ? event.getSeverity() : (uint8_t) severity; - - // key << "console.event." << assignedBrokerBank << "." << assignedAgentBank << "." << - // event.getPackageName() << "." << event.getEventName(); - key << "agent.ind.event." << keyifyNameStr(event.getPackageName()) - << "." << keyifyNameStr(event.getEventName()) - << "." << severityStr[sev] - << "." << vendorNameKey - << "." << productNameKey - << "." << instanceNameKey; - - Variant::Map map_; - Variant::Map schemaId; - Variant::Map values; - - map_["_schema_id"] = mapEncodeSchemaId(event.getPackageName(), - event.getEventName(), - event.getMd5Sum(), - ManagementItem::CLASS_KIND_EVENT); - event.mapEncode(values); - map_["_values"] = values; - map_["_timestamp"] = uint64_t(Duration(EPOCH, now())); - map_["_severity"] = sev; - - headers["method"] = "indication"; - headers["qmf.opcode"] = "_data_indication"; - headers["qmf.content"] = "_event"; - headers["qmf.agent"] = name_address; - - Variant::List list; - list.push_back(map_); - ListCodec::encode(list, content); - } - - connThreadBody.sendBuffer(content, "", headers, topicExchange, key.str(), "amqp/list"); -} - -uint32_t ManagementAgentImpl::pollCallbacks(uint32_t callLimit) -{ - sys::Mutex::ScopedLock lock(agentLock); - - if (inCallback) { - QPID_LOG(critical, "pollCallbacks invoked from the agent's thread!"); - return 0; - } - - for (uint32_t idx = 0; callLimit == 0 || idx < callLimit; idx++) { - if (methodQueue.empty()) - break; - - QueuedMethod* item = methodQueue.front(); - methodQueue.pop_front(); - { - sys::Mutex::ScopedUnlock unlock(agentLock); - invokeMethodRequest(item->body, item->cid, item->replyToExchange, item->replyToKey, item->userId); - delete item; - } - } - - if (pipeHandle != 0) { - char rbuf[100]; - while (pipeHandle->read(rbuf, 100) > 0) ; // Consume all signaling bytes - } - return methodQueue.size(); -} - -int ManagementAgentImpl::getSignalFd() -{ - if (extThread) { - if (pipeHandle == 0) - pipeHandle = new PipeHandle(true); - return pipeHandle->getReadHandle(); - } - - return -1; -} - -void ManagementAgentImpl::setSignalCallback(cb_t callback, void* context) -{ - sys::Mutex::ScopedLock lock(agentLock); - notifyCallback = callback; - notifyContext = context; -} - -void ManagementAgentImpl::setSignalCallback(Notifyable& _notifyable) -{ - sys::Mutex::ScopedLock lock(agentLock); - notifyable = &_notifyable; -} - -void ManagementAgentImpl::startProtocol() -{ - sendHeartbeat(); - { - sys::Mutex::ScopedLock lock(agentLock); - publishAllData = true; - } -} - -void ManagementAgentImpl::storeData(bool requested) -{ - if (!storeFile.empty()) { - ofstream outFile(storeFile.c_str()); - uint32_t brokerBankToWrite = requested ? requestedBrokerBank : assignedBrokerBank; - uint32_t agentBankToWrite = requested ? requestedAgentBank : assignedAgentBank; - - if (outFile.good()) { - outFile << storeMagicNumber << " " << brokerBankToWrite << " " << - agentBankToWrite << " " << bootSequence << endl; - - if (attrMap.find("_vendor") != attrMap.end()) - outFile << "vendor=" << attrMap["_vendor"] << endl; - if (attrMap.find("_product") != attrMap.end()) - outFile << "product=" << attrMap["_product"] << endl; - if (attrMap.find("_instance") != attrMap.end()) - outFile << "instance=" << attrMap["_instance"] << endl; - - outFile.close(); - } - } -} - -void ManagementAgentImpl::retrieveData(std::string& vendor, std::string& product, std::string& inst) -{ - vendor.clear(); - product.clear(); - inst.clear(); - - if (!storeFile.empty()) { - ifstream inFile(storeFile.c_str()); - string mn; - - if (inFile.good()) { - inFile >> mn; - if (mn == storeMagicNumber) { - std::string inText; - - inFile >> requestedBrokerBank; - inFile >> requestedAgentBank; - inFile >> bootSequence; - - while (inFile.good()) { - std::getline(inFile, inText); - if (!inText.compare(0, 7, "vendor=")) { - vendor = inText.substr(7); - QPID_LOG(debug, "read vendor name [" << vendor << "] from configuration file."); - } else if (!inText.compare(0, 8, "product=")) { - product = inText.substr(8); - QPID_LOG(debug, "read product name [" << product << "] from configuration file."); - } else if (!inText.compare(0, 9, "instance=")) { - inst = inText.substr(9); - QPID_LOG(debug, "read instance name [" << inst << "] from configuration file."); - } - } - } - inFile.close(); - } - } -} - -void ManagementAgentImpl::sendHeartbeat() -{ - static const string addr_key_base("agent.ind.heartbeat."); - - Variant::Map map; - Variant::Map headers; - string content; - std::stringstream addr_key; - - addr_key << addr_key_base << vendorNameKey - << "." << productNameKey - << "." << instanceNameKey; - - headers["method"] = "indication"; - headers["qmf.opcode"] = "_agent_heartbeat_indication"; - headers["qmf.agent"] = name_address; - - getHeartbeatContent(map); - MapCodec::encode(map, content); - - // Set TTL (in msecs) on outgoing heartbeat indications based on the interval - // time to prevent stale heartbeats from getting to the consoles. - - connThreadBody.sendBuffer(content, "", headers, topicExchange, addr_key.str(), - "amqp/map", interval * 2 * 1000); - - QPID_LOG(trace, "SENT AgentHeartbeat name=" << name_address); -} - -void ManagementAgentImpl::sendException(const string& rte, const string& rtk, const string& cid, - const string& text, uint32_t code) -{ - Variant::Map map; - Variant::Map headers; - Variant::Map values; - string content; - - headers["method"] = "indication"; - headers["qmf.opcode"] = "_exception"; - headers["qmf.agent"] = name_address; - - values["error_code"] = code; - values["error_text"] = text; - map["_values"] = values; - - MapCodec::encode(map, content); - connThreadBody.sendBuffer(content, cid, headers, rte, rtk); - - QPID_LOG(trace, "SENT Exception code=" << code <<" text=" << text); -} - -void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, const string& rte, const string& rtk) -{ - string packageName; - SchemaClassKey key; - uint32_t outLen(0); - char localBuffer[MA_BUFFER_SIZE]; - Buffer outBuffer(localBuffer, MA_BUFFER_SIZE); - bool found(false); - - inBuffer.getShortString(packageName); - inBuffer.getShortString(key.name); - inBuffer.getBin128(key.hash); - - QPID_LOG(trace, "RCVD SchemaRequest: package=" << packageName << " class=" << key.name); - - { - sys::Mutex::ScopedLock lock(agentLock); - PackageMap::iterator pIter = packages.find(packageName); - if (pIter != packages.end()) { - ClassMap& cMap = pIter->second; - ClassMap::iterator cIter = cMap.find(key); - if (cIter != cMap.end()) { - SchemaClass& schema = cIter->second; - string body; - - encodeHeader(outBuffer, 's', sequence); - schema.writeSchemaCall(body); - outBuffer.putRawData(body); - outLen = MA_BUFFER_SIZE - outBuffer.available(); - outBuffer.reset(); - found = true; - } - } - } - - if (found) { - connThreadBody.sendBuffer(outBuffer, outLen, rte, rtk); - QPID_LOG(trace, "SENT SchemaInd: package=" << packageName << " class=" << key.name); - } -} - -void ManagementAgentImpl::handleConsoleAddedIndication() -{ - sys::Mutex::ScopedLock lock(agentLock); - publishAllData = true; - - QPID_LOG(trace, "RCVD ConsoleAddedInd"); -} - -void ManagementAgentImpl::invokeMethodRequest(const string& body, const string& cid, const string& rte, const string& rtk, const string& userId) -{ - string methodName; - bool failed = false; - Variant::Map inMap; - Variant::Map outMap; - Variant::Map::const_iterator oid, mid; - string content; - - MapCodec::decode(body, inMap); - - if ((oid = inMap.find("_object_id")) == inMap.end() || - (mid = inMap.find("_method_name")) == inMap.end()) { - sendException(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_PARAMETER_INVALID), - Manageable::STATUS_PARAMETER_INVALID); - failed = true; - } else { - string methodName; - ObjectId objId; - Variant::Map inArgs; - Variant::Map callMap; - - try { - // conversions will throw if input is invalid. - objId = ObjectId(oid->second.asMap()); - methodName = mid->second.getString(); - - mid = inMap.find("_arguments"); - if (mid != inMap.end()) { - inArgs = (mid->second).asMap(); - } - - QPID_LOG(trace, "Invoking Method: name=" << methodName << " args=" << inArgs); - - boost::shared_ptr<ManagementObject> oPtr; - { - sys::Mutex::ScopedLock lock(agentLock); - ObjectMap::iterator iter = managementObjects.find(objId); - if (iter != managementObjects.end() && !iter->second->isDeleted()) - oPtr = iter->second; - } - - if (oPtr.get() == 0) { - sendException(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_UNKNOWN_OBJECT), - Manageable::STATUS_UNKNOWN_OBJECT); - failed = true; - } else { - oPtr->doMethod(methodName, inArgs, callMap, userId); - - if (callMap["_status_code"].asUint32() == 0) { - outMap["_arguments"] = Variant::Map(); - for (Variant::Map::const_iterator iter = callMap.begin(); - iter != callMap.end(); iter++) - if (iter->first != "_status_code" && iter->first != "_status_text") - outMap["_arguments"].asMap()[iter->first] = iter->second; - } else { - sendException(rte, rtk, cid, callMap["_status_text"], callMap["_status_code"]); - failed = true; - } - } - - } catch(types::InvalidConversion& e) { - sendException(rte, rtk, cid, e.what(), Manageable::STATUS_EXCEPTION); - failed = true; - } - } - - if (!failed) { - Variant::Map headers; - headers["method"] = "response"; - headers["qmf.agent"] = name_address; - headers["qmf.opcode"] = "_method_response"; - QPID_LOG(trace, "SENT MethodResponse map=" << outMap); - MapCodec::encode(outMap, content); - connThreadBody.sendBuffer(content, cid, headers, rte, rtk); - } -} - -void ManagementAgentImpl::handleGetQuery(const string& body, const string& cid, const string& rte, const string& rtk) -{ - { - sys::Mutex::ScopedLock lock(agentLock); - moveNewObjectsLH(lock); - } - - Variant::Map inMap; - Variant::Map::const_iterator i; - Variant::Map headers; - - MapCodec::decode(body, inMap); - QPID_LOG(trace, "RCVD GetQuery: map=" << inMap << " cid=" << cid); - - headers["method"] = "response"; - headers["qmf.opcode"] = "_query_response"; - headers["qmf.agent"] = name_address; - headers["partial"] = Variant(); - - Variant::List list_; - Variant::Map map_; - Variant::Map values; - Variant::Map oidMap; - string content; - - /* - * Unpack the _what element of the query. Currently we only support OBJECT queries. - */ - i = inMap.find("_what"); - if (i == inMap.end()) { - sendException(rte, rtk, cid, "_what element missing in Query"); - return; - } - - if (i->second.getType() != qpid::types::VAR_STRING) { - sendException(rte, rtk, cid, "_what element is not a string"); - return; - } - - if (i->second.asString() == "OBJECT") { - headers["qmf.content"] = "_data"; - /* - * Unpack the _object_id element of the query if it is present. If it is present, find that one - * object and return it. If it is not present, send a class-based result. - */ - i = inMap.find("_object_id"); - if (i != inMap.end() && i->second.getType() == qpid::types::VAR_MAP) { - ObjectId objId(i->second.asMap()); - boost::shared_ptr<ManagementObject> object; - - { - sys::Mutex::ScopedLock lock(agentLock); - ObjectMap::iterator iter = managementObjects.find(objId); - if (iter != managementObjects.end()) - object = iter->second; - } - - if (object.get() != 0) { - if (object->getConfigChanged() || object->getInstChanged()) - object->setUpdateTime(); - - object->mapEncodeValues(values, true, true); // write both stats and properties - objId.mapEncode(oidMap); - map_["_values"] = values; - map_["_object_id"] = oidMap; - object->writeTimestamps(map_); - map_["_schema_id"] = mapEncodeSchemaId(object->getPackageName(), - object->getClassName(), - object->getMd5Sum()); - list_.push_back(map_); - headers.erase("partial"); - - ListCodec::encode(list_, content); - connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list"); - QPID_LOG(trace, "SENT QueryResponse (query by object_id) to=" << rte << "/" << rtk); - return; - } - } else { // match using schema_id, if supplied - - string className; - string packageName; - - i = inMap.find("_schema_id"); - if (i != inMap.end() && i->second.getType() == qpid::types::VAR_MAP) { - const Variant::Map& schemaIdMap(i->second.asMap()); - - Variant::Map::const_iterator s_iter = schemaIdMap.find("_class_name"); - if (s_iter != schemaIdMap.end() && s_iter->second.getType() == qpid::types::VAR_STRING) - className = s_iter->second.asString(); - - s_iter = schemaIdMap.find("_package_name"); - if (s_iter != schemaIdMap.end() && s_iter->second.getType() == qpid::types::VAR_STRING) - packageName = s_iter->second.asString(); - - typedef list<boost::shared_ptr<ManagementObject> > StageList; - StageList staging; - - { - sys::Mutex::ScopedLock lock(agentLock); - for (ObjectMap::iterator iter = managementObjects.begin(); - iter != managementObjects.end(); - iter++) { - ManagementObject* object = iter->second.get(); - if (object->getClassName() == className && - (packageName.empty() || object->getPackageName() == packageName)) - staging.push_back(iter->second); - } - } - - unsigned int objCount = 0; - for (StageList::iterator iter = staging.begin(); iter != staging.end(); iter++) { - ManagementObject* object = iter->get(); - if (object->getClassName() == className && - (packageName.empty() || object->getPackageName() == packageName)) { - - values.clear(); - oidMap.clear(); - map_.clear(); - - if (object->getConfigChanged() || object->getInstChanged()) - object->setUpdateTime(); - - object->mapEncodeValues(values, true, true); // write both stats and properties - object->getObjectId().mapEncode(oidMap); - map_["_values"] = values; - map_["_object_id"] = oidMap; - object->writeTimestamps(map_); - map_["_schema_id"] = mapEncodeSchemaId(object->getPackageName(), - object->getClassName(), - object->getMd5Sum()); - list_.push_back(map_); - - if (++objCount >= maxV2ReplyObjs) { - objCount = 0; - ListCodec::encode(list_, content); - connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list"); - QPID_LOG(trace, "SENT QueryResponse (query by schema_id) to=" << rte << "/" << rtk); - content.clear(); - list_.clear(); - } - } - } - } - } - - // Send last "non-partial" message to indicate CommandComplete - headers.erase("partial"); - ListCodec::encode(list_, content); - connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list"); - QPID_LOG(trace, "SENT QueryResponse (last message, no 'partial' indicator) to=" << rte << "/" << rtk); - - } else if (i->second.asString() == "SCHEMA_ID") { - headers["qmf.content"] = "_schema_id"; - /** - * @todo - support for a predicate. For now, send a list of all known schema class keys. - */ - for (PackageMap::iterator pIter = packages.begin(); - pIter != packages.end(); pIter++) { - for (ClassMap::iterator cIter = pIter->second.begin(); - cIter != pIter->second.end(); cIter++) { - - list_.push_back(mapEncodeSchemaId( pIter->first, - cIter->first.name, - cIter->first.hash, - cIter->second.kind )); - } - } - - headers.erase("partial"); - ListCodec::encode(list_, content); - connThreadBody.sendBuffer(content, cid, headers, rte, rtk, "amqp/list"); - QPID_LOG(trace, "SENT QueryResponse (SchemaId) to=" << rte << "/" << rtk); - - } else { - // Unknown query target - sendException(rte, rtk, cid, "Query for _what => '" + i->second.asString() + "' not supported"); - } -} - -void ManagementAgentImpl::handleLocateRequest(const string&, const string& cid, const string& rte, const string& rtk) -{ - QPID_LOG(trace, "RCVD AgentLocateRequest"); - - Variant::Map map; - Variant::Map headers; - string content; - - headers["method"] = "indication"; - headers["qmf.opcode"] = "_agent_locate_response"; - headers["qmf.agent"] = name_address; - - getHeartbeatContent(map); - MapCodec::encode(map, content); - connThreadBody.sendBuffer(content, cid, headers, rte, rtk); - - QPID_LOG(trace, "SENT AgentLocateResponse replyTo=" << rte << "/" << rtk); - - { - sys::Mutex::ScopedLock lock(agentLock); - publishAllData = true; - } -} - -void ManagementAgentImpl::handleMethodRequest(const string& body, const string& cid, const string& rte, const string& rtk, const string& userId) -{ - if (extThread) { - sys::Mutex::ScopedLock lock(agentLock); - - methodQueue.push_back(new QueuedMethod(cid, rte, rtk, body, userId)); - if (pipeHandle != 0) { - pipeHandle->write("X", 1); - } else if (notifyable != 0) { - inCallback = true; - { - sys::Mutex::ScopedUnlock unlock(agentLock); - notifyable->notify(); - } - inCallback = false; - } else if (notifyCallback != 0) { - inCallback = true; - { - sys::Mutex::ScopedUnlock unlock(agentLock); - notifyCallback(notifyContext); - } - inCallback = false; - } - } else { - invokeMethodRequest(body, cid, rte, rtk, userId); - } - - QPID_LOG(trace, "RCVD MethodRequest"); -} - -void ManagementAgentImpl::received(Message& msg) -{ - string replyToExchange; - string replyToKey; - framing::MessageProperties mp = msg.getMessageProperties(); - if (mp.hasReplyTo()) { - const framing::ReplyTo& rt = mp.getReplyTo(); - replyToExchange = rt.getExchange(); - replyToKey = rt.getRoutingKey(); - } - - string userId; - if (mp.hasUserId()) - userId = mp.getUserId(); - - if (mp.hasAppId() && mp.getAppId() == "qmf2") - { - string opcode = mp.getApplicationHeaders().getAsString("qmf.opcode"); - string cid = msg.getMessageProperties().getCorrelationId(); - - if (opcode == "_agent_locate_request") handleLocateRequest(msg.getData(), cid, replyToExchange, replyToKey); - else if (opcode == "_method_request") handleMethodRequest(msg.getData(), cid, replyToExchange, replyToKey, userId); - else if (opcode == "_query_request") handleGetQuery(msg.getData(), cid, replyToExchange, replyToKey); - else { - QPID_LOG(warning, "Support for QMF V2 Opcode [" << opcode << "] TBD!!!"); - } - return; - } - - // old preV2 binary messages - - uint32_t sequence; - string data = msg.getData(); - Buffer inBuffer(const_cast<char*>(data.c_str()), data.size()); - uint8_t opcode; - - - if (checkHeader(inBuffer, &opcode, &sequence)) - { - if (opcode == 'S') handleSchemaRequest(inBuffer, sequence, replyToExchange, replyToKey); - else if (opcode == 'x') handleConsoleAddedIndication(); - else - QPID_LOG(warning, "Ignoring old-format QMF Request! opcode=" << char(opcode)); - } -} - - -void ManagementAgentImpl::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq) -{ - buf.putOctet('A'); - buf.putOctet('M'); - buf.putOctet('2'); - buf.putOctet(opcode); - buf.putLong (seq); -} - -Variant::Map ManagementAgentImpl::mapEncodeSchemaId(const string& pname, - const string& cname, - const uint8_t *md5Sum, - uint8_t type) -{ - Variant::Map map_; - - map_["_package_name"] = pname; - map_["_class_name"] = cname; - map_["_hash"] = types::Uuid(md5Sum); - if (type == ManagementItem::CLASS_KIND_EVENT) - map_["_type"] = "_event"; - else - map_["_type"] = "_data"; - - return map_; -} - - -bool ManagementAgentImpl::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq) -{ - if (buf.getSize() < 8) - return false; - - uint8_t h1 = buf.getOctet(); - uint8_t h2 = buf.getOctet(); - uint8_t h3 = buf.getOctet(); - - *opcode = buf.getOctet(); - *seq = buf.getLong(); - - return h1 == 'A' && h2 == 'M' && h3 == '2'; -} - -ManagementAgentImpl::PackageMap::iterator ManagementAgentImpl::findOrAddPackage(const string& name) -{ - PackageMap::iterator pIter = packages.find(name); - if (pIter != packages.end()) - return pIter; - - // No such package found, create a new map entry. - pair<PackageMap::iterator, bool> result = - packages.insert(pair<string, ClassMap>(name, ClassMap())); - - return result.first; -} - -// note well: caller must hold agentLock when calling this! -void ManagementAgentImpl::moveNewObjectsLH(const sys::Mutex::ScopedLock& /*agentLock*/) -{ - sys::Mutex::ScopedLock lock(addLock); - ObjectMap::iterator newObj = newManagementObjects.begin(); - while (newObj != newManagementObjects.end()) { - // before adding a new mgmt object, check for duplicates: - ObjectMap::iterator oldObj = managementObjects.find(newObj->first); - if (oldObj == managementObjects.end()) { - managementObjects[newObj->first] = newObj->second; - newManagementObjects.erase(newObj++); // post inc iterator safe! - } else { - // object exists with same object id. This may be legit, for example, when a - // recently deleted object is re-added before the mgmt poll runs. - if (newObj->second->isDeleted()) { - // @TODO fixme: we missed an add-delete for the new object - QPID_LOG(warning, "Mgmt Object deleted before update sent, oid=" << newObj->first); - newManagementObjects.erase(newObj++); // post inc iterator safe! - } else if (oldObj->second->isDeleted()) { - // skip adding newObj, try again later once oldObj has been cleaned up by poll - ++newObj; - } else { - // real bad - two objects exist with same OID. This is a bug in the application - QPID_LOG(error, "Detected two Mgmt Objects using the same object id! oid=" << newObj->first - << ", this is bad!"); - // what to do here? Can't erase an active obj - owner has a pointer to it. - // for now I punt. Maybe the flood of log messages will get someone's attention :P - ++newObj; - } - } - } -} - -void ManagementAgentImpl::addClassLocal(uint8_t classKind, - PackageMap::iterator pIter, - const string& className, - uint8_t* md5Sum, - ManagementObject::writeSchemaCall_t schemaCall) -{ - SchemaClassKey key; - ClassMap& cMap = pIter->second; - - key.name = className; - memcpy(&key.hash, md5Sum, 16); - - ClassMap::iterator cIter = cMap.find(key); - if (cIter != cMap.end()) - return; - - // No such class found, create a new class with local information. - cMap.insert(pair<SchemaClassKey, SchemaClass>(key, SchemaClass(schemaCall, classKind))); - schemaTimestamp = Duration(EPOCH, now()); - QPID_LOG(trace, "Updated schema timestamp, now=" << uint64_t(schemaTimestamp)); -} - -void ManagementAgentImpl::encodePackageIndication(Buffer& buf, - PackageMap::iterator pIter) -{ - buf.putShortString((*pIter).first); - - QPID_LOG(trace, "SENT PackageInd: package=" << (*pIter).first); -} - -void ManagementAgentImpl::encodeClassIndication(Buffer& buf, - PackageMap::iterator pIter, - ClassMap::iterator cIter) -{ - SchemaClassKey key = (*cIter).first; - - buf.putOctet((*cIter).second.kind); - buf.putShortString((*pIter).first); - buf.putShortString(key.name); - buf.putBin128(key.hash); - - QPID_LOG(trace, "SENT ClassInd: package=" << (*pIter).first << " class=" << key.name); -} - -struct MessageItem { - string content; - Variant::Map headers; - string key; - MessageItem(const Variant::Map& h, const string& k) : headers(h), key(k) {} -}; - -void ManagementAgentImpl::periodicProcessing() -{ - string addr_key_base = "agent.ind.data."; - list<ObjectId> deleteList; - list<boost::shared_ptr<MessageItem> > message_list; - - sendHeartbeat(); - - { - sys::Mutex::ScopedLock lock(agentLock); - - if (!connected) - return; - - moveNewObjectsLH(lock); - - // - // Clear the been-here flag on all objects in the map. - // - for (ObjectMap::iterator iter = managementObjects.begin(); - iter != managementObjects.end(); - iter++) { - ManagementObject* object = iter->second.get(); - object->setFlags(0); - if (publishAllData) { - object->setForcePublish(true); - } - } - - publishAllData = false; - - // - // Process the entire object map. - // - uint32_t v2Objs = 0; - - for (ObjectMap::iterator baseIter = managementObjects.begin(); - baseIter != managementObjects.end(); - baseIter++) { - ManagementObject* baseObject = baseIter->second.get(); - - // - // Skip until we find a base object requiring a sent message. - // - if (baseObject->getFlags() == 1 || - (!baseObject->getConfigChanged() && - !baseObject->getInstChanged() && - !baseObject->getForcePublish() && - !baseObject->isDeleted())) - continue; - - std::string packageName = baseObject->getPackageName(); - std::string className = baseObject->getClassName(); - - Variant::List list_; - std::stringstream addr_key; - Variant::Map headers; - - addr_key << addr_key_base; - addr_key << keyifyNameStr(packageName) - << "." << keyifyNameStr(className) - << "." << vendorNameKey - << "." << productNameKey - << "." << instanceNameKey; - - headers["method"] = "indication"; - headers["qmf.opcode"] = "_data_indication"; - headers["qmf.content"] = "_data"; - headers["qmf.agent"] = name_address; - - for (ObjectMap::iterator iter = baseIter; - iter != managementObjects.end(); - iter++) { - ManagementObject* object = iter->second.get(); - bool send_stats, send_props; - if (baseObject->isSameClass(*object) && object->getFlags() == 0) { - object->setFlags(1); - if (object->getConfigChanged() || object->getInstChanged()) - object->setUpdateTime(); - - send_props = (object->getConfigChanged() || object->getForcePublish() || object->isDeleted()); - send_stats = (object->hasInst() && (object->getInstChanged() || object->getForcePublish())); - - if (send_stats || send_props) { - Variant::Map map_; - Variant::Map values; - Variant::Map oid; - - object->getObjectId().mapEncode(oid); - map_["_object_id"] = oid; - map_["_schema_id"] = mapEncodeSchemaId(object->getPackageName(), - object->getClassName(), - object->getMd5Sum()); - object->writeTimestamps(map_); - object->mapEncodeValues(values, send_props, send_stats); - map_["_values"] = values; - list_.push_back(map_); - - if (++v2Objs >= maxV2ReplyObjs) { - v2Objs = 0; - boost::shared_ptr<MessageItem> item(new MessageItem(headers, addr_key.str())); - ListCodec::encode(list_, item->content); - message_list.push_back(item); - list_.clear(); - } - } - - if (object->isDeleted()) - deleteList.push_back(iter->first); - object->setForcePublish(false); - } - } - - if (!list_.empty()) { - boost::shared_ptr<MessageItem> item(new MessageItem(headers, addr_key.str())); - ListCodec::encode(list_, item->content); - message_list.push_back(item); - } - } - - // Delete flagged objects - for (list<ObjectId>::reverse_iterator iter = deleteList.rbegin(); - iter != deleteList.rend(); - iter++) - managementObjects.erase(*iter); - } - - while (!message_list.empty()) { - boost::shared_ptr<MessageItem> item(message_list.front()); - message_list.pop_front(); - connThreadBody.sendBuffer(item->content, "", item->headers, topicExchange, item->key, "amqp/list"); - QPID_LOG(trace, "SENT DataIndication"); - } -} - - -void ManagementAgentImpl::getHeartbeatContent(qpid::types::Variant::Map& map) -{ - map["_values"] = attrMap; - map["_values"].asMap()["_timestamp"] = uint64_t(Duration(EPOCH, now())); - map["_values"].asMap()["_heartbeat_interval"] = interval; - map["_values"].asMap()["_epoch"] = bootSequence; - map["_values"].asMap()["_schema_updated"] = uint64_t(schemaTimestamp); -} - -void ManagementAgentImpl::ConnectionThread::run() -{ - static const int delayMin(1); - static const int delayMax(128); - static const int delayFactor(2); - int delay(delayMin); - string dest("qmfagent"); - ConnectionThread::shared_ptr tmp; - - sessionId.generate(); - queueName << "qmfagent-" << sessionId; - - while (true) { - try { - if (agent.initialized) { - QPID_LOG(debug, "QMF Agent attempting to connect to the broker..."); - connection.open(agent.connectionSettings); - session = connection.newSession(queueName.str()); - subscriptions.reset(new client::SubscriptionManager(session)); - - session.queueDeclare(arg::queue=queueName.str(), arg::autoDelete=true, - arg::exclusive=true); - session.exchangeBind(arg::exchange="amq.direct", arg::queue=queueName.str(), - arg::bindingKey=queueName.str()); - session.exchangeBind(arg::exchange=agent.directExchange, arg::queue=queueName.str(), - arg::bindingKey=agent.name_address); - session.exchangeBind(arg::exchange=agent.topicExchange, arg::queue=queueName.str(), - arg::bindingKey="console.#"); - - subscriptions->subscribe(agent, queueName.str(), dest); - QPID_LOG(info, "Connection established with broker"); - { - sys::Mutex::ScopedLock _lock(connLock); - if (shutdown) - return; - operational = true; - agent.connected = true; - agent.startProtocol(); - try { - sys::Mutex::ScopedUnlock _unlock(connLock); - subscriptions->run(); - } catch (exception) {} - - QPID_LOG(warning, "Connection to the broker has been lost"); - - operational = false; - agent.connected = false; - tmp = subscriptions; - subscriptions.reset(); - } - tmp.reset(); // frees the subscription outside the lock - delay = delayMin; - connection.close(); - } - } catch (exception &e) { - if (delay < delayMax) - delay *= delayFactor; - QPID_LOG(debug, "Connection failed: exception=" << e.what()); - } - - { - // 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 - sys::Mutex::ScopedLock _lock(connLock); - if (shutdown) - return; - sleeping = true; - int totalSleep = 0; - do { - sys::Mutex::ScopedUnlock _unlock(connLock); - qpid::sys::sleep(delayMin); - totalSleep += delayMin; - } while (totalSleep < delay && !shutdown); - sleeping = false; - if (shutdown) - return; - } - } -} - -ManagementAgentImpl::ConnectionThread::~ConnectionThread() -{ -} - -void ManagementAgentImpl::ConnectionThread::sendBuffer(Buffer& buf, - uint32_t length, - const string& exchange, - const string& routingKey) -{ - Message msg; - string data; - - buf.getRawData(data, length); - msg.setData(data); - sendMessage(msg, exchange, routingKey); -} - - - -void ManagementAgentImpl::ConnectionThread::sendBuffer(const string& data, - const string& cid, - const Variant::Map headers, - const string& exchange, - const string& routingKey, - const string& contentType, - uint64_t ttl_msec) -{ - Message msg; - Variant::Map::const_iterator i; - - if (!cid.empty()) - msg.getMessageProperties().setCorrelationId(cid); - - if (!contentType.empty()) - msg.getMessageProperties().setContentType(contentType); - - if (ttl_msec) - msg.getDeliveryProperties().setTtl(ttl_msec); - - for (i = headers.begin(); i != headers.end(); ++i) { - msg.getHeaders().setString(i->first, i->second.asString()); - } - - msg.setData(data); - sendMessage(msg, exchange, routingKey); -} - - - - - -void ManagementAgentImpl::ConnectionThread::sendMessage(Message msg, - const string& exchange, - const string& routingKey) -{ - ConnectionThread::shared_ptr s; - { - sys::Mutex::ScopedLock _lock(connLock); - if (!operational) - return; - s = subscriptions; - } - - msg.getDeliveryProperties().setRoutingKey(routingKey); - msg.getMessageProperties().setReplyTo(ReplyTo("amq.direct", queueName.str())); - msg.getMessageProperties().getApplicationHeaders().setString("qmf.agent", agent.name_address); - msg.getMessageProperties().setAppId("qmf2"); - try { - session.messageTransfer(arg::content=msg, arg::destination=exchange); - } catch(exception& e) { - QPID_LOG(error, "Exception caught in sendMessage: " << e.what()); - // Bounce the connection - if (s) - s->stop(); - } -} - - - -void ManagementAgentImpl::ConnectionThread::bindToBank(uint32_t brokerBank, uint32_t agentBank) -{ - stringstream key; - key << "agent." << brokerBank << "." << agentBank; - session.exchangeBind(arg::exchange="qpid.management", arg::queue=queueName.str(), - arg::bindingKey=key.str()); -} - -void ManagementAgentImpl::ConnectionThread::close() -{ - ConnectionThread::shared_ptr s; - { - sys::Mutex::ScopedLock _lock(connLock); - shutdown = true; - s = subscriptions; - } - if (s) - s->stop(); -} - -bool ManagementAgentImpl::ConnectionThread::isSleeping() const -{ - sys::Mutex::ScopedLock _lock(connLock); - return sleeping; -} - - -void ManagementAgentImpl::PublishThread::run() -{ - uint16_t totalSleep; - uint16_t sleepTime; - - while (!shutdown) { - agent.periodicProcessing(); - totalSleep = 0; - - // - // Calculate a sleep time that is no greater than 5 seconds and - // no less than 1 second. - // - sleepTime = agent.getInterval(); - if (sleepTime > 5) - sleepTime = 5; - else if (sleepTime == 0) - sleepTime = 1; - - while (totalSleep < agent.getInterval() && !shutdown) { - qpid::sys::sleep(sleepTime); - totalSleep += sleepTime; - } - } -} - -}} - diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h deleted file mode 100644 index 4c97bc89da..0000000000 --- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.h +++ /dev/null @@ -1,294 +0,0 @@ -#ifndef _qpid_agent_ManagementAgentImpl_ -#define _qpid_agent_ManagementAgentImpl_ - -// -// 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/agent/ManagementAgent.h" -#include "qpid/client/Connection.h" -#include "qpid/client/ConnectionSettings.h" -#include "qpid/client/SubscriptionManager.h" -#include "qpid/client/Session.h" -#include "qpid/client/AsyncSession.h" -#include "qpid/client/Message.h" -#include "qpid/client/MessageListener.h" -#include "qpid/sys/Thread.h" -#include "qpid/sys/Runnable.h" -#include "qpid/sys/Mutex.h" -#include "qpid/sys/PipeHandle.h" -#include "qpid/sys/Time.h" -#include "qpid/framing/Uuid.h" -#include <iostream> -#include <sstream> -#include <deque> - -namespace qpid { -namespace management { - -class ManagementAgentImpl : public ManagementAgent, public client::MessageListener -{ - public: - - ManagementAgentImpl(); - virtual ~ManagementAgentImpl(); - - // - // Methods from ManagementAgent - // - int getMaxThreads() { return 1; } - void setName(const std::string& vendor, - const std::string& product, - const std::string& instance=""); - void getName(std::string& vendor, std::string& product, std::string& instance); - const std::string& getAddress(); - void init(const std::string& brokerHost = "localhost", - uint16_t brokerPort = 5672, - uint16_t intervalSeconds = 10, - bool useExternalThread = false, - const std::string& storeFile = "", - const std::string& uid = "", - const std::string& pwd = "", - const std::string& mech = "PLAIN", - const std::string& proto = "tcp"); - void init(const management::ConnectionSettings& settings, - uint16_t intervalSeconds = 10, - bool useExternalThread = false, - const std::string& storeFile = ""); - bool isConnected() { return connected; } - std::string& getLastFailure() { return lastFailure; } - void registerClass(const std::string& packageName, - const std::string& className, - uint8_t* md5Sum, - management::ManagementObject::writeSchemaCall_t schemaCall); - void registerEvent(const std::string& packageName, - const std::string& eventName, - uint8_t* md5Sum, - management::ManagementObject::writeSchemaCall_t schemaCall); - ObjectId addObject(management::ManagementObject* objectPtr, uint64_t persistId = 0); - ObjectId addObject(management::ManagementObject* objectPtr, const std::string& key, - bool persistent); - void raiseEvent(const management::ManagementEvent& event, severity_t severity = SEV_DEFAULT); - uint32_t pollCallbacks(uint32_t callLimit = 0); - int getSignalFd(); - void setSignalCallback(cb_t callback, void* context); - void setSignalCallback(Notifyable& n); - - uint16_t getInterval() { return interval; } - void periodicProcessing(); - - uint16_t getBootSequence(void) { return bootSequence; } - void setBootSequence(uint16_t b) { bootSequence = b; } - - private: - - struct SchemaClassKey { - std::string name; - uint8_t hash[16]; - }; - - struct SchemaClassKeyComp { - bool operator() (const SchemaClassKey& lhs, const SchemaClassKey& rhs) const - { - if (lhs.name != rhs.name) - return lhs.name < rhs.name; - else - for (int i = 0; i < 16; i++) - if (lhs.hash[i] != rhs.hash[i]) - return lhs.hash[i] < rhs.hash[i]; - return false; - } - }; - - struct SchemaClass { - management::ManagementObject::writeSchemaCall_t writeSchemaCall; - uint8_t kind; - - SchemaClass(const management::ManagementObject::writeSchemaCall_t call, - const uint8_t _kind) : writeSchemaCall(call), kind(_kind) {} - }; - - struct QueuedMethod { - QueuedMethod(const std::string& _cid, const std::string& _rte, const std::string& _rtk, const std::string& _body, const std::string& _uid) : - cid(_cid), replyToExchange(_rte), replyToKey(_rtk), body(_body), userId(_uid) {} - - std::string cid; - std::string replyToExchange; - std::string replyToKey; - std::string body; - std::string userId; - }; - - typedef std::deque<QueuedMethod*> MethodQueue; - typedef std::map<SchemaClassKey, SchemaClass, SchemaClassKeyComp> ClassMap; - typedef std::map<std::string, ClassMap> PackageMap; - - PackageMap packages; - AgentAttachment attachment; - - typedef std::map<ObjectId, boost::shared_ptr<ManagementObject> > ObjectMap; - - ObjectMap managementObjects; - ObjectMap newManagementObjects; - MethodQueue methodQueue; - - void received (client::Message& msg); - - qpid::types::Variant::Map attrMap; - std::string name_address; - std::string vendorNameKey; // vendor name with "." --> "_" - std::string productNameKey; // product name with "." --> "_" - std::string instanceNameKey; // agent instance with "." --> "_" - uint16_t interval; - bool extThread; - sys::PipeHandle* pipeHandle; - uint64_t nextObjectId; - cb_t notifyCallback; - void* notifyContext; - Notifyable* notifyable; - bool inCallback; - std::string storeFile; - sys::Mutex agentLock; - sys::Mutex addLock; - framing::Uuid systemId; - client::ConnectionSettings connectionSettings; - bool initialized; - bool connected; - bool useMapMsg; - std::string lastFailure; - std::string topicExchange; - std::string directExchange; - qpid::sys::Duration schemaTimestamp; - - bool publishAllData; - uint32_t requestedBrokerBank; - uint32_t requestedAgentBank; - uint32_t assignedBrokerBank; - uint32_t assignedAgentBank; - uint16_t bootSequence; - - // Maximum # of objects allowed in a single V2 response - // message. - uint32_t maxV2ReplyObjs; - - static const uint8_t DEBUG_OFF = 0; - static const uint8_t DEBUG_CONN = 1; - static const uint8_t DEBUG_PROTO = 2; - static const uint8_t DEBUG_PUBLISH = 3; - -# define MA_BUFFER_SIZE 65536 - char outputBuffer[MA_BUFFER_SIZE]; - char eventBuffer[MA_BUFFER_SIZE]; - - 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; - ConnectionThread::shared_ptr subscriptions; - std::stringstream queueName; - mutable sys::Mutex connLock; - bool shutdown; - bool sleeping; - void run(); - public: - ConnectionThread(ManagementAgentImpl& _agent) : - operational(false), agent(_agent), - shutdown(false), sleeping(false) {} - ~ConnectionThread(); - void sendBuffer(qpid::framing::Buffer& buf, - uint32_t length, - const std::string& exchange, - const std::string& routingKey); - void sendBuffer(const std::string& data, - const std::string& cid, - const qpid::types::Variant::Map headers, - const std::string& exchange, - const std::string& routingKey, - const std::string& contentType="amqp/map", - uint64_t ttl_msec=0); - void sendMessage(qpid::client::Message msg, - const std::string& exchange, - const std::string& routingKey); - void bindToBank(uint32_t brokerBank, uint32_t agentBank); - void close(); - bool isSleeping() const; - }; - - class PublishThread : public sys::Runnable - { - ManagementAgentImpl& agent; - void run(); - bool shutdown; - public: - PublishThread(ManagementAgentImpl& _agent) : - agent(_agent), shutdown(false) {} - void close() { shutdown = true; } - }; - - ConnectionThread connThreadBody; - sys::Thread connThread; - PublishThread pubThreadBody; - sys::Thread pubThread; - - static const std::string storeMagicNumber; - - void startProtocol(); - void storeData(bool requested=false); - void retrieveData(std::string& vendor, std::string& product, std::string& inst); - PackageMap::iterator findOrAddPackage(const std::string& name); - void moveNewObjectsLH(const sys::Mutex::ScopedLock& agentLock); - void addClassLocal (uint8_t classKind, - PackageMap::iterator pIter, - const std::string& className, - uint8_t* md5Sum, - management::ManagementObject::writeSchemaCall_t schemaCall); - void encodePackageIndication (framing::Buffer& buf, - PackageMap::iterator pIter); - void encodeClassIndication (framing::Buffer& buf, - PackageMap::iterator pIter, - ClassMap::iterator cIter); - void encodeHeader (framing::Buffer& buf, uint8_t opcode, uint32_t seq = 0); - qpid::types::Variant::Map mapEncodeSchemaId(const std::string& pname, - const std::string& cname, - const uint8_t *md5Sum, - uint8_t type=ManagementItem::CLASS_KIND_TABLE); - bool checkHeader (framing::Buffer& buf, uint8_t *opcode, uint32_t *seq); - void sendHeartbeat(); - void sendException(const std::string& replyToExchange, const std::string& replyToKey, const std::string& cid, - const std::string& text, uint32_t code=1); - void handlePackageRequest (qpid::framing::Buffer& inBuffer); - void handleClassQuery (qpid::framing::Buffer& inBuffer); - void handleSchemaRequest (qpid::framing::Buffer& inBuffer, uint32_t sequence, const std::string& rte, const std::string& rtk); - void invokeMethodRequest (const std::string& body, const std::string& cid, const std::string& rte, const std::string& rtk, const std::string& userId); - - void handleGetQuery (const std::string& body, const std::string& cid, const std::string& rte, const std::string& rtk); - void handleLocateRequest (const std::string& body, const std::string& sequence, const std::string& rte, const std::string& rtk); - void handleMethodRequest (const std::string& body, const std::string& sequence, const std::string& rte, const std::string& rtk, const std::string& userId); - void handleConsoleAddedIndication(); - void getHeartbeatContent (qpid::types::Variant::Map& map); -}; - -}} - -#endif /*!_qpid_agent_ManagementAgentImpl_*/ diff --git a/qpid/cpp/src/qpid/amqp/DataBuilder.cpp b/qpid/cpp/src/qpid/amqp/DataBuilder.cpp new file mode 100644 index 0000000000..91c9393457 --- /dev/null +++ b/qpid/cpp/src/qpid/amqp/DataBuilder.cpp @@ -0,0 +1,194 @@ +/* + * + * 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 "DataBuilder.h" +#include "CharSequence.h" +#include "qpid/log/Statement.h" +#include "qpid/types/encodings.h" + +namespace qpid { +namespace amqp { + +void DataBuilder::onNull(const Descriptor*) +{ + handle(qpid::types::Variant()); +} +void DataBuilder::onBoolean(bool v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onUByte(uint8_t v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onUShort(uint16_t v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onUInt(uint32_t v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onULong(uint64_t v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onByte(int8_t v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onShort(int16_t v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onInt(int32_t v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onLong(int64_t v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onFloat(float v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onDouble(double v, const Descriptor*) +{ + handle(v); +} +void DataBuilder::onUuid(const CharSequence& v, const Descriptor*) +{ + if (v.size == qpid::types::Uuid::SIZE) { + handle(qpid::types::Uuid(v.data)); + } +} +void DataBuilder::onTimestamp(int64_t v, const Descriptor*) +{ + handle(v); +} + +void DataBuilder::handle(const qpid::types::Variant& v) +{ + switch (nested.top()->getType()) { + case qpid::types::VAR_MAP: + nested.push(&nested.top()->asMap()[v.asString()]); + break; + case qpid::types::VAR_LIST: + nested.top()->asList().push_back(v); + break; + default: + *(nested.top()) = v; + nested.pop(); + break; + } +} + +void DataBuilder::onBinary(const CharSequence& v, const Descriptor*) +{ + onString(std::string(v.data, v.size), qpid::types::encodings::BINARY); +} +void DataBuilder::onString(const CharSequence& v, const Descriptor*) +{ + onString(std::string(v.data, v.size), qpid::types::encodings::UTF8); +} +void DataBuilder::onSymbol(const CharSequence& v, const Descriptor*) +{ + onString(std::string(v.data, v.size), qpid::types::encodings::ASCII); +} + +void DataBuilder::onString(const std::string& value, const std::string& encoding) +{ + switch (nested.top()->getType()) { + case qpid::types::VAR_MAP: + nested.push(&nested.top()->asMap()[value]); + break; + case qpid::types::VAR_LIST: + nested.top()->asList().push_back(qpid::types::Variant(value)); + nested.top()->asList().back().setEncoding(encoding); + break; + default: + qpid::types::Variant& v = *(nested.top()); + v = value; + v.setEncoding(encoding); + nested.pop(); + break; + } +} + +bool DataBuilder::proceed() +{ + return !nested.empty(); +} + +bool DataBuilder::nest(const qpid::types::Variant& n) +{ + switch (nested.top()->getType()) { + case qpid::types::VAR_MAP: + QPID_LOG(error, QPID_MSG("Expecting map key; got " << n)); + break; + case qpid::types::VAR_LIST: + nested.top()->asList().push_back(n); + nested.push(&nested.top()->asList().back()); + break; + default: + qpid::types::Variant& value = *(nested.top()); + value = n; + nested.pop(); + nested.push(&value); + break; + } + return true; +} + +bool DataBuilder::onStartList(uint32_t, const CharSequence&, const CharSequence&, const Descriptor*) +{ + return nest(qpid::types::Variant::List()); +} +void DataBuilder::onEndList(uint32_t /*count*/, const Descriptor*) +{ + nested.pop(); +} +bool DataBuilder::onStartMap(uint32_t /*count*/, const CharSequence&, const CharSequence&, const Descriptor*) +{ + return nest(qpid::types::Variant::Map()); +} +void DataBuilder::onEndMap(uint32_t /*count*/, const Descriptor*) +{ + nested.pop(); +} +bool DataBuilder::onStartArray(uint32_t count, const CharSequence&, const Constructor&, const Descriptor*) +{ + return onStartList(count, CharSequence::create(), CharSequence::create(), 0); +} +void DataBuilder::onEndArray(uint32_t count, const Descriptor*) +{ + onEndList(count, 0); +} +qpid::types::Variant& DataBuilder::getValue() +{ + return base; +} +DataBuilder::DataBuilder(qpid::types::Variant v) : base(v) +{ + nested.push(&base); +} +DataBuilder::~DataBuilder() {} +}} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/DataBuilder.h b/qpid/cpp/src/qpid/amqp/DataBuilder.h new file mode 100644 index 0000000000..51ee3da5f8 --- /dev/null +++ b/qpid/cpp/src/qpid/amqp/DataBuilder.h @@ -0,0 +1,79 @@ +#ifndef QPID_AMQP_DATABUILDER_H +#define QPID_AMQP_DATABUILDER_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 "Reader.h" +#include "qpid/types/Variant.h" +#include "qpid/CommonImportExport.h" +#include <stack> + +namespace qpid { +namespace amqp { + +/** + * Utility to build a Variant based structure (or value) from a data stream + */ +class DataBuilder : public Reader +{ + public: + QPID_COMMON_EXTERN DataBuilder(qpid::types::Variant); + QPID_COMMON_EXTERN virtual ~DataBuilder(); + QPID_COMMON_EXTERN void onNull(const Descriptor*); + QPID_COMMON_EXTERN void onBoolean(bool, const Descriptor*); + QPID_COMMON_EXTERN void onUByte(uint8_t, const Descriptor*); + QPID_COMMON_EXTERN void onUShort(uint16_t, const Descriptor*); + QPID_COMMON_EXTERN void onUInt(uint32_t, const Descriptor*); + QPID_COMMON_EXTERN void onULong(uint64_t, const Descriptor*); + QPID_COMMON_EXTERN void onByte(int8_t, const Descriptor*); + QPID_COMMON_EXTERN void onShort(int16_t, const Descriptor*); + QPID_COMMON_EXTERN void onInt(int32_t, const Descriptor*); + QPID_COMMON_EXTERN void onLong(int64_t, const Descriptor*); + QPID_COMMON_EXTERN void onFloat(float, const Descriptor*); + QPID_COMMON_EXTERN void onDouble(double, const Descriptor*); + QPID_COMMON_EXTERN void onUuid(const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN void onTimestamp(int64_t, const Descriptor*); + + QPID_COMMON_EXTERN void onBinary(const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN void onString(const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN void onSymbol(const CharSequence&, const Descriptor*); + + QPID_COMMON_EXTERN bool onStartList(uint32_t /*count*/, const CharSequence&, const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN bool onStartMap(uint32_t /*count*/, const CharSequence&, const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN bool onStartArray(uint32_t /*count*/, const CharSequence&, const Constructor&, const Descriptor*); + QPID_COMMON_EXTERN void onEndList(uint32_t /*count*/, const Descriptor*); + QPID_COMMON_EXTERN void onEndMap(uint32_t /*count*/, const Descriptor*); + QPID_COMMON_EXTERN void onEndArray(uint32_t /*count*/, const Descriptor*); + + QPID_COMMON_EXTERN bool proceed(); + QPID_COMMON_EXTERN qpid::types::Variant& getValue(); + private: + qpid::types::Variant base; + std::stack<qpid::types::Variant*> nested; + std::string key; + + void handle(const qpid::types::Variant& v); + bool nest(const qpid::types::Variant& v); + void onString(const std::string&, const std::string&); +}; +}} // namespace qpid::amqp + +#endif /*!QPID_AMQP_DATABUILDER_H*/ diff --git a/qpid/cpp/src/qpid/amqp/Decoder.cpp b/qpid/cpp/src/qpid/amqp/Decoder.cpp index 1d5abc99c7..1058f83e38 100644 --- a/qpid/cpp/src/qpid/amqp/Decoder.cpp +++ b/qpid/cpp/src/qpid/amqp/Decoder.cpp @@ -22,6 +22,7 @@ #include "qpid/amqp/CharSequence.h" #include "qpid/amqp/Constructor.h" #include "qpid/amqp/Descriptor.h" +#include "qpid/amqp/MapBuilder.h" #include "qpid/amqp/Reader.h" #include "qpid/amqp/typecodes.h" #include "qpid/types/Uuid.h" @@ -34,121 +35,13 @@ namespace amqp { using namespace qpid::amqp::typecodes; -Decoder::Decoder(const char* d, size_t s) : start(d), size(s), position(0) {} +Decoder::Decoder(const char* d, size_t s) : start(d), size(s), position(0), current(0) {} -namespace { -class MapBuilder : public Reader -{ - public: - void onNull(const Descriptor*) - { - qpid::types::Variant v; - handle(v, NULL_NAME); - } - void onBoolean(bool v, const Descriptor*) - { - handle(v, BOOLEAN_NAME); - } - void onUByte(uint8_t v, const Descriptor*) - { - handle(v, UBYTE_NAME); - } - void onUShort(uint16_t v, const Descriptor*) - { - handle(v, USHORT_NAME); - } - void onUInt(uint32_t v, const Descriptor*) - { - handle(v, UINT_NAME); - } - void onULong(uint64_t v, const Descriptor*) - { - handle(v, ULONG_NAME); - } - void onByte(int8_t v, const Descriptor*) - { - handle(v, BYTE_NAME); - } - void onShort(int16_t v, const Descriptor*) - { - handle(v, SHORT_NAME); - } - void onInt(int32_t v, const Descriptor*) - { - handle(v, INT_NAME); - } - void onLong(int64_t v, const Descriptor*) - { - handle(v, LONG_NAME); - } - void onFloat(float v, const Descriptor*) - { - handle(v, FLOAT_NAME); - } - void onDouble(double v, const Descriptor*) - { - handle(v, DOUBLE_NAME); - } - void onUuid(const CharSequence& v, const Descriptor*) - { - handle(v, UUID_NAME); - } - void onTimestamp(int64_t v, const Descriptor*) - { - handle(v, TIMESTAMP_NAME); - } - void onBinary(const CharSequence& v, const Descriptor*) - { - handle(v); - } - void onString(const CharSequence& v, const Descriptor*) - { - handle(v); - } - void onSymbol(const CharSequence& v, const Descriptor*) - { - handle(v); - } - MapBuilder(qpid::types::Variant::Map& m) : map(m), state(KEY) {} - private: - qpid::types::Variant::Map& map; - enum {KEY, SKIP, VALUE} state; - std::string key; - - template <typename T> void handle(T value, const std::string& name) - { - switch (state) { - case KEY: - QPID_LOG(warning, "Ignoring key of type " << name); - state = SKIP; - break; - case VALUE: - map[key] = value; - case SKIP: - state = KEY; - break; - } - } - void handle(const CharSequence& value) - { - switch (state) { - case KEY: - key = value.str(); - state = VALUE; - break; - case VALUE: - map[key] = value.str(); - case SKIP: - state = KEY; - break; - } - } -}; -} void Decoder::readMap(qpid::types::Variant::Map& map) { - MapBuilder builder(map); + MapBuilder builder; read(builder); + map = builder.getMap(); } qpid::types::Variant::Map Decoder::readMap() @@ -168,6 +61,7 @@ void Decoder::read(Reader& reader) void Decoder::readOne(Reader& reader) { const char* temp = start + position; + current = position; Constructor c = readConstructor(); if (c.isDescribed) reader.onDescriptor(c.descriptor, temp); readValue(reader, c.code, c.isDescribed ? &c.descriptor : 0); @@ -263,7 +157,7 @@ void Decoder::readValue(Reader& reader, uint8_t code, const Descriptor* descript break; case LIST0: - reader.onStartList(0, CharSequence::create(), descriptor); + reader.onStartList(0, CharSequence::create(), getCurrent(0), descriptor); reader.onEndList(0, descriptor); break; case LIST8: @@ -333,7 +227,7 @@ void Decoder::readArray32(Reader& reader, const Descriptor* descriptor) void Decoder::readList(Reader& reader, uint32_t size, uint32_t count, const Descriptor* descriptor) { - if (reader.onStartList(count, CharSequence::create(data(), size), descriptor)) { + if (reader.onStartList(count, CharSequence::create(data(), size), getCurrent(size), descriptor)) { for (uint32_t i = 0; i < count; ++i) { readOne(reader); } @@ -345,7 +239,7 @@ void Decoder::readList(Reader& reader, uint32_t size, uint32_t count, const Desc } void Decoder::readMap(Reader& reader, uint32_t size, uint32_t count, const Descriptor* descriptor) { - if (reader.onStartMap(count, CharSequence::create(data(), size), descriptor)) { + if (reader.onStartMap(count, CharSequence::create(data(), size), getCurrent(size), descriptor)) { for (uint32_t i = 0; i < count; ++i) { readOne(reader); } @@ -401,7 +295,7 @@ Descriptor Decoder::readDescriptor() case ULONG_ZERO: return Descriptor((uint64_t) 0); default: - throw qpid::Exception(QPID_MSG("Expected descriptor of type ulong or symbol; found " << code)); + throw qpid::Exception(QPID_MSG("Expected descriptor of type ulong or symbol; found " << (int)code)); } } @@ -542,4 +436,10 @@ CharSequence Decoder::readRawUuid() size_t Decoder::getPosition() const { return position; } size_t Decoder::getSize() const { return size; } void Decoder::resetSize(size_t s) { size = s; } + +CharSequence Decoder::getCurrent(size_t remaining) const +{ + return CharSequence::create(start + current, (position-current)+remaining); +} + }} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/Decoder.h b/qpid/cpp/src/qpid/amqp/Decoder.h index 7ddfe0f17f..a78518be2b 100644 --- a/qpid/cpp/src/qpid/amqp/Decoder.h +++ b/qpid/cpp/src/qpid/amqp/Decoder.h @@ -77,6 +77,7 @@ class Decoder const char* const start; size_t size; size_t position; + size_t current; void readOne(Reader& reader); void readValue(Reader& reader, uint8_t code, const Descriptor* descriptor); @@ -92,7 +93,7 @@ class Decoder CharSequence readRawUuid(); Constructor readConstructor(); const char* data(); - + CharSequence getCurrent(size_t remaining) const; }; }} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/Descriptor.cpp b/qpid/cpp/src/qpid/amqp/Descriptor.cpp index 1d2df01e6e..384eba15b0 100644 --- a/qpid/cpp/src/qpid/amqp/Descriptor.cpp +++ b/qpid/cpp/src/qpid/amqp/Descriptor.cpp @@ -59,7 +59,7 @@ std::ostream& operator<<(std::ostream& os, const Descriptor& d) else os << "null"; break; case Descriptor::NUMERIC: - os << d.value.code; + os << "0x" << std::hex << d.value.code; break; } return os; diff --git a/qpid/cpp/src/qpid/amqp/Descriptor.h b/qpid/cpp/src/qpid/amqp/Descriptor.h index 789f4dcc63..b9a83628e7 100644 --- a/qpid/cpp/src/qpid/amqp/Descriptor.h +++ b/qpid/cpp/src/qpid/amqp/Descriptor.h @@ -42,13 +42,13 @@ struct Descriptor SYMBOLIC } type; - Descriptor(uint64_t code); - Descriptor(const CharSequence& symbol); - bool match(const std::string&, uint64_t) const; - size_t getSize() const; + QPID_COMMON_EXTERN Descriptor(uint64_t code); + QPID_COMMON_EXTERN Descriptor(const CharSequence& symbol); + QPID_COMMON_EXTERN bool match(const std::string&, uint64_t) const; + QPID_COMMON_EXTERN size_t getSize() const; }; -std::ostream& operator<<(std::ostream& os, const Descriptor& d); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const Descriptor& d); }} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/Encoder.cpp b/qpid/cpp/src/qpid/amqp/Encoder.cpp index 549b6d1e4e..627cc4aed6 100644 --- a/qpid/cpp/src/qpid/amqp/Encoder.cpp +++ b/qpid/cpp/src/qpid/amqp/Encoder.cpp @@ -23,11 +23,15 @@ #include "qpid/amqp/Descriptor.h" #include "qpid/amqp/typecodes.h" #include "qpid/types/Uuid.h" +#include "qpid/types/Variant.h" +#include "qpid/types/encodings.h" #include "qpid/log/Statement.h" #include "qpid/Exception.h" #include <assert.h> #include <string.h> +using namespace qpid::types::encodings; + namespace qpid { namespace amqp { @@ -373,6 +377,87 @@ void Encoder::endArray32(size_t count, void* token) end<uint32_t>(count, token, data+position); } +void Encoder::writeMap(const std::map<std::string, qpid::types::Variant>& value, const Descriptor* d, bool large) +{ + void* token = large ? startMap32(d) : startMap8(d); + for (qpid::types::Variant::Map::const_iterator i = value.begin(); i != value.end(); ++i) { + writeString(i->first); + writeValue(i->second); + } + if (large) endMap32(value.size()*2, token); + else endMap8(value.size()*2, token); +} + +void Encoder::writeList(const std::list<qpid::types::Variant>& value, const Descriptor* d, bool large) +{ + void* token = large ? startList32(d) : startList8(d); + for (qpid::types::Variant::List::const_iterator i = value.begin(); i != value.end(); ++i) { + writeValue(*i); + } + if (large) endList32(value.size(), token); + else endList8(value.size(), token); +} + +void Encoder::writeValue(const qpid::types::Variant& value, const Descriptor* d) +{ + switch (value.getType()) { + case qpid::types::VAR_VOID: + writeNull(d); + break; + case qpid::types::VAR_BOOL: + writeBoolean(value.asBool(), d); + break; + case qpid::types::VAR_UINT8: + writeUByte(value.asUint8(), d); + break; + case qpid::types::VAR_UINT16: + writeUShort(value.asUint16(), d); + break; + case qpid::types::VAR_UINT32: + writeUInt(value.asUint32(), d); + break; + case qpid::types::VAR_UINT64: + writeULong(value.asUint64(), d); + break; + case qpid::types::VAR_INT8: + writeByte(value.asInt8(), d); + break; + case qpid::types::VAR_INT16: + writeShort(value.asInt16(), d); + break; + case qpid::types::VAR_INT32: + writeInt(value.asInt32(), d); + break; + case qpid::types::VAR_INT64: + writeLong(value.asInt64(), d); + break; + case qpid::types::VAR_FLOAT: + writeFloat(value.asFloat(), d); + break; + case qpid::types::VAR_DOUBLE: + writeDouble(value.asDouble(), d); + break; + case qpid::types::VAR_STRING: + if (value.getEncoding() == UTF8) { + writeString(value.getString(), d); + } else if (value.getEncoding() == ASCII) { + writeSymbol(value.getString(), d); + } else { + writeBinary(value.getString(), d); + } + break; + case qpid::types::VAR_MAP: + writeMap(value.asMap(), d); + break; + case qpid::types::VAR_LIST: + writeList(value.asList(), d); + break; + case qpid::types::VAR_UUID: + writeUuid(value.asUuid(), d); + break; + } + +} void Encoder::writeDescriptor(const Descriptor& d) { diff --git a/qpid/cpp/src/qpid/amqp/Encoder.h b/qpid/cpp/src/qpid/amqp/Encoder.h index c661e4ac5d..e79ed76726 100644 --- a/qpid/cpp/src/qpid/amqp/Encoder.h +++ b/qpid/cpp/src/qpid/amqp/Encoder.h @@ -23,12 +23,15 @@ */ #include "qpid/sys/IntegerTypes.h" #include "qpid/amqp/Constructor.h" +#include <list> +#include <map> #include <stddef.h> #include <string> namespace qpid { namespace types { class Uuid; +class Variant; } namespace amqp { struct CharSequence; @@ -74,7 +77,7 @@ class Encoder void writeString(const CharSequence&, const Descriptor* d=0); void writeString(const std::string&, const Descriptor* d=0); void writeBinary(const CharSequence&, const Descriptor* d=0); - void writeBinary(const std::string&, const Descriptor* d=0); + QPID_COMMON_EXTERN void writeBinary(const std::string&, const Descriptor* d=0); void* startList8(const Descriptor* d=0); void* startList32(const Descriptor* d=0); @@ -91,9 +94,13 @@ class Encoder void endArray8(size_t count, void*); void endArray32(size_t count, void*); + QPID_COMMON_EXTERN void writeValue(const qpid::types::Variant&, const Descriptor* d=0); + QPID_COMMON_EXTERN void writeMap(const std::map<std::string, qpid::types::Variant>& value, const Descriptor* d=0, bool large=true); + QPID_COMMON_EXTERN void writeList(const std::list<qpid::types::Variant>& value, const Descriptor* d=0, bool large=true); + void writeDescriptor(const Descriptor&); - Encoder(char* data, size_t size); - size_t getPosition(); + QPID_COMMON_EXTERN Encoder(char* data, size_t size); + QPID_COMMON_EXTERN size_t getPosition(); void resetPosition(size_t p); char* skip(size_t); void writeBytes(const char* bytes, size_t count); diff --git a/qpid/cpp/src/qpid/console/Agent.cpp b/qpid/cpp/src/qpid/amqp/ListBuilder.cpp index fa76a13583..f2ca8e8805 100644 --- a/qpid/cpp/src/qpid/console/Agent.cpp +++ b/qpid/cpp/src/qpid/amqp/ListBuilder.cpp @@ -7,9 +7,9 @@ * 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 @@ -18,13 +18,16 @@ * under the License. * */ +#include "ListBuilder.h" + +namespace qpid { +namespace amqp { -#include "qpid/console/Agent.h" +ListBuilder::ListBuilder() : DataBuilder(qpid::types::Variant::List()) {} -std::ostream& qpid::console::operator<<(std::ostream& o, const Agent& agent) +qpid::types::Variant::List& ListBuilder::getList() { - o << "Agent at bank " << agent.getBrokerBank() << "." << agent.getAgentBank() << - " (" << agent.getLabel() << ")"; - return o; + return getValue().asList(); } +}} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/ListBuilder.h b/qpid/cpp/src/qpid/amqp/ListBuilder.h new file mode 100644 index 0000000000..825f384f56 --- /dev/null +++ b/qpid/cpp/src/qpid/amqp/ListBuilder.h @@ -0,0 +1,41 @@ +#ifndef QPID_AMQP_LISTBUILDER_H +#define QPID_AMQP_LISTBUILDER_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 "DataBuilder.h" +#include "qpid/CommonImportExport.h" + +namespace qpid { +namespace amqp { + +/** + * Utility to build a Variant::List from a data stream + */ +class ListBuilder : public DataBuilder +{ + public: + QPID_COMMON_EXTERN ListBuilder(); + QPID_COMMON_EXTERN qpid::types::Variant::List& getList(); +}; +}} // namespace qpid::amqp + +#endif /*!QPID_AMQP_LISTBUILDER_H*/ diff --git a/qpid/cpp/src/qpid/amqp/ListReader.h b/qpid/cpp/src/qpid/amqp/ListReader.h index dce874bf2f..fafe2a1f9c 100644 --- a/qpid/cpp/src/qpid/amqp/ListReader.h +++ b/qpid/cpp/src/qpid/amqp/ListReader.h @@ -53,10 +53,10 @@ class ListReader : public Reader virtual void onString(const CharSequence& v, const Descriptor* descriptor) { getReader().onString(v, descriptor); } virtual void onSymbol(const CharSequence& v, const Descriptor* descriptor) { getReader().onSymbol(v, descriptor); } - virtual bool onStartList(uint32_t count, const CharSequence& v, const Descriptor* descriptor) + virtual bool onStartList(uint32_t count, const CharSequence& elements, const CharSequence& all, const Descriptor* descriptor) { ++level; - getReader().onStartList(count, v, descriptor); + getReader().onStartList(count, elements, all, descriptor); return false; } virtual void onEndList(uint32_t count, const Descriptor* descriptor) @@ -64,10 +64,10 @@ class ListReader : public Reader --level; getReader().onEndList(count, descriptor); } - virtual bool onStartMap(uint32_t count, const CharSequence& v, const Descriptor* descriptor) + virtual bool onStartMap(uint32_t count, const CharSequence& elements, const CharSequence& all, const Descriptor* descriptor) { ++level; - getReader().onStartMap(count, v, descriptor); + getReader().onStartMap(count, elements, all, descriptor); return false; } virtual void onEndMap(uint32_t count, const Descriptor* descriptor) diff --git a/qpid/cpp/src/qpid/amqp/MapBuilder.cpp b/qpid/cpp/src/qpid/amqp/MapBuilder.cpp index a554497791..ce8eea038e 100644 --- a/qpid/cpp/src/qpid/amqp/MapBuilder.cpp +++ b/qpid/cpp/src/qpid/amqp/MapBuilder.cpp @@ -19,112 +19,12 @@ * */ #include "MapBuilder.h" -#include <assert.h> namespace qpid { namespace amqp { -namespace { -const std::string BINARY("binary"); -const std::string UTF8("utf8"); -const std::string ASCII("ascii"); -} - +MapBuilder::MapBuilder() : DataBuilder(qpid::types::Variant::Map()) {} qpid::types::Variant::Map MapBuilder::getMap() { - return map; -} -const qpid::types::Variant::Map MapBuilder::getMap() const -{ - return map; -} - -void MapBuilder::onNullValue(const CharSequence& key, const Descriptor*) -{ - map[std::string(key.data, key.size)] = qpid::types::Variant(); -} -void MapBuilder::onBooleanValue(const CharSequence& key, bool value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} -void MapBuilder::onUByteValue(const CharSequence& key, uint8_t value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onUShortValue(const CharSequence& key, uint16_t value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onUIntValue(const CharSequence& key, uint32_t value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onULongValue(const CharSequence& key, uint64_t value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onByteValue(const CharSequence& key, int8_t value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onShortValue(const CharSequence& key, int16_t value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onIntValue(const CharSequence& key, int32_t value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onLongValue(const CharSequence& key, int64_t value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onFloatValue(const CharSequence& key, float value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onDoubleValue(const CharSequence& key, double value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onUuidValue(const CharSequence& key, const CharSequence& value, const Descriptor*) -{ - assert(value.size == 16); - map[std::string(key.data, key.size)] = qpid::types::Uuid(value.data); -} - -void MapBuilder::onTimestampValue(const CharSequence& key, int64_t value, const Descriptor*) -{ - map[std::string(key.data, key.size)] = value; -} - -void MapBuilder::onBinaryValue(const CharSequence& key, const CharSequence& value, const Descriptor*) -{ - qpid::types::Variant& v = map[std::string(key.data, key.size)]; - v = std::string(value.data, value.size); - v.setEncoding(BINARY); -} - -void MapBuilder::onStringValue(const CharSequence& key, const CharSequence& value, const Descriptor*) -{ - qpid::types::Variant& v = map[std::string(key.data, key.size)]; - v = std::string(value.data, value.size); - v.setEncoding(UTF8); -} - -void MapBuilder::onSymbolValue(const CharSequence& key, const CharSequence& value, const Descriptor*) -{ - qpid::types::Variant& v = map[std::string(key.data, key.size)]; - v = std::string(value.data, value.size); - v.setEncoding(ASCII); + return getValue().asMap(); } }} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/MapBuilder.h b/qpid/cpp/src/qpid/amqp/MapBuilder.h index 0e3b95f633..fd94ae04af 100644 --- a/qpid/cpp/src/qpid/amqp/MapBuilder.h +++ b/qpid/cpp/src/qpid/amqp/MapBuilder.h @@ -21,42 +21,20 @@ * under the License. * */ -#include "MapReader.h" -#include "qpid/types/Variant.h" +#include "DataBuilder.h" +#include "qpid/CommonImportExport.h" namespace qpid { namespace amqp { /** - * Utility to build a Variant::Map from a data stream (doesn't handle - * nested maps or lists yet) + * Utility to build a Variant::Map from a data stream */ -class MapBuilder : public MapReader +class MapBuilder : public DataBuilder { public: - void onNullValue(const CharSequence& /*key*/, const Descriptor*); - void onBooleanValue(const CharSequence& /*key*/, bool, const Descriptor*); - void onUByteValue(const CharSequence& /*key*/, uint8_t, const Descriptor*); - void onUShortValue(const CharSequence& /*key*/, uint16_t, const Descriptor*); - void onUIntValue(const CharSequence& /*key*/, uint32_t, const Descriptor*); - void onULongValue(const CharSequence& /*key*/, uint64_t, const Descriptor*); - void onByteValue(const CharSequence& /*key*/, int8_t, const Descriptor*); - void onShortValue(const CharSequence& /*key*/, int16_t, const Descriptor*); - void onIntValue(const CharSequence& /*key*/, int32_t, const Descriptor*); - void onLongValue(const CharSequence& /*key*/, int64_t, const Descriptor*); - void onFloatValue(const CharSequence& /*key*/, float, const Descriptor*); - void onDoubleValue(const CharSequence& /*key*/, double, const Descriptor*); - void onUuidValue(const CharSequence& /*key*/, const CharSequence&, const Descriptor*); - void onTimestampValue(const CharSequence& /*key*/, int64_t, const Descriptor*); - - void onBinaryValue(const CharSequence& /*key*/, const CharSequence&, const Descriptor*); - void onStringValue(const CharSequence& /*key*/, const CharSequence&, const Descriptor*); - void onSymbolValue(const CharSequence& /*key*/, const CharSequence&, const Descriptor*); - - qpid::types::Variant::Map getMap(); - const qpid::types::Variant::Map getMap() const; - private: - qpid::types::Variant::Map map; + QPID_COMMON_EXTERN MapBuilder(); + QPID_COMMON_EXTERN qpid::types::Variant::Map getMap(); }; }} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/MapReader.cpp b/qpid/cpp/src/qpid/amqp/MapReader.cpp index aff885c5d3..b6c31849f0 100644 --- a/qpid/cpp/src/qpid/amqp/MapReader.cpp +++ b/qpid/cpp/src/qpid/amqp/MapReader.cpp @@ -219,7 +219,7 @@ void MapReader::onSymbol(const CharSequence& v, const Descriptor* d) } } -bool MapReader::onStartList(uint32_t count, const CharSequence&, const Descriptor* d) +bool MapReader::onStartList(uint32_t count, const CharSequence&, const CharSequence&, const Descriptor* d) { if (!level) throw qpid::Exception(QPID_MSG("Expecting map as top level datum")); if (key) { @@ -232,7 +232,7 @@ bool MapReader::onStartList(uint32_t count, const CharSequence&, const Descripto return true; } -bool MapReader::onStartMap(uint32_t count, const CharSequence&, const Descriptor* d) +bool MapReader::onStartMap(uint32_t count, const CharSequence&, const CharSequence&, const Descriptor* d) { if (level++) { if (key) { diff --git a/qpid/cpp/src/qpid/amqp/MapReader.h b/qpid/cpp/src/qpid/amqp/MapReader.h index cb977e1326..875f919d63 100644 --- a/qpid/cpp/src/qpid/amqp/MapReader.h +++ b/qpid/cpp/src/qpid/amqp/MapReader.h @@ -68,36 +68,36 @@ class MapReader : public Reader //this class implements the Reader interface, thus acting as a transformer into a more map oriented scheme - void onNull(const Descriptor*); - void onBoolean(bool, const Descriptor*); - void onUByte(uint8_t, const Descriptor*); - void onUShort(uint16_t, const Descriptor*); - void onUInt(uint32_t, const Descriptor*); - void onULong(uint64_t, const Descriptor*); - void onByte(int8_t, const Descriptor*); - void onShort(int16_t, const Descriptor*); - void onInt(int32_t, const Descriptor*); - void onLong(int64_t, const Descriptor*); - void onFloat(float, const Descriptor*); - void onDouble(double, const Descriptor*); - void onUuid(const CharSequence&, const Descriptor*); - void onTimestamp(int64_t, const Descriptor*); + QPID_COMMON_EXTERN void onNull(const Descriptor*); + QPID_COMMON_EXTERN void onBoolean(bool, const Descriptor*); + QPID_COMMON_EXTERN void onUByte(uint8_t, const Descriptor*); + QPID_COMMON_EXTERN void onUShort(uint16_t, const Descriptor*); + QPID_COMMON_EXTERN void onUInt(uint32_t, const Descriptor*); + QPID_COMMON_EXTERN void onULong(uint64_t, const Descriptor*); + QPID_COMMON_EXTERN void onByte(int8_t, const Descriptor*); + QPID_COMMON_EXTERN void onShort(int16_t, const Descriptor*); + QPID_COMMON_EXTERN void onInt(int32_t, const Descriptor*); + QPID_COMMON_EXTERN void onLong(int64_t, const Descriptor*); + QPID_COMMON_EXTERN void onFloat(float, const Descriptor*); + QPID_COMMON_EXTERN void onDouble(double, const Descriptor*); + QPID_COMMON_EXTERN void onUuid(const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN void onTimestamp(int64_t, const Descriptor*); - void onBinary(const CharSequence&, const Descriptor*); - void onString(const CharSequence&, const Descriptor*); - void onSymbol(const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN void onBinary(const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN void onString(const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN void onSymbol(const CharSequence&, const Descriptor*); - bool onStartList(uint32_t /*count*/, const CharSequence&, const Descriptor*); - bool onStartMap(uint32_t /*count*/, const CharSequence&, const Descriptor*); - bool onStartArray(uint32_t /*count*/, const CharSequence&, const Constructor&, const Descriptor*); - void onEndList(uint32_t /*count*/, const Descriptor*); - void onEndMap(uint32_t /*count*/, const Descriptor*); - void onEndArray(uint32_t /*count*/, const Descriptor*); + QPID_COMMON_EXTERN bool onStartList(uint32_t /*count*/, const CharSequence&, const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN bool onStartMap(uint32_t /*count*/, const CharSequence&, const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN bool onStartArray(uint32_t /*count*/, const CharSequence&, const Constructor&, const Descriptor*); + QPID_COMMON_EXTERN void onEndList(uint32_t /*count*/, const Descriptor*); + QPID_COMMON_EXTERN void onEndMap(uint32_t /*count*/, const Descriptor*); + QPID_COMMON_EXTERN void onEndArray(uint32_t /*count*/, const Descriptor*); - MapReader(); - static const int SYMBOL_KEY; - static const int STRING_KEY; - void setAllowedKeyType(int); + QPID_COMMON_EXTERN MapReader(); + QPID_COMMON_EXTERN static const int SYMBOL_KEY; + QPID_COMMON_EXTERN static const int STRING_KEY; + QPID_COMMON_EXTERN void setAllowedKeyType(int); private: CharSequence key; size_t level; diff --git a/qpid/cpp/src/qpid/amqp/MessageEncoder.cpp b/qpid/cpp/src/qpid/amqp/MessageEncoder.cpp index 3b493d1de7..beaea2befd 100644 --- a/qpid/cpp/src/qpid/amqp/MessageEncoder.cpp +++ b/qpid/cpp/src/qpid/amqp/MessageEncoder.cpp @@ -156,68 +156,6 @@ void MessageEncoder::writeApplicationProperties(const qpid::types::Variant::Map& writeMap(properties, &qpid::amqp::message::APPLICATION_PROPERTIES, large); } -void MessageEncoder::writeMap(const qpid::types::Variant::Map& properties, const Descriptor* d, bool large) -{ - void* token = large ? startMap32(d) : startMap8(d); - for (qpid::types::Variant::Map::const_iterator i = properties.begin(); i != properties.end(); ++i) { - writeString(i->first); - switch (i->second.getType()) { - case qpid::types::VAR_MAP: - case qpid::types::VAR_LIST: - //not allowed (TODO: revise, only strictly true for application-properties) whereas this is now a more general method) - QPID_LOG(warning, "Ignoring nested map/list; not allowed in application-properties for AMQP 1.0"); - case qpid::types::VAR_VOID: - writeNull(); - break; - case qpid::types::VAR_BOOL: - writeBoolean(i->second); - break; - case qpid::types::VAR_UINT8: - writeUByte(i->second); - break; - case qpid::types::VAR_UINT16: - writeUShort(i->second); - break; - case qpid::types::VAR_UINT32: - writeUInt(i->second); - break; - case qpid::types::VAR_UINT64: - writeULong(i->second); - break; - case qpid::types::VAR_INT8: - writeByte(i->second); - break; - case qpid::types::VAR_INT16: - writeShort(i->second); - break; - case qpid::types::VAR_INT32: - writeInt(i->second); - break; - case qpid::types::VAR_INT64: - writeULong(i->second); - break; - case qpid::types::VAR_FLOAT: - writeFloat(i->second); - break; - case qpid::types::VAR_DOUBLE: - writeDouble(i->second); - break; - case qpid::types::VAR_STRING: - if (i->second.getEncoding() == BINARY) { - writeBinary(i->second); - } else { - writeString(i->second); - } - break; - case qpid::types::VAR_UUID: - writeUuid(i->second); - break; - } - } - if (large) endMap32(properties.size()*2, token); - else endMap8(properties.size()*2, token); -} - size_t MessageEncoder::getEncodedSize(const Header& h, const Properties& p, const qpid::types::Variant::Map& ap, const std::string& d) { return getEncodedSize(h) + getEncodedSize(p, ap, d); @@ -288,46 +226,56 @@ size_t MessageEncoder::getEncodedSizeForElements(const qpid::types::Variant::Map { size_t total = 0; for (qpid::types::Variant::Map::const_iterator i = map.begin(); i != map.end(); ++i) { - total += 1/*code*/ + encodedSize(i->first); - - switch (i->second.getType()) { - case qpid::types::VAR_MAP: - case qpid::types::VAR_LIST: - case qpid::types::VAR_VOID: - case qpid::types::VAR_BOOL: - total += 1; - break; - - case qpid::types::VAR_UINT8: - case qpid::types::VAR_INT8: - total += 2; - break; - - case qpid::types::VAR_UINT16: - case qpid::types::VAR_INT16: - total += 3; - break; - - case qpid::types::VAR_UINT32: - case qpid::types::VAR_INT32: - case qpid::types::VAR_FLOAT: - total += 5; - break; - - case qpid::types::VAR_UINT64: - case qpid::types::VAR_INT64: - case qpid::types::VAR_DOUBLE: - total += 9; - break; - - case qpid::types::VAR_UUID: - total += 17; - break; - - case qpid::types::VAR_STRING: - total += 1/*code*/ + encodedSize(i->second); - break; - } + total += 1/*code*/ + encodedSize(i->first) + getEncodedSizeForValue(i->second); + } + return total; +} + +size_t MessageEncoder::getEncodedSizeForValue(const qpid::types::Variant& value) +{ + size_t total = 0; + switch (value.getType()) { + case qpid::types::VAR_MAP: + total += getEncodedSize(value.asMap(), true); + break; + case qpid::types::VAR_LIST: + total += getEncodedSize(value.asList(), true); + break; + + case qpid::types::VAR_VOID: + case qpid::types::VAR_BOOL: + total += 1; + break; + + case qpid::types::VAR_UINT8: + case qpid::types::VAR_INT8: + total += 2; + break; + + case qpid::types::VAR_UINT16: + case qpid::types::VAR_INT16: + total += 3; + break; + + case qpid::types::VAR_UINT32: + case qpid::types::VAR_INT32: + case qpid::types::VAR_FLOAT: + total += 5; + break; + + case qpid::types::VAR_UINT64: + case qpid::types::VAR_INT64: + case qpid::types::VAR_DOUBLE: + total += 9; + break; + + case qpid::types::VAR_UUID: + total += 17; + break; + + case qpid::types::VAR_STRING: + total += 1/*code*/ + encodedSize(value.getString()); + break; } return total; } @@ -345,4 +293,20 @@ size_t MessageEncoder::getEncodedSize(const qpid::types::Variant::Map& map, bool return total; } + +size_t MessageEncoder::getEncodedSize(const qpid::types::Variant::List& list, bool alwaysUseLargeList) +{ + size_t total(0); + for (qpid::types::Variant::List::const_iterator i = list.begin(); i != list.end(); ++i) { + total += getEncodedSizeForValue(*i); + } + + //its not just the count that determines whether we can use a small list, but the aggregate size: + if (alwaysUseLargeList || list.size()*2 > 255 || total > 255) total += 4/*size*/ + 4/*count*/; + else total += 1/*size*/ + 1/*count*/; + + total += 1 /*code for list itself*/; + + return total; +} }} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/MessageEncoder.h b/qpid/cpp/src/qpid/amqp/MessageEncoder.h index 1de3d47bb2..05e1714004 100644 --- a/qpid/cpp/src/qpid/amqp/MessageEncoder.h +++ b/qpid/cpp/src/qpid/amqp/MessageEncoder.h @@ -39,7 +39,7 @@ class MessageEncoder : public Encoder virtual ~Header() {} virtual bool isDurable() const = 0; virtual uint8_t getPriority() const = 0; - virtual bool hasTtl() const = 0; + QPID_COMMON_EXTERN virtual bool hasTtl() const = 0; virtual uint32_t getTtl() const = 0; virtual bool isFirstAcquirer() const = 0; virtual uint32_t getDeliveryCount() const = 0; @@ -84,29 +84,33 @@ class MessageEncoder : public Encoder virtual void handle(MapHandler&) const = 0; }; - MessageEncoder(char* d, size_t s, bool o=false) : Encoder(d, s), optimise(o) {} - void writeHeader(const Header&); - void writeProperties(const Properties&); - void writeApplicationProperties(const ApplicationProperties&); - void writeApplicationProperties(const qpid::types::Variant::Map& properties); - void writeApplicationProperties(const qpid::types::Variant::Map& properties, bool useLargeMap); + QPID_COMMON_EXTERN MessageEncoder(char* d, size_t s) : Encoder(d, s), optimise(true) {} + QPID_COMMON_EXTERN void writeHeader(const Header&); + QPID_COMMON_EXTERN void writeProperties(const Properties&); + QPID_COMMON_EXTERN void writeApplicationProperties(const ApplicationProperties&); + QPID_COMMON_EXTERN void writeApplicationProperties(const qpid::types::Variant::Map& properties); + QPID_COMMON_EXTERN void writeApplicationProperties(const qpid::types::Variant::Map& properties, bool useLargeMap); - void writeMap(const qpid::types::Variant::Map& map, const Descriptor*, bool useLargeMap); + QPID_COMMON_EXTERN static size_t getEncodedSize(const Header&); + QPID_COMMON_EXTERN static size_t getEncodedSize(const Properties&); + QPID_COMMON_EXTERN static size_t getEncodedSize(const ApplicationProperties&); - static size_t getEncodedSize(const Header&); - static size_t getEncodedSize(const Properties&); - static size_t getEncodedSize(const ApplicationProperties&); - static size_t getEncodedSize(const Header&, const Properties&, const ApplicationProperties&, const std::string&); + QPID_COMMON_EXTERN static size_t getEncodedSize(const qpid::types::Variant::List&, bool useLargeList); + QPID_COMMON_EXTERN static size_t getEncodedSize(const qpid::types::Variant::Map&, bool useLargeMap); + + QPID_COMMON_EXTERN static size_t getEncodedSizeForValue(const qpid::types::Variant& value); + QPID_COMMON_EXTERN static size_t getEncodedSizeForContent(const std::string&); + + //used in translating 0-10 content to 1.0, to determine buffer space needed + QPID_COMMON_EXTERN static size_t getEncodedSize(const Properties&, const qpid::types::Variant::Map&, const std::string&); - static size_t getEncodedSize(const qpid::types::Variant::Map&, bool useLargeMap); - static size_t getEncodedSize(const qpid::types::Variant::Map&); - static size_t getEncodedSize(const Header&, const Properties&, const qpid::types::Variant::Map&, const std::string&); - static size_t getEncodedSize(const Properties&, const qpid::types::Variant::Map&, const std::string&); private: bool optimise; + static size_t getEncodedSize(const Header&, const Properties&, const ApplicationProperties&, const std::string&); + static size_t getEncodedSize(const Header&, const Properties&, const qpid::types::Variant::Map&, const std::string&); + static size_t getEncodedSizeForElements(const qpid::types::Variant::Map&); - static size_t getEncodedSizeForContent(const std::string&); }; }} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/MessageReader.cpp b/qpid/cpp/src/qpid/amqp/MessageReader.cpp index 1550fa1977..70374f4cd6 100644 --- a/qpid/cpp/src/qpid/amqp/MessageReader.cpp +++ b/qpid/cpp/src/qpid/amqp/MessageReader.cpp @@ -21,6 +21,7 @@ #include "qpid/amqp/MessageReader.h" #include "qpid/amqp/Descriptor.h" #include "qpid/amqp/descriptors.h" +#include "qpid/amqp/typecodes.h" #include "qpid/types/Uuid.h" #include "qpid/types/Variant.h" #include "qpid/log/Statement.h" @@ -55,40 +56,6 @@ const size_t REPLY_TO_GROUP_ID(12); } -/* -Reader& MessageReader::HeaderReader::getReader(size_t index) -{ - switch (index) { - case DURABLE: return durableReader; - case PRIORITY: return priorityReader; - case TTL: return ttlReader; - case FIRST_ACQUIRER: return firstAcquirerReader; - case DELIVERY_COUNT: return deliveryCountReader; - default: return noSuchFieldReader; - } -} - -Reader& MessageReader::PropertiesReader::getReader(size_t index) -{ - switch (index) { - case MESSAGE_ID: return messageIdReader; - case USER_ID: return userIdReader; - case TO: return toReader; - case SUBJECT: return subjectReader; - case REPLY_TO: return replyToReader; - case CORRELATION_ID: return correlationIdReader; - case CONTENT_TYPE: return contentTypeReader; - case CONTENT_ENCODING: return contentEncodingReader; - case ABSOLUTE_EXPIRY_TIME: return absoluteExpiryTimeReader; - case CREATION_TIME: return creationTimeReader; - case GROUP_ID: return groupIdReader; - case GROUP_SEQUENCE: return groupSequenceReader; - case REPLY_TO_GROUP_ID: return replyToGroupIdReader; - default: return noSuchFieldReader; - } -} -*/ - MessageReader::HeaderReader::HeaderReader(MessageReader& p) : parent(p), index(0) {} void MessageReader::HeaderReader::onBoolean(bool v, const Descriptor*) // durable, first-acquirer { @@ -132,7 +99,7 @@ void MessageReader::PropertiesReader::onUuid(const CharSequence& v, const Descri if (index == MESSAGE_ID) { parent.onMessageId(v, qpid::types::VAR_UUID); } else if (index == CORRELATION_ID) { - parent.onCorrelationId(v); + parent.onCorrelationId(v, qpid::types::VAR_UUID); } else { QPID_LOG(warning, "Unexpected message format, got uuid at index " << index << " of properties"); } @@ -154,7 +121,7 @@ void MessageReader::PropertiesReader::onBinary(const CharSequence& v, const Desc if (index == MESSAGE_ID) { parent.onMessageId(v, qpid::types::VAR_STRING); } else if (index == CORRELATION_ID) { - parent.onCorrelationId(v); + parent.onCorrelationId(v, qpid::types::VAR_STRING); } else if (index == USER_ID) { parent.onUserId(v); } else { @@ -165,9 +132,9 @@ void MessageReader::PropertiesReader::onBinary(const CharSequence& v, const Desc void MessageReader::PropertiesReader::onString(const CharSequence& v, const Descriptor*) // message-id, correlation-id, group-id, reply-to-group-id, subject, to, reply-to { if (index == MESSAGE_ID) { - parent.onMessageId(v); + parent.onMessageId(v, qpid::types::VAR_STRING); } else if (index == CORRELATION_ID) { - parent.onCorrelationId(v); + parent.onCorrelationId(v, qpid::types::VAR_STRING); } else if (index == GROUP_ID) { parent.onGroupId(v); } else if (index == REPLY_TO_GROUP_ID) { @@ -218,129 +185,76 @@ void MessageReader::PropertiesReader::onNull(const Descriptor*) { ++index; } - -/* -MessageReader::DurableReader::DurableReader(MessageReader& p) : parent(p) {} -void MessageReader::DurableReader::onBoolean(bool v, const Descriptor*) -{ - parent.onDurable(v); -} -MessageReader::PriorityReader::PriorityReader(MessageReader& p) : parent(p) {} -void MessageReader::PriorityReader::onUByte(uint8_t v, const Descriptor*) -{ - parent.onPriority(v); -} -MessageReader::TtlReader::TtlReader(MessageReader& p) : parent(p) {} -void MessageReader::TtlReader::onUInt(uint32_t v, const Descriptor*) -{ - parent.onTtl(v); -} -MessageReader::FirstAcquirerReader::FirstAcquirerReader(MessageReader& p) : parent(p) {} -void MessageReader::FirstAcquirerReader::onBoolean(bool v, const Descriptor*) -{ - parent.onFirstAcquirer(v); -} -MessageReader::DeliveryCountReader::DeliveryCountReader(MessageReader& p) : parent(p) {} -void MessageReader::DeliveryCountReader::onUInt(uint32_t v, const Descriptor*) -{ - parent.onDeliveryCount(v); -} -MessageReader::MessageIdReader::MessageIdReader(MessageReader& p) : parent(p) {} -void MessageReader::MessageIdReader::onUuid(const qpid::types::Uuid& v, const Descriptor*) -{ - parent.onMessageId(v); -} -void MessageReader::MessageIdReader::onULong(uint64_t v, const Descriptor*) +void MessageReader::PropertiesReader::onBoolean(bool, const Descriptor*) { - parent.onMessageId(v); -} -void MessageReader::MessageIdReader::onString(const CharSequence& v, const Descriptor*) -{ - parent.onMessageId(v); -} -void MessageReader::MessageIdReader::onBinary(const CharSequence& v, const Descriptor*) -{ - parent.onMessageId(v); -} -MessageReader::UserIdReader::UserIdReader(MessageReader& p) : parent(p) {} -void MessageReader::UserIdReader::onBinary(const CharSequence& v, const Descriptor*) -{ - parent.onUserId(v); -} -MessageReader::ToReader::ToReader(MessageReader& p) : parent(p) {} -void MessageReader::ToReader::onString(const CharSequence& v, const Descriptor*) -{ - parent.onTo(v); -} -MessageReader::SubjectReader::SubjectReader(MessageReader& p) : parent(p) {} -void MessageReader::SubjectReader::onString(const CharSequence& v, const Descriptor*) -{ - parent.onSubject(v); -} -MessageReader::ReplyToReader::ReplyToReader(MessageReader& p) : parent(p) {} -void MessageReader::ReplyToReader::onString(const CharSequence& v, const Descriptor*) -{ - parent.onReplyTo(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (boolean)"); + ++index; } -MessageReader::CorrelationIdReader::CorrelationIdReader(MessageReader& p) : parent(p) {} -void MessageReader::CorrelationIdReader::onUuid(const qpid::types::Uuid& v, const Descriptor*) +void MessageReader::PropertiesReader::onUByte(uint8_t, const Descriptor*) { - parent.onCorrelationId(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (ubyte)"); + ++index; } -void MessageReader::CorrelationIdReader::onULong(uint64_t v, const Descriptor*) +void MessageReader::PropertiesReader::onUShort(uint16_t, const Descriptor*) { - parent.onCorrelationId(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (ushort)"); + ++index; } -void MessageReader::CorrelationIdReader::onString(const CharSequence& v, const Descriptor*) +void MessageReader::PropertiesReader::onByte(int8_t, const Descriptor*) { - parent.onCorrelationId(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (byte)"); + ++index; } -void MessageReader::CorrelationIdReader::onBinary(const CharSequence& v, const Descriptor*) +void MessageReader::PropertiesReader::onShort(int16_t, const Descriptor*) { - parent.onCorrelationId(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (short)"); + ++index; } -MessageReader::ContentTypeReader::ContentTypeReader(MessageReader& p) : parent(p) {} -void MessageReader::ContentTypeReader::onString(const CharSequence& v, const Descriptor*) +void MessageReader::PropertiesReader::onInt(int32_t, const Descriptor*) { - parent.onContentType(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (int)"); + ++index; } -MessageReader::ContentEncodingReader::ContentEncodingReader(MessageReader& p) : parent(p) {} -void MessageReader::ContentEncodingReader::onString(const CharSequence& v, const Descriptor*) +void MessageReader::PropertiesReader::onLong(int64_t, const Descriptor*) { - parent.onContentEncoding(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (long)"); + ++index; } -MessageReader::AbsoluteExpiryTimeReader::AbsoluteExpiryTimeReader(MessageReader& p) : parent(p) {} -void MessageReader::AbsoluteExpiryTimeReader::onTimestamp(int64_t v, const Descriptor*) +void MessageReader::PropertiesReader::onFloat(float, const Descriptor*) { - parent.onAbsoluteExpiryTime(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (float)"); + ++index; } -MessageReader::CreationTimeReader::CreationTimeReader(MessageReader& p) : parent(p) {} -void MessageReader::CreationTimeReader::onTimestamp(int64_t v, const Descriptor*) +void MessageReader::PropertiesReader::onDouble(double, const Descriptor*) { - parent.onCreationTime(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (double)"); + ++index; } -MessageReader::GroupIdReader::GroupIdReader(MessageReader& p) : parent(p) {} -void MessageReader::GroupIdReader::onString(const CharSequence& v, const Descriptor*) +bool MessageReader::PropertiesReader::onStartList(uint32_t /*count*/, const CharSequence& /*elements*/, const CharSequence& /*complete*/, const Descriptor*) { - parent.onGroupId(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (list)"); + ++index; + return false; } -MessageReader::GroupSequenceReader::GroupSequenceReader(MessageReader& p) : parent(p) {} -void MessageReader::GroupSequenceReader::onUInt(uint32_t v, const Descriptor*) +bool MessageReader::PropertiesReader::onStartMap(uint32_t /*count*/, const CharSequence& /*elements*/, const CharSequence& /*complete*/, const Descriptor*) { - parent.onGroupSequence(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (map)"); + ++index; + return false; } -MessageReader::ReplyToGroupIdReader::ReplyToGroupIdReader(MessageReader& p) : parent(p) {} -void MessageReader::ReplyToGroupIdReader::onString(const CharSequence& v, const Descriptor*) +bool MessageReader::PropertiesReader::onStartArray(uint32_t /*count*/, const CharSequence&, const Constructor&, const Descriptor*) { - parent.onReplyToGroupId(v); + QPID_LOG(info, "skipping message property at index " << index << " unexpected type (array)"); + ++index; + return false; } -*/ + //header, properties, amqp-sequence, amqp-value -bool MessageReader::onStartList(uint32_t count, const CharSequence& raw, const Descriptor* descriptor) +bool MessageReader::onStartList(uint32_t count, const CharSequence& elements, const CharSequence& raw, const Descriptor* descriptor) { if (delegate) { - return delegate->onStartList(count, raw, descriptor); + return delegate->onStartList(count, elements, raw, descriptor); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got no descriptor for list."); @@ -351,8 +265,11 @@ bool MessageReader::onStartList(uint32_t count, const CharSequence& raw, const D } else if (descriptor->match(PROPERTIES_SYMBOL, PROPERTIES_CODE)) { delegate = &propertiesReader; return true; - } else if (descriptor->match(AMQP_SEQUENCE_SYMBOL, AMQP_SEQUENCE_CODE) || descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { - onBody(raw, *descriptor); + } else if (descriptor->match(AMQP_SEQUENCE_SYMBOL, AMQP_SEQUENCE_CODE)) { + onAmqpSequence(raw); + return false; + } else if (descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { + onAmqpValue(elements, qpid::amqp::typecodes::LIST_NAME); return false; } else { QPID_LOG(warning, "Unexpected described list: " << *descriptor); @@ -372,28 +289,28 @@ void MessageReader::onEndList(uint32_t count, const Descriptor* descriptor) } //delivery-annotations, message-annotations, application-properties, amqp-value -bool MessageReader::onStartMap(uint32_t count, const CharSequence& raw, const Descriptor* descriptor) +bool MessageReader::onStartMap(uint32_t count, const CharSequence& elements, const CharSequence& raw, const Descriptor* descriptor) { if (delegate) { - return delegate->onStartMap(count, raw, descriptor); + return delegate->onStartMap(count, elements, raw, descriptor); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got no descriptor for map."); return false; } else if (descriptor->match(DELIVERY_ANNOTATIONS_SYMBOL, DELIVERY_ANNOTATIONS_CODE)) { - onDeliveryAnnotations(raw); + onDeliveryAnnotations(elements, raw); return false; } else if (descriptor->match(MESSAGE_ANNOTATIONS_SYMBOL, MESSAGE_ANNOTATIONS_CODE)) { - onMessageAnnotations(raw); + onMessageAnnotations(elements, raw); return false; } else if (descriptor->match(FOOTER_SYMBOL, FOOTER_CODE)) { - onFooter(raw); + onFooter(elements, raw); return false; } else if (descriptor->match(APPLICATION_PROPERTIES_SYMBOL, APPLICATION_PROPERTIES_CODE)) { - onApplicationProperties(raw); + onApplicationProperties(elements, raw); return false; } else if (descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { - onBody(raw, *descriptor); + onAmqpValue(elements, qpid::amqp::typecodes::MAP_NAME); return false; } else { QPID_LOG(warning, "Unexpected described map: " << *descriptor); @@ -417,8 +334,10 @@ void MessageReader::onBinary(const CharSequence& bytes, const Descriptor* descri } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got binary value with no descriptor."); - } else if (descriptor->match(DATA_SYMBOL, DATA_CODE) || descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { - onBody(bytes, *descriptor); + } else if (descriptor->match(DATA_SYMBOL, DATA_CODE)) { + onData(bytes); + } else if (descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { + onAmqpValue(bytes, qpid::amqp::typecodes::BINARY_NAME); } else { QPID_LOG(warning, "Unexpected binary value with descriptor: " << *descriptor); } @@ -434,7 +353,7 @@ void MessageReader::onNull(const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant v; - onBody(v, *descriptor); + onAmqpValue(v); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got null value with no descriptor."); @@ -450,7 +369,7 @@ void MessageReader::onString(const CharSequence& v, const Descriptor* descriptor delegate->onString(v, descriptor); } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { - onBody(v, *descriptor); + onAmqpValue(v, qpid::amqp::typecodes::STRING_NAME); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got string value with no descriptor."); @@ -466,7 +385,7 @@ void MessageReader::onSymbol(const CharSequence& v, const Descriptor* descriptor delegate->onSymbol(v, descriptor); } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { - onBody(v, *descriptor); + onAmqpValue(v, qpid::amqp::typecodes::SYMBOL_NAME); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got symbol value with no descriptor."); @@ -484,7 +403,7 @@ void MessageReader::onBoolean(bool v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got boolean value with no descriptor."); @@ -502,7 +421,7 @@ void MessageReader::onUByte(uint8_t v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got ubyte value with no descriptor."); @@ -520,7 +439,7 @@ void MessageReader::onUShort(uint16_t v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got ushort value with no descriptor."); @@ -538,7 +457,7 @@ void MessageReader::onUInt(uint32_t v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got uint value with no descriptor."); @@ -556,7 +475,7 @@ void MessageReader::onULong(uint64_t v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got ulong value with no descriptor."); @@ -574,7 +493,7 @@ void MessageReader::onByte(int8_t v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got byte value with no descriptor."); @@ -592,7 +511,7 @@ void MessageReader::onShort(int16_t v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got short value with no descriptor."); @@ -610,7 +529,7 @@ void MessageReader::onInt(int32_t v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got int value with no descriptor."); @@ -628,7 +547,7 @@ void MessageReader::onLong(int64_t v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got long value with no descriptor."); @@ -646,7 +565,7 @@ void MessageReader::onFloat(float v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got float value with no descriptor."); @@ -664,7 +583,7 @@ void MessageReader::onDouble(double v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got double value with no descriptor."); @@ -681,7 +600,7 @@ void MessageReader::onUuid(const CharSequence& v, const Descriptor* descriptor) delegate->onUuid(v, descriptor); } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { - onBody(v, *descriptor); + onAmqpValue(v, qpid::amqp::typecodes::UUID_NAME); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got uuid value with no descriptor."); @@ -699,7 +618,7 @@ void MessageReader::onTimestamp(int64_t v, const Descriptor* descriptor) } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { qpid::types::Variant body = v; - onBody(body, *descriptor); + onAmqpValue(body); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got timestamp value with no descriptor."); @@ -716,7 +635,8 @@ bool MessageReader::onStartArray(uint32_t count, const CharSequence& raw, const return delegate->onStartArray(count, raw, constructor, descriptor); } else { if (descriptor && descriptor->match(AMQP_VALUE_SYMBOL, AMQP_VALUE_CODE)) { - onBody(raw, *descriptor); + //TODO: might be better to decode this here + onAmqpValue(raw, qpid::amqp::typecodes::ARRAY_NAME); } else { if (!descriptor) { QPID_LOG(warning, "Expected described type but got array with no descriptor."); diff --git a/qpid/cpp/src/qpid/amqp/MessageReader.h b/qpid/cpp/src/qpid/amqp/MessageReader.h index 5d26b288f5..4e2248070b 100644 --- a/qpid/cpp/src/qpid/amqp/MessageReader.h +++ b/qpid/cpp/src/qpid/amqp/MessageReader.h @@ -24,7 +24,6 @@ #include "qpid/amqp/CharSequence.h" #include "qpid/amqp/Reader.h" -#include "qpid/amqp/ListReader.h" #include "qpid/types/Variant.h" #include "qpid/CommonImportExport.h" @@ -40,11 +39,11 @@ class MessageReader : public Reader QPID_COMMON_EXTERN MessageReader(); //header, properties, amqp-sequence, amqp-value - QPID_COMMON_EXTERN bool onStartList(uint32_t, const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN bool onStartList(uint32_t, const CharSequence&, const CharSequence&, const Descriptor*); QPID_COMMON_EXTERN void onEndList(uint32_t, const Descriptor*); //delivery-annotations, message-annotations, application-headers, amqp-value - QPID_COMMON_EXTERN bool onStartMap(uint32_t, const CharSequence&, const Descriptor*); + QPID_COMMON_EXTERN bool onStartMap(uint32_t, const CharSequence&, const CharSequence&, const Descriptor*); QPID_COMMON_EXTERN void onEndMap(uint32_t, const Descriptor*); //data, amqp-value @@ -95,175 +94,24 @@ class MessageReader : public Reader virtual void onGroupSequence(uint32_t) = 0; virtual void onReplyToGroupId(const CharSequence&) = 0; - virtual void onApplicationProperties(const CharSequence&) = 0; - virtual void onDeliveryAnnotations(const CharSequence&) = 0; - virtual void onMessageAnnotations(const CharSequence&) = 0; - virtual void onBody(const CharSequence&, const Descriptor&) = 0; - virtual void onBody(const qpid::types::Variant&, const Descriptor&) = 0; - virtual void onFooter(const CharSequence&) = 0; + virtual void onApplicationProperties(const CharSequence& /*values*/, const CharSequence& /*full*/) = 0; + virtual void onDeliveryAnnotations(const CharSequence& /*values*/, const CharSequence& /*full*/) = 0; + virtual void onMessageAnnotations(const CharSequence& /*values*/, const CharSequence& /*full*/) = 0; + + virtual void onData(const CharSequence&) = 0; + virtual void onAmqpSequence(const CharSequence&) = 0; + virtual void onAmqpValue(const CharSequence&, const std::string& type) = 0; + virtual void onAmqpValue(const qpid::types::Variant&) = 0; + + virtual void onFooter(const CharSequence& /*values*/, const CharSequence& /*full*/) = 0; QPID_COMMON_EXTERN CharSequence getBareMessage() const; private: - /* - class DurableReader : public Reader - { - public: - DurableReader(MessageReader&); - void onBoolean(bool v, const Descriptor*); - private: - MessageReader& parent; - }; - class PriorityReader : public Reader - { - public: - PriorityReader(MessageReader&); - void onUByte(uint8_t v, const Descriptor*); - private: - MessageReader& parent; - }; - class TtlReader : public Reader - { - public: - TtlReader(MessageReader&); - void onUInt(uint32_t v, const Descriptor*); - private: - MessageReader& parent; - }; - class FirstAcquirerReader : public Reader - { - public: - FirstAcquirerReader(MessageReader&); - void onBoolean(bool v, const Descriptor*); - private: - MessageReader& parent; - }; - class DeliveryCountReader : public Reader - { - public: - DeliveryCountReader(MessageReader&); - void onUInt(uint32_t v, const Descriptor*); - private: - MessageReader& parent; - }; - class MessageIdReader : public Reader - { - public: - MessageIdReader(MessageReader&); - void onUuid(const qpid::types::Uuid& v, const Descriptor*); - void onULong(uint64_t v, const Descriptor*); - void onString(const CharSequence& v, const Descriptor*); - void onBinary(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - class UserIdReader : public Reader - { - public: - UserIdReader(MessageReader&); - void onBinary(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - class ToReader : public Reader + class HeaderReader : public Reader { public: - ToReader(MessageReader&); - void onString(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - class SubjectReader : public Reader - { - public: - SubjectReader(MessageReader&); - void onString(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - class ReplyToReader : public Reader - { - public: - ReplyToReader(MessageReader&); - void onString(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - class CorrelationIdReader : public Reader - { - public: - CorrelationIdReader(MessageReader&); - void onUuid(const qpid::types::Uuid& v, const Descriptor*); - void onULong(uint64_t v, const Descriptor*); - void onString(const CharSequence& v, const Descriptor*); - void onBinary(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - class ContentTypeReader : public Reader - { - public: - ContentTypeReader(MessageReader&); - void onString(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - class ContentEncodingReader : public Reader - { - public: - ContentEncodingReader(MessageReader&); - void onString(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - class AbsoluteExpiryTimeReader : public Reader - { - public: - AbsoluteExpiryTimeReader(MessageReader&); - void onTimestamp(int64_t v, const Descriptor*); - private: - MessageReader& parent; - }; - class CreationTimeReader : public Reader - { - public: - CreationTimeReader(MessageReader&); - void onTimestamp(int64_t v, const Descriptor*); - private: - MessageReader& parent; - }; - class GroupIdReader : public Reader - { - public: - GroupIdReader(MessageReader&); - void onString(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - class GroupSequenceReader : public Reader - { - public: - GroupSequenceReader(MessageReader&); - void onUInt(uint32_t v, const Descriptor*); - private: - MessageReader& parent; - }; - class ReplyToGroupIdReader : public Reader - { - public: - ReplyToGroupIdReader(MessageReader&); - void onString(const CharSequence& v, const Descriptor*); - private: - MessageReader& parent; - }; - */ - - class HeaderReader : public Reader //public ListReader - { - public: - //Reader& getReader(size_t index); - HeaderReader(MessageReader&); void onBoolean(bool v, const Descriptor*); // durable, first-acquirer void onUByte(uint8_t v, const Descriptor*); // priority @@ -273,11 +121,9 @@ class MessageReader : public Reader MessageReader& parent; size_t index; }; - class PropertiesReader : public Reader //public ListReader + class PropertiesReader : public Reader { public: - //Reader& getReader(size_t index); - PropertiesReader(MessageReader&); void onUuid(const CharSequence& v, const Descriptor*); // message-id, correlation-id void onULong(uint64_t v, const Descriptor*); // message-id, correlation-id @@ -287,6 +133,20 @@ class MessageReader : public Reader void onTimestamp(int64_t v, const Descriptor*); // absolute-expiry-time, creation-time void onUInt(uint32_t v, const Descriptor*); // group-sequence void onNull(const Descriptor*); + + void onBoolean(bool, const Descriptor*); + void onUByte(uint8_t, const Descriptor*); + void onUShort(uint16_t, const Descriptor*); + void onByte(int8_t, const Descriptor*); + void onShort(int16_t, const Descriptor*); + void onInt(int32_t, const Descriptor*); + void onLong(int64_t, const Descriptor*); + void onFloat(float, const Descriptor*); + void onDouble(double, const Descriptor*); + bool onStartList(uint32_t /*count*/, const CharSequence& /*elements*/, const CharSequence& /*complete*/, const Descriptor*); + bool onStartMap(uint32_t /*count*/, const CharSequence& /*elements*/, const CharSequence& /*complete*/, const Descriptor*); + bool onStartArray(uint32_t /*count*/, const CharSequence&, const Constructor&, const Descriptor*); + private: MessageReader& parent; size_t index; diff --git a/qpid/cpp/src/qpid/amqp/Reader.h b/qpid/cpp/src/qpid/amqp/Reader.h index 64019d1521..32f33dc33f 100644 --- a/qpid/cpp/src/qpid/amqp/Reader.h +++ b/qpid/cpp/src/qpid/amqp/Reader.h @@ -63,8 +63,8 @@ class Reader * @return true to get elements of the compound value, false * to skip over it */ - virtual bool onStartList(uint32_t /*count*/, const CharSequence&, const Descriptor*) { return true; } - virtual bool onStartMap(uint32_t /*count*/, const CharSequence&, const Descriptor*) { return true; } + virtual bool onStartList(uint32_t /*count*/, const CharSequence& /*elements*/, const CharSequence& /*complete*/, const Descriptor*) { return true; } + virtual bool onStartMap(uint32_t /*count*/, const CharSequence& /*elements*/, const CharSequence& /*complete*/, const Descriptor*) { return true; } virtual bool onStartArray(uint32_t /*count*/, const CharSequence&, const Constructor&, const Descriptor*) { return true; } virtual void onEndList(uint32_t /*count*/, const Descriptor*) {} virtual void onEndMap(uint32_t /*count*/, const Descriptor*) {} diff --git a/qpid/cpp/src/qpid/amqp/Sasl.h b/qpid/cpp/src/qpid/amqp/Sasl.h index 558f6071fc..8235a9b9ed 100644 --- a/qpid/cpp/src/qpid/amqp/Sasl.h +++ b/qpid/cpp/src/qpid/amqp/Sasl.h @@ -35,12 +35,12 @@ namespace amqp { class Sasl : protected Reader { public: - Sasl(const std::string& id); - virtual ~Sasl(); - std::size_t read(const char* data, size_t available); - std::size_t write(char* data, size_t available); - std::size_t readProtocolHeader(const char* buffer, std::size_t size); - std::size_t writeProtocolHeader(char* buffer, std::size_t size); + QPID_COMMON_EXTERN Sasl(const std::string& id); + QPID_COMMON_EXTERN virtual ~Sasl(); + QPID_COMMON_EXTERN std::size_t read(const char* data, size_t available); + QPID_COMMON_EXTERN std::size_t write(char* data, size_t available); + QPID_COMMON_EXTERN std::size_t readProtocolHeader(const char* buffer, std::size_t size); + QPID_COMMON_EXTERN std::size_t writeProtocolHeader(char* buffer, std::size_t size); protected: const std::string id; std::vector<char> buffer; diff --git a/qpid/cpp/src/qpid/amqp/SaslClient.cpp b/qpid/cpp/src/qpid/amqp/SaslClient.cpp index 69660e9294..d8a38750c5 100644 --- a/qpid/cpp/src/qpid/amqp/SaslClient.cpp +++ b/qpid/cpp/src/qpid/amqp/SaslClient.cpp @@ -116,7 +116,7 @@ class SaslOutcomeReader : public Reader }; } -bool SaslClient::onStartList(uint32_t count, const CharSequence& arguments, const Descriptor* descriptor) +bool SaslClient::onStartList(uint32_t count, const CharSequence& arguments, const CharSequence& /*full raw data*/, const Descriptor* descriptor) { if (!descriptor) { QPID_LOG(error, "Expected described type in SASL negotiation but got no descriptor"); diff --git a/qpid/cpp/src/qpid/amqp/SaslClient.h b/qpid/cpp/src/qpid/amqp/SaslClient.h index 9f3eefadc2..d22887de1a 100644 --- a/qpid/cpp/src/qpid/amqp/SaslClient.h +++ b/qpid/cpp/src/qpid/amqp/SaslClient.h @@ -21,6 +21,7 @@ * under the License. * */ +#include <qpid/CommonImportExport.h> #include "qpid/amqp/Sasl.h" namespace qpid { @@ -33,19 +34,19 @@ namespace amqp { class SaslClient : public Sasl { public: - SaslClient(const std::string& id); - virtual ~SaslClient(); - virtual void mechanisms(const std::string&) = 0; - virtual void challenge(const std::string&) = 0; - virtual void challenge() = 0; //null != empty string - virtual void outcome(uint8_t result, const std::string&) = 0; - virtual void outcome(uint8_t result) = 0; + QPID_COMMON_EXTERN SaslClient(const std::string& id); + QPID_COMMON_EXTERN virtual ~SaslClient(); + QPID_COMMON_EXTERN virtual void mechanisms(const std::string&) = 0; + QPID_COMMON_EXTERN virtual void challenge(const std::string&) = 0; + QPID_COMMON_EXTERN virtual void challenge() = 0; //null != empty string + QPID_COMMON_EXTERN virtual void outcome(uint8_t result, const std::string&) = 0; + QPID_COMMON_EXTERN virtual void outcome(uint8_t result) = 0; - void init(const std::string& mechanism, const std::string* response, const std::string* hostname); - void response(const std::string*); + QPID_COMMON_EXTERN void init(const std::string& mechanism, const std::string* response, const std::string* hostname); + QPID_COMMON_EXTERN void response(const std::string*); private: - bool onStartList(uint32_t count, const CharSequence& arguments, const Descriptor* descriptor); + QPID_COMMON_EXTERN bool onStartList(uint32_t count, const CharSequence& arguments, const CharSequence&, const Descriptor* descriptor); }; diff --git a/qpid/cpp/src/qpid/amqp/SaslServer.cpp b/qpid/cpp/src/qpid/amqp/SaslServer.cpp index 403730ad69..250858bda0 100644 --- a/qpid/cpp/src/qpid/amqp/SaslServer.cpp +++ b/qpid/cpp/src/qpid/amqp/SaslServer.cpp @@ -158,7 +158,7 @@ class SaslResponseReader : public Reader }; } -bool SaslServer::onStartList(uint32_t count, const CharSequence& arguments, const Descriptor* descriptor) +bool SaslServer::onStartList(uint32_t count, const CharSequence& arguments, const CharSequence& /*full raw data*/, const Descriptor* descriptor) { if (!descriptor) { QPID_LOG(error, "Expected described type in SASL negotiation but got no descriptor"); diff --git a/qpid/cpp/src/qpid/amqp/SaslServer.h b/qpid/cpp/src/qpid/amqp/SaslServer.h index 43b960454f..68d0854488 100644 --- a/qpid/cpp/src/qpid/amqp/SaslServer.h +++ b/qpid/cpp/src/qpid/amqp/SaslServer.h @@ -33,17 +33,17 @@ namespace amqp { class SaslServer : public Sasl { public: - SaslServer(const std::string& id); - virtual ~SaslServer(); + QPID_COMMON_EXTERN SaslServer(const std::string& id); + QPID_COMMON_EXTERN virtual ~SaslServer(); virtual void init(const std::string& mechanism, const std::string* response, const std::string* hostname) = 0; virtual void response(const std::string*) = 0; - void mechanisms(const std::string& mechanisms); - void challenge(const std::string*); - void completed(bool succeeded); + QPID_COMMON_EXTERN void mechanisms(const std::string& mechanisms); + QPID_COMMON_EXTERN void challenge(const std::string*); + QPID_COMMON_EXTERN void completed(bool succeeded); private: - bool onStartList(uint32_t count, const CharSequence& arguments, const Descriptor* descriptor); + QPID_COMMON_EXTERN bool onStartList(uint32_t count, const CharSequence& arguments, const CharSequence&, const Descriptor* descriptor); }; }} // namespace qpid::amqp diff --git a/qpid/cpp/src/qpid/amqp/descriptors.h b/qpid/cpp/src/qpid/amqp/descriptors.h index 248d6df2df..e395fc25d7 100644 --- a/qpid/cpp/src/qpid/amqp/descriptors.h +++ b/qpid/cpp/src/qpid/amqp/descriptors.h @@ -52,6 +52,7 @@ const Descriptor DELIVERY_ANNOTATIONS(DELIVERY_ANNOTATIONS_CODE); const Descriptor MESSAGE_ANNOTATIONS(MESSAGE_ANNOTATIONS_CODE); const Descriptor PROPERTIES(PROPERTIES_CODE); const Descriptor APPLICATION_PROPERTIES(APPLICATION_PROPERTIES_CODE); +const Descriptor AMQP_VALUE(AMQP_VALUE_CODE); const Descriptor DATA(DATA_CODE); } diff --git a/qpid/cpp/src/qpid/amqp/typecodes.h b/qpid/cpp/src/qpid/amqp/typecodes.h index 3c6bd17b97..915b75ca3f 100644 --- a/qpid/cpp/src/qpid/amqp/typecodes.h +++ b/qpid/cpp/src/qpid/amqp/typecodes.h @@ -83,7 +83,7 @@ const uint8_t ARRAY32(0xf0); const std::string NULL_NAME("null"); -const std::string BOOLEAN_NAME("name"); +const std::string BOOLEAN_NAME("bool"); const std::string UBYTE_NAME("ubyte"); const std::string USHORT_NAME("ushort"); diff --git a/qpid/cpp/src/qpid/amqp_0_10/Codecs.h b/qpid/cpp/src/qpid/amqp_0_10/Codecs.h new file mode 100644 index 0000000000..408307eb7a --- /dev/null +++ b/qpid/cpp/src/qpid/amqp_0_10/Codecs.h @@ -0,0 +1,86 @@ +#ifndef QPID_AMQP_0_10_CODECS_H +#define QPID_AMQP_0_10_CODECS_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/CommonImportExport.h" +#include "qpid/types/Variant.h" +#include "boost/shared_ptr.hpp" + +namespace qpid { +namespace framing { +class FieldTable; +class FieldValue; +} +namespace amqp_0_10 { +/** + * Codec for encoding/decoding a map of Variants using the AMQP 0-10 + * map encoding. + */ +class QPID_COMMON_CLASS_EXTERN MapCodec +{ + public: + typedef qpid::types::Variant::Map ObjectType; + static void QPID_COMMON_EXTERN encode(const ObjectType&, std::string&); + static void QPID_COMMON_EXTERN decode(const std::string&, ObjectType&); + static size_t QPID_COMMON_EXTERN encodedSize(const ObjectType&); + static const QPID_COMMON_EXTERN std::string contentType; + private: +}; + +/** + * Codec for encoding/decoding a list of Variants using the AMQP 0-10 + * list encoding. + */ +class QPID_COMMON_CLASS_EXTERN ListCodec +{ + public: + typedef qpid::types::Variant::List ObjectType; + static void QPID_COMMON_EXTERN encode(const ObjectType&, std::string&); + static void QPID_COMMON_EXTERN decode(const std::string&, ObjectType&); + static size_t QPID_COMMON_EXTERN encodedSize(const ObjectType&); + static const QPID_COMMON_EXTERN std::string contentType; + private: +}; + +/** + * @internal + * + * Conversion functions between qpid::types:Variant::Map and the + * deprecated qpid::framing::FieldTable. + * + */ +QPID_COMMON_EXTERN void translate(const qpid::types::Variant::Map& from, + qpid::framing::FieldTable& to); +QPID_COMMON_EXTERN void translate(const qpid::types::Variant::Map& from, const std::string& efield, const qpid::types::Variant& evalue, + qpid::framing::FieldTable& to); +QPID_COMMON_EXTERN void translate(const qpid::framing::FieldTable& from, + qpid::types::Variant::Map& to); + +QPID_COMMON_EXTERN void translate(const boost::shared_ptr<qpid::framing::FieldValue> from, + qpid::types::Variant& to); +QPID_COMMON_EXTERN void translate(const types::Variant& from, + boost::shared_ptr<qpid::framing::FieldValue> to); + +}} // namespace qpid::amqp_0_10 + +#endif /*!QPID_AMQP_0_10_CODECS_H*/ diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp index 69894e1633..85900f8061 100644 --- a/qpid/cpp/src/qpid/broker/Broker.cpp +++ b/qpid/cpp/src/qpid/broker/Broker.cpp @@ -38,6 +38,7 @@ #include "qpid/broker/PersistableObject.h" #include "qpid/broker/QueueFlowLimit.h" #include "qpid/broker/QueueSettings.h" +#include "qpid/broker/TransactionObserver.h" #include "qpid/broker/MessageGroupManager.h" #include "qmf/org/apache/qpid/broker/Package.h" @@ -139,7 +140,7 @@ Broker::Options::Options(const std::string& name) : requireEncrypted(false), knownHosts(knownHostsNone), qmf2Support(true), - qmf1Support(true), + qmf1Support(false), queueFlowStopRatio(80), queueFlowResumeRatio(70), queueThresholdEventRatio(80), @@ -399,7 +400,7 @@ boost::intrusive_ptr<Broker> Broker::create(const Options& opts) return boost::intrusive_ptr<Broker>(new Broker(opts)); } -void Broker::setStore (boost::shared_ptr<MessageStore>& _store) +void Broker::setStore (const boost::shared_ptr<MessageStore>& _store) { store.reset(new MessageStoreModule (_store)); setStore(); @@ -442,6 +443,8 @@ void Broker::shutdown() { } Broker::~Broker() { + if (mgmtObject != 0) + mgmtObject->debugStats("destroying"); shutdown(); finalize(); // Finalize any plugins. if (config.auth) @@ -1446,7 +1449,7 @@ void Broker::bind(const std::string& queueName, throw framing::NotFoundException(QPID_MSG("Bind failed. No such exchange: " << exchangeName)); } else { if (queue->bind(exchange, key, arguments)) { - getConfigurationObservers().bind(exchange, queue, key, arguments); + getBrokerObservers().bind(exchange, queue, key, arguments); if (managementAgent.get()) { managementAgent->raiseEvent(_qmf::EventBind(connectionId, userId, exchangeName, queueName, key, ManagementAgent::toMap(arguments))); @@ -1488,7 +1491,7 @@ void Broker::unbind(const std::string& queueName, if (exchange->isDurable() && queue->isDurable()) { store->unbind(*exchange, *queue, key, qpid::framing::FieldTable()); } - getConfigurationObservers().unbind( + getBrokerObservers().unbind( exchange, queue, key, framing::FieldTable()); if (managementAgent.get()) { managementAgent->raiseEvent(_qmf::EventUnbind(connectionId, userId, exchangeName, queueName, key)); diff --git a/qpid/cpp/src/qpid/broker/Broker.h b/qpid/cpp/src/qpid/broker/Broker.h index 52b79a0944..3e22fb491b 100644 --- a/qpid/cpp/src/qpid/broker/Broker.h +++ b/qpid/cpp/src/qpid/broker/Broker.h @@ -38,7 +38,7 @@ #include "qpid/broker/System.h" #include "qpid/broker/ConsumerFactory.h" #include "qpid/broker/ConnectionObservers.h" -#include "qpid/broker/ConfigurationObservers.h" +#include "qpid/broker/BrokerObservers.h" #include "qpid/management/Manageable.h" #include "qpid/sys/ConnectionCodec.h" #include "qpid/sys/Mutex.h" @@ -65,6 +65,7 @@ class AclModule; class ExpiryPolicy; class Message; struct QueueSettings; + static const uint16_t DEFAULT_PORT=5672; struct NoSuchTransportException : qpid::Exception @@ -175,7 +176,7 @@ class Broker : public sys::Runnable, public Plugin::Target, AclModule* acl; DataDir dataDir; ConnectionObservers connectionObservers; - ConfigurationObservers configurationObservers; + BrokerObservers brokerObservers; QueueRegistry queues; ExchangeRegistry exchanges; @@ -225,7 +226,8 @@ class Broker : public sys::Runnable, public Plugin::Target, /** Shut down the broker */ QPID_BROKER_EXTERN virtual void shutdown(); - QPID_BROKER_EXTERN void setStore (boost::shared_ptr<MessageStore>& store); + QPID_BROKER_EXTERN void setStore (const boost::shared_ptr<MessageStore>& store); + bool hasStore() const { return store.get(); } MessageStore& getStore() { return *store; } void setAcl (AclModule* _acl) {acl = _acl;} AclModule* getAcl() { return acl; } @@ -352,7 +354,7 @@ class Broker : public sys::Runnable, public Plugin::Target, ConsumerFactories& getConsumerFactories() { return consumerFactories; } ConnectionObservers& getConnectionObservers() { return connectionObservers; } - ConfigurationObservers& getConfigurationObservers() { return configurationObservers; } + BrokerObservers& getBrokerObservers() { return brokerObservers; } /** Properties to be set on outgoing link connections */ QPID_BROKER_EXTERN framing::FieldTable getLinkClientProperties() const; diff --git a/qpid/cpp/src/qpid/broker/ConfigurationObserver.h b/qpid/cpp/src/qpid/broker/BrokerObserver.h index 789490e08c..2249d33e64 100644 --- a/qpid/cpp/src/qpid/broker/ConfigurationObserver.h +++ b/qpid/cpp/src/qpid/broker/BrokerObserver.h @@ -1,5 +1,5 @@ -#ifndef QPID_BROKER_CONFIGURATIONOBSERVER_H -#define QPID_BROKER_CONFIGURATIONOBSERVER_H +#ifndef QPID_BROKER_BROKEROBSERVER_H +#define QPID_BROKER_BROKEROBSERVER_H /* * @@ -34,7 +34,8 @@ class FieldTable; namespace broker { class Queue; class Exchange; - +class TxBuffer; +class DtxBuffer; /** * Observer for changes to configuration (aka wiring) @@ -43,10 +44,10 @@ class Exchange; * the registry lock held. This is necessary to ensure * they are called in the correct sequence. */ -class ConfigurationObserver +class BrokerObserver { public: - virtual ~ConfigurationObserver() {} + virtual ~BrokerObserver() {} virtual void queueCreate(const boost::shared_ptr<Queue>&) {} virtual void queueDestroy(const boost::shared_ptr<Queue>&) {} virtual void exchangeCreate(const boost::shared_ptr<Exchange>&) {} @@ -59,7 +60,9 @@ class ConfigurationObserver const boost::shared_ptr<Queue>& , const std::string& /*key*/, const framing::FieldTable& /*args*/) {} + virtual void startTx(const boost::shared_ptr<TxBuffer>&) {} + virtual void startDtx(const boost::shared_ptr<DtxBuffer>&) {} }; }} // namespace qpid::broker -#endif /*!QPID_BROKER_CONFIGURATIONOBSERVER_H*/ +#endif /*!QPID_BROKER_BROKEROBSERVER_H*/ diff --git a/qpid/cpp/src/qpid/broker/ConfigurationObservers.h b/qpid/cpp/src/qpid/broker/BrokerObservers.h index 4c1159747d..5ba7bac890 100644 --- a/qpid/cpp/src/qpid/broker/ConfigurationObservers.h +++ b/qpid/cpp/src/qpid/broker/BrokerObservers.h @@ -1,5 +1,5 @@ -#ifndef QPID_BROKER_CONFIGURATIONOBSERVERS_H -#define QPID_BROKER_CONFIGURATIONOBSERVERS_H +#ifndef QPID_BROKER_BROKEROBSERVERS_H +#define QPID_BROKER_BROKEROBSERVERS_H /* * @@ -22,7 +22,7 @@ * */ -#include "ConfigurationObserver.h" +#include "BrokerObserver.h" #include "Observers.h" #include "qpid/sys/Mutex.h" @@ -30,43 +30,48 @@ namespace qpid { namespace broker { /** - * A configuration observer that delegates to a collection of - * configuration observers. + * A broker observer that delegates to a collection of broker observers. * * THREAD SAFE */ -class ConfigurationObservers : public ConfigurationObserver, - public Observers<ConfigurationObserver> +class BrokerObservers : public BrokerObserver, + public Observers<BrokerObserver> { public: void queueCreate(const boost::shared_ptr<Queue>& q) { - each(boost::bind(&ConfigurationObserver::queueCreate, _1, q)); + each(boost::bind(&BrokerObserver::queueCreate, _1, q)); } void queueDestroy(const boost::shared_ptr<Queue>& q) { - each(boost::bind(&ConfigurationObserver::queueDestroy, _1, q)); + each(boost::bind(&BrokerObserver::queueDestroy, _1, q)); } void exchangeCreate(const boost::shared_ptr<Exchange>& e) { - each(boost::bind(&ConfigurationObserver::exchangeCreate, _1, e)); + each(boost::bind(&BrokerObserver::exchangeCreate, _1, e)); } void exchangeDestroy(const boost::shared_ptr<Exchange>& e) { - each(boost::bind(&ConfigurationObserver::exchangeDestroy, _1, e)); + each(boost::bind(&BrokerObserver::exchangeDestroy, _1, e)); } void bind(const boost::shared_ptr<Exchange>& exchange, const boost::shared_ptr<Queue>& queue, const std::string& key, const framing::FieldTable& args) { each(boost::bind( - &ConfigurationObserver::bind, _1, exchange, queue, key, args)); + &BrokerObserver::bind, _1, exchange, queue, key, args)); } void unbind(const boost::shared_ptr<Exchange>& exchange, const boost::shared_ptr<Queue>& queue, const std::string& key, const framing::FieldTable& args) { each(boost::bind( - &ConfigurationObserver::unbind, _1, exchange, queue, key, args)); + &BrokerObserver::unbind, _1, exchange, queue, key, args)); + } + void startTx(const boost::shared_ptr<TxBuffer>& tx) { + each(boost::bind(&BrokerObserver::startTx, _1, tx)); + } + void startDtx(const boost::shared_ptr<DtxBuffer>& dtx) { + each(boost::bind(&BrokerObserver::startDtx, _1, dtx)); } }; }} // namespace qpid::broker -#endif /*!QPID_BROKER_CONFIGURATIONOBSERVERS_H*/ +#endif /*!QPID_BROKER_BROKEROBSERVERS_H*/ diff --git a/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp b/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp index 14a2e94571..06ecf62ed4 100644 --- a/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp +++ b/qpid/cpp/src/qpid/broker/DeliveryRecord.cpp @@ -106,7 +106,9 @@ void DeliveryRecord::dequeue(TransactionContext* ctxt) const void DeliveryRecord::committed() const { - queue->dequeueCommitted(msg); + if (acquired && !ended) { + queue->dequeueCommitted(msg); + } } void DeliveryRecord::reject() diff --git a/qpid/cpp/src/qpid/broker/DirectExchange.cpp b/qpid/cpp/src/qpid/broker/DirectExchange.cpp index 773a99d2c9..8ab7b59ed1 100644 --- a/qpid/cpp/src/qpid/broker/DirectExchange.cpp +++ b/qpid/cpp/src/qpid/broker/DirectExchange.cpp @@ -196,6 +196,9 @@ bool DirectExchange::isBound(Queue::shared_ptr queue, const string* const routin return false; } -DirectExchange::~DirectExchange() {} +DirectExchange::~DirectExchange() { + if (mgmtExchange != 0) + mgmtExchange->debugStats("destroying"); +} const std::string DirectExchange::typeName("direct"); diff --git a/qpid/cpp/src/qpid/broker/DirectExchange.h b/qpid/cpp/src/qpid/broker/DirectExchange.h index 833be52c1c..cfefef54e8 100644 --- a/qpid/cpp/src/qpid/broker/DirectExchange.h +++ b/qpid/cpp/src/qpid/broker/DirectExchange.h @@ -42,7 +42,7 @@ class DirectExchange : public virtual Exchange { qpid::sys::Mutex lock; public: - static const std::string typeName; + QPID_BROKER_EXTERN static const std::string typeName; QPID_BROKER_EXTERN DirectExchange(const std::string& name, management::Manageable* parent = 0, Broker* broker = 0); diff --git a/qpid/cpp/src/qpid/broker/DtxAck.h b/qpid/cpp/src/qpid/broker/DtxAck.h index 10d63f5b0c..5775edf5de 100644 --- a/qpid/cpp/src/qpid/broker/DtxAck.h +++ b/qpid/cpp/src/qpid/broker/DtxAck.h @@ -39,6 +39,9 @@ class DtxAck : public TxOp{ virtual bool prepare(TransactionContext* ctxt) throw(); virtual void commit() throw(); virtual void rollback() throw(); + // TODO aconway 2013-07-08: + virtual void callObserver(const boost::shared_ptr<TransactionObserver>&) {} + virtual ~DtxAck(){} const DeliveryRecords& getPending() const { return pending; } }; diff --git a/qpid/cpp/src/qpid/broker/Exchange.cpp b/qpid/cpp/src/qpid/broker/Exchange.cpp index b9080cdda5..0a25d57cd8 100644 --- a/qpid/cpp/src/qpid/broker/Exchange.cpp +++ b/qpid/cpp/src/qpid/broker/Exchange.cpp @@ -353,6 +353,7 @@ Exchange::Binding::Binding(const string& _key, Queue::shared_ptr _queue, Exchang Exchange::Binding::~Binding () { if (mgmtBinding != 0) { + mgmtBinding->debugStats("destroying"); _qmf::Queue::shared_ptr mo = boost::dynamic_pointer_cast<_qmf::Queue>(queue->GetManagementObject()); if (mo != 0) mo->dec_bindingCount(); diff --git a/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp b/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp index 645918d526..9eeffadb90 100644 --- a/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp +++ b/qpid/cpp/src/qpid/broker/ExchangeRegistry.cpp @@ -81,7 +81,7 @@ pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare( result = std::pair<Exchange::shared_ptr, bool>(exchange, true); if (alternate) exchange->setAlternate(alternate); // Call exchangeCreate inside the lock to ensure correct ordering. - if (broker) broker->getConfigurationObservers().exchangeCreate(exchange); + if (broker) broker->getBrokerObservers().exchangeCreate(exchange); } else { result = std::pair<Exchange::shared_ptr, bool>(i->second, false); } @@ -118,7 +118,7 @@ void ExchangeRegistry::destroy( if (broker) { // Call exchangeDestroy and raiseEvent inside the lock to ensure // correct ordering. - broker->getConfigurationObservers().exchangeDestroy(i->second); + broker->getBrokerObservers().exchangeDestroy(i->second); if (broker->getManagementAgent()) broker->getManagementAgent()->raiseEvent( _qmf::EventExchangeDelete(connectionId, userId, name)); diff --git a/qpid/cpp/src/qpid/broker/FanOutExchange.cpp b/qpid/cpp/src/qpid/broker/FanOutExchange.cpp index 43c67af810..20ca06e048 100644 --- a/qpid/cpp/src/qpid/broker/FanOutExchange.cpp +++ b/qpid/cpp/src/qpid/broker/FanOutExchange.cpp @@ -117,6 +117,9 @@ bool FanOutExchange::isBound(Queue::shared_ptr queue, const string* const, const } -FanOutExchange::~FanOutExchange() {} +FanOutExchange::~FanOutExchange() { + if (mgmtExchange != 0) + mgmtExchange->debugStats("destroying"); +} const std::string FanOutExchange::typeName("fanout"); diff --git a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp index 82284feaeb..4e86b09565 100644 --- a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp +++ b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp @@ -339,7 +339,10 @@ void HeadersExchange::getNonFedArgs(const FieldTable* args, FieldTable& nonFedAr } } -HeadersExchange::~HeadersExchange() {} +HeadersExchange::~HeadersExchange() { + if (mgmtExchange != 0) + mgmtExchange->debugStats("destroying"); +} const std::string HeadersExchange::typeName("headers"); diff --git a/qpid/cpp/src/qpid/broker/HeadersExchange.h b/qpid/cpp/src/qpid/broker/HeadersExchange.h index b5b10350d2..e51478d365 100644 --- a/qpid/cpp/src/qpid/broker/HeadersExchange.h +++ b/qpid/cpp/src/qpid/broker/HeadersExchange.h @@ -79,7 +79,7 @@ class HeadersExchange : public virtual Exchange { framing::FieldTable& nonFedArgs); public: - static const std::string typeName; + QPID_BROKER_EXTERN static const std::string typeName; QPID_BROKER_EXTERN HeadersExchange(const std::string& name, management::Manageable* parent = 0, Broker* broker = 0); diff --git a/qpid/cpp/src/qpid/broker/IngressCompletion.h b/qpid/cpp/src/qpid/broker/IngressCompletion.h index 28bb9cf03d..ca21ec9837 100644 --- a/qpid/cpp/src/qpid/broker/IngressCompletion.h +++ b/qpid/cpp/src/qpid/broker/IngressCompletion.h @@ -38,7 +38,7 @@ class Queue; class IngressCompletion : public AsyncCompletion { public: - virtual ~IngressCompletion(); + QPID_BROKER_EXTERN virtual ~IngressCompletion(); void enqueueAsync(boost::shared_ptr<Queue>); void flush(); diff --git a/qpid/cpp/src/qpid/broker/Link.cpp b/qpid/cpp/src/qpid/broker/Link.cpp index 31685eb1de..cd7ba35dd8 100644 --- a/qpid/cpp/src/qpid/broker/Link.cpp +++ b/qpid/cpp/src/qpid/broker/Link.cpp @@ -536,7 +536,7 @@ bool Link::tryFailoverLH() { if (url.empty()) return false; Address next = url[reconnectNext++]; if (next.host != host || next.port != port || next.protocol != transport) { - QPID_LOG(notice, "Inter-broker link '" << name << "' failing over to " << next); + QPID_LOG(info, "Inter-broker link '" << name << "' failing over to " << next); reconnectLH(next); return true; } diff --git a/qpid/cpp/src/qpid/broker/Link.h b/qpid/cpp/src/qpid/broker/Link.h index d9924feec3..ceee0186f3 100644 --- a/qpid/cpp/src/qpid/broker/Link.h +++ b/qpid/cpp/src/qpid/broker/Link.h @@ -151,8 +151,8 @@ class Link : public PersistableConfig, public management::Manageable { bool isDurable() { return durable; } void maintenanceVisit (); - framing::ChannelId nextChannel(); // allocate channel from link free pool - void returnChannel(framing::ChannelId); // return channel to link free pool + QPID_BROKER_EXTERN framing::ChannelId nextChannel(); // allocate channel from link free pool + QPID_BROKER_EXTERN void returnChannel(framing::ChannelId); // return channel to link free pool void add(Bridge::shared_ptr); void cancel(Bridge::shared_ptr); diff --git a/qpid/cpp/src/qpid/broker/LossyQueue.cpp b/qpid/cpp/src/qpid/broker/LossyQueue.cpp index 4104503dac..ba7dfd11a1 100644 --- a/qpid/cpp/src/qpid/broker/LossyQueue.cpp +++ b/qpid/cpp/src/qpid/broker/LossyQueue.cpp @@ -52,7 +52,7 @@ bool LossyQueue::checkDepth(const QueueDepth& increment, const Message& message) QPID_LOG(debug, "purging " << name << ": current depth is [" << current << "], max depth is [" << settings.maxDepth << "], new message has size " << increment.getSize()); qpid::sys::Mutex::ScopedUnlock u(messageLock); //TODO: arguably we should try and purge expired messages first but that is potentially expensive - if (remove(1, settings.priorities ? boost::bind(&isLowerPriorityThan, message.getPriority(), _1) : MessagePredicate(), MessageFunctor(), PURGE, false)) { + if (remove(1, settings.priorities ? boost::bind(&isLowerPriorityThan, message.getPriority(), _1) : MessagePredicate(), boost::bind(&reroute, alternateExchange, _1), PURGE, false)) { if (mgmtObject) { mgmtObject->inc_discardsRing(1); if (brokerMgmtObject) diff --git a/qpid/cpp/src/qpid/broker/Lvq.cpp b/qpid/cpp/src/qpid/broker/Lvq.cpp index ff13b97dbd..34f080c57f 100644 --- a/qpid/cpp/src/qpid/broker/Lvq.cpp +++ b/qpid/cpp/src/qpid/broker/Lvq.cpp @@ -57,7 +57,8 @@ void Lvq::push(Message& message, bool isRecovery) copy.notify(); if (removed) { if (isRecovery) pendingDequeues.push_back(old); - else dequeueFromStore(old.getPersistentContext());//do outside of lock + else if (old.isPersistent()) + dequeueFromStore(old.getPersistentContext());//do outside of lock } } }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp index ec44404793..e71125b4ab 100644 --- a/qpid/cpp/src/qpid/broker/Message.cpp +++ b/qpid/cpp/src/qpid/broker/Message.cpp @@ -145,7 +145,7 @@ uint64_t Message::getTtl() const } } -bool Message::getTtl(uint64_t ttl) const +bool Message::getTtl(uint64_t& ttl) const { if (encoding->getTtl(ttl) && expiration < FAR_FUTURE) { sys::Duration remaining(sys::AbsTime::now(), getExpiration()); @@ -182,8 +182,10 @@ void Message::addAnnotation(const std::string& key, const qpid::types::Variant& void Message::annotationsChanged() { if (persistentContext) { + uint64_t id = persistentContext->getPersistenceId(); persistentContext = persistentContext->merge(annotations); persistentContext->setIngressCompletion(encoding); + persistentContext->setPersistenceId(id); } } diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h index 03ef21e77a..84f62a771d 100644 --- a/qpid/cpp/src/qpid/broker/Message.h +++ b/qpid/cpp/src/qpid/broker/Message.h @@ -39,7 +39,7 @@ namespace qpid { namespace amqp { class MapHandler; -class MessageId; +struct MessageId; } namespace management { @@ -104,7 +104,7 @@ public: sys::AbsTime getExpiration() const { return expiration; } void setExpiration(sys::AbsTime exp) { expiration = exp; } uint64_t getTtl() const; - bool getTtl(uint64_t) const; + QPID_BROKER_EXTERN bool getTtl(uint64_t&) const; /** set the timestamp delivery property to the current time-of-day */ QPID_BROKER_EXTERN void setTimestamp(); @@ -136,7 +136,7 @@ public: QPID_BROKER_EXTERN qpid::types::Variant getAnnotation(const std::string& key) const; QPID_BROKER_EXTERN const qpid::types::Variant::Map& getAnnotations() const; - std::string getUserId() const; + QPID_BROKER_EXTERN std::string getUserId() const; QPID_BROKER_EXTERN std::string getContent() const;//Used for ha, management, when content needs to be decoded diff --git a/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp b/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp index f19b31fa76..edfe6e7819 100644 --- a/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp +++ b/qpid/cpp/src/qpid/broker/MessageStoreModule.cpp @@ -33,7 +33,7 @@ using std::string; namespace qpid { namespace broker { -MessageStoreModule::MessageStoreModule(boost::shared_ptr<MessageStore>& _store) +MessageStoreModule::MessageStoreModule(const boost::shared_ptr<MessageStore>& _store) : store(_store) {} MessageStoreModule::~MessageStoreModule() diff --git a/qpid/cpp/src/qpid/broker/MessageStoreModule.h b/qpid/cpp/src/qpid/broker/MessageStoreModule.h index 82308db84c..a71e8cc9b6 100644 --- a/qpid/cpp/src/qpid/broker/MessageStoreModule.h +++ b/qpid/cpp/src/qpid/broker/MessageStoreModule.h @@ -38,7 +38,7 @@ class MessageStoreModule : public MessageStore { boost::shared_ptr<MessageStore> store; public: - MessageStoreModule(boost::shared_ptr<MessageStore>& store); + MessageStoreModule(const boost::shared_ptr<MessageStore>& store); bool init(const Options* options); std::auto_ptr<TransactionContext> begin(); diff --git a/qpid/cpp/src/qpid/broker/ObjectFactory.h b/qpid/cpp/src/qpid/broker/ObjectFactory.h index 1b8f0356d6..d1b570da2f 100644 --- a/qpid/cpp/src/qpid/broker/ObjectFactory.h +++ b/qpid/cpp/src/qpid/broker/ObjectFactory.h @@ -21,6 +21,7 @@ * under the License. * */ +#include "qpid/broker/BrokerImportExport.h" #include "qpid/types/Variant.h" #include <vector> @@ -56,7 +57,7 @@ class ObjectFactoryRegistry : public ObjectFactory bool recoverObject(Broker&, const std::string& type, const std::string& name, const qpid::types::Variant::Map& properties, uint64_t persistenceId); ~ObjectFactoryRegistry(); - void add(ObjectFactory*); + QPID_BROKER_EXTERN void add(ObjectFactory*); private: typedef std::vector<ObjectFactory*> Factories; Factories factories; diff --git a/qpid/cpp/src/qpid/broker/PagedQueue.cpp b/qpid/cpp/src/qpid/broker/PagedQueue.cpp index 9bce28061a..862e9c0d48 100644 --- a/qpid/cpp/src/qpid/broker/PagedQueue.cpp +++ b/qpid/cpp/src/qpid/broker/PagedQueue.cpp @@ -64,7 +64,7 @@ size_t decode(ProtocolRegistry& protocols, Message& msg, const char* data, size_ } PagedQueue::PagedQueue(const std::string& name, const std::string& directory, uint m, uint factor, ProtocolRegistry& p) - : pageSize(file.getPageSize()*factor), maxLoaded(m), protocols(p), offset(0) + : pageSize(file.getPageSize()*factor), maxLoaded(m), protocols(p), offset(0), loaded(0), version(0) { path = file.open(name, directory); QPID_LOG(debug, "PagedQueue[" << path << "]"); @@ -295,7 +295,8 @@ void PagedQueue::Page::load(MemoryMappedFile& file, ProtocolRegistry& protocols) bool haveData = used > 0; used = 4;//first 4 bytes are the count if (haveData) { - uint32_t count = *(reinterpret_cast<uint32_t*>(region)); + qpid::framing::Buffer buffer(region, sizeof(uint32_t)); + uint32_t count = buffer.getLong(); //decode messages into Page::messages for (size_t i = 0; i < count; ++i) { Message message; @@ -331,7 +332,8 @@ void PagedQueue::Page::unload(MemoryMappedFile& file) if (i->getState() == ACQUIRED) acquired.add(i->getSequence()); } uint32_t count = messages.size(); - ::memcpy(region, &count, sizeof(count)); + qpid::framing::Buffer buffer(region, sizeof(uint32_t)); + buffer.putLong(count); file.flush(region, size); file.unmap(region, size); //remove messages from memory diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.h b/qpid/cpp/src/qpid/broker/PersistableMessage.h index 85ac4a3b85..cfcf8f0afc 100644 --- a/qpid/cpp/src/qpid/broker/PersistableMessage.h +++ b/qpid/cpp/src/qpid/broker/PersistableMessage.h @@ -62,8 +62,8 @@ class PersistableMessage : public Persistable mutable uint64_t persistenceId; public: - virtual ~PersistableMessage(); - PersistableMessage(); + QPID_BROKER_EXTERN virtual ~PersistableMessage(); + QPID_BROKER_EXTERN PersistableMessage(); virtual QPID_BROKER_EXTERN bool isPersistent() const = 0; diff --git a/qpid/cpp/src/qpid/broker/PersistableObject.h b/qpid/cpp/src/qpid/broker/PersistableObject.h index c6aff466f7..4d7e5e4498 100644 --- a/qpid/cpp/src/qpid/broker/PersistableObject.h +++ b/qpid/cpp/src/qpid/broker/PersistableObject.h @@ -21,6 +21,7 @@ * under the License. * */ +#include "qpid/broker/BrokerImportExport.h" #include "PersistableConfig.h" #include "qpid/types/Variant.h" #include <vector> @@ -37,13 +38,13 @@ class RecoverableConfig; class PersistableObject : public PersistableConfig { public: - PersistableObject(const std::string& name, const std::string& type, const qpid::types::Variant::Map properties); - virtual ~PersistableObject(); - const std::string& getName() const; - void setPersistenceId(uint64_t id) const; - uint64_t getPersistenceId() const; - void encode(framing::Buffer& buffer) const; - uint32_t encodedSize() const; + QPID_BROKER_EXTERN PersistableObject(const std::string& name, const std::string& type, const qpid::types::Variant::Map properties); + QPID_BROKER_EXTERN virtual ~PersistableObject(); + QPID_BROKER_EXTERN const std::string& getName() const; + QPID_BROKER_EXTERN void setPersistenceId(uint64_t id) const; + QPID_BROKER_EXTERN uint64_t getPersistenceId() const; + QPID_BROKER_EXTERN void encode(framing::Buffer& buffer) const; + QPID_BROKER_EXTERN uint32_t encodedSize() const; friend class RecoveredObjects; private: std::string name; diff --git a/qpid/cpp/src/qpid/broker/PriorityQueue.cpp b/qpid/cpp/src/qpid/broker/PriorityQueue.cpp index 99488ded13..5e60fe5cce 100644 --- a/qpid/cpp/src/qpid/broker/PriorityQueue.cpp +++ b/qpid/cpp/src/qpid/broker/PriorityQueue.cpp @@ -135,7 +135,12 @@ void PriorityQueue::publish(const Message& published) Message* PriorityQueue::release(const QueueCursor& cursor) { MessagePointer* ptr = fifo.release(cursor); - return ptr ? &(ptr->holder->message) : 0; + if (ptr) { + messages[ptr->holder->priority].resetCursors(); + return &(ptr->holder->message); + } else { + return 0; + } } void PriorityQueue::foreach(Functor f) diff --git a/qpid/cpp/src/qpid/broker/Protocol.h b/qpid/cpp/src/qpid/broker/Protocol.h index 282e4bd83d..e736e4b367 100644 --- a/qpid/cpp/src/qpid/broker/Protocol.h +++ b/qpid/cpp/src/qpid/broker/Protocol.h @@ -72,7 +72,7 @@ class ProtocolRegistry : public Protocol QPID_BROKER_EXTERN Message decode(qpid::framing::Buffer&); QPID_BROKER_EXTERN ~ProtocolRegistry(); - void add(const std::string&, Protocol*); + QPID_BROKER_EXTERN void add(const std::string&, Protocol*); private: //name may be useful for descriptive purposes or even for some //limited manipulation of ordering diff --git a/qpid/cpp/src/qpid/broker/Queue.cpp b/qpid/cpp/src/qpid/broker/Queue.cpp index 1d0a8017ef..5a43df44a4 100644 --- a/qpid/cpp/src/qpid/broker/Queue.cpp +++ b/qpid/cpp/src/qpid/broker/Queue.cpp @@ -34,6 +34,7 @@ #include "qpid/broker/NullMessageStore.h" #include "qpid/broker/QueueRegistry.h" #include "qpid/broker/Selector.h" +#include "qpid/broker/TransactionObserver.h" //TODO: get rid of this #include "qpid/broker/amqp_0_10/MessageTransfer.h" @@ -167,6 +168,12 @@ void Queue::TxPublish::rollback() throw() } } +void Queue::TxPublish::callObserver( + const boost::shared_ptr<TransactionObserver>& observer) +{ + observer->enqueue(queue, message); +} + Queue::Queue(const string& _name, const QueueSettings& _settings, MessageStore* const _store, Manageable* parent, @@ -216,6 +223,8 @@ Queue::Queue(const string& _name, const QueueSettings& _settings, Queue::~Queue() { + if (mgmtObject != 0) + mgmtObject->debugStats("destroying"); } bool Queue::isLocal(const Message& msg) @@ -270,6 +279,7 @@ void Queue::deliver(Message msg, TxBuffer* txn) void Queue::deliverTo(Message msg, TxBuffer* txn) { if (accept(msg)) { + interceptors.record(msg); if (txn) { TxOp::shared_ptr op(new TxPublish(msg, shared_from_this())); txn->enlist(op); @@ -385,6 +395,7 @@ bool Queue::getNextMessage(Message& m, Consumer::shared_ptr& c) if (!checkNotDeleted(c)) return false; QueueListeners::NotificationSet set; ScopedAutoDelete autodelete(*this); + bool messageFound(false); while (true) { //TODO: reduce lock scope Mutex::ScopedLock locker(messageLock); @@ -426,7 +437,8 @@ bool Queue::getNextMessage(Message& m, Consumer::shared_ptr& c) QPID_LOG(debug, "Message " << msg->getSequence() << " retrieved from '" << name << "'"); m = *msg; - return true; + messageFound = true; + break; } else { //message(s) are available but consumer hasn't got enough credit QPID_LOG(debug, "Consumer can't currently accept message from '" << name << "'"); @@ -448,11 +460,12 @@ bool Queue::getNextMessage(Message& m, Consumer::shared_ptr& c) } else { QPID_LOG(debug, "No messages to dispatch on queue '" << name << "'"); listeners.addListener(c); - return false; + break; } + } set.notify(); - return false; + return messageFound; } void Queue::removeListener(Consumer::shared_ptr c) @@ -677,17 +690,6 @@ namespace { return new MessageFilter(); } - bool reroute(boost::shared_ptr<Exchange> e, const Message& m) - { - if (e) { - DeliverableMessage d(m, 0); - d.getMessage().clearTrace(); - e->routeWithAlternate(d); - return true; - } else { - return false; - } - } void moveTo(boost::shared_ptr<Queue> q, Message& m) { if (q) { @@ -846,7 +848,6 @@ bool Queue::isEmpty(const Mutex::ScopedLock&) const */ bool Queue::enqueue(TransactionContext* ctxt, Message& msg) { - interceptors.record(msg); ScopedUse u(barrier); if (!u.acquired) return false; @@ -1684,6 +1685,19 @@ void Queue::setMgmtRedirectState( std::string peer, bool enabled, bool isSrc ) { mgmtObject->set_redirectSource(isSrc); } } + +bool Queue::reroute(boost::shared_ptr<Exchange> e, const Message& m) +{ + if (e) { + DeliverableMessage d(m, 0); + d.getMessage().clearTrace(); + e->routeWithAlternate(d); + return true; + } else { + return false; + } +} + Queue::QueueUsers::QueueUsers() : consumers(0), browsers(0), others(0), controller(false) {} void Queue::QueueUsers::addConsumer() { ++consumers; } void Queue::QueueUsers::addBrowser() { ++browsers; } diff --git a/qpid/cpp/src/qpid/broker/Queue.h b/qpid/cpp/src/qpid/broker/Queue.h index 5598ee5d13..a832b95feb 100644 --- a/qpid/cpp/src/qpid/broker/Queue.h +++ b/qpid/cpp/src/qpid/broker/Queue.h @@ -118,6 +118,7 @@ class Queue : public boost::enable_shared_from_this<Queue>, bool prepare(TransactionContext* ctxt) throw(); void commit() throw(); void rollback() throw(); + void callObserver(const boost::shared_ptr<TransactionObserver>&); }; /** @@ -501,6 +502,9 @@ class Queue : public boost::enable_shared_from_this<Queue>, QPID_BROKER_EXTERN bool isRedirectSource() const { return redirectSource; } QPID_BROKER_EXTERN void setMgmtRedirectState( std::string peer, bool enabled, bool isSrc ); + //utility function + static bool reroute(boost::shared_ptr<Exchange> e, const Message& m); + friend class QueueFactory; }; } diff --git a/qpid/cpp/src/qpid/broker/QueueFactory.cpp b/qpid/cpp/src/qpid/broker/QueueFactory.cpp index 67499c9985..807026ef0d 100644 --- a/qpid/cpp/src/qpid/broker/QueueFactory.cpp +++ b/qpid/cpp/src/qpid/broker/QueueFactory.cpp @@ -33,6 +33,7 @@ #include "qpid/broker/PagedQueue.h" #include "qpid/broker/PriorityQueue.h" #include "qpid/broker/QueueFlowLimit.h" +#include "qpid/broker/SelfDestructQueue.h" #include "qpid/broker/ThresholdAlerts.h" #include "qpid/broker/FifoDistributor.h" #include "qpid/log/Statement.h" @@ -53,6 +54,8 @@ boost::shared_ptr<Queue> QueueFactory::create(const std::string& name, const Que boost::shared_ptr<Queue> queue; if (settings.dropMessagesAtLimit) { queue = boost::shared_ptr<Queue>(new LossyQueue(name, settings, settings.durable ? store : 0, parent, broker)); + } else if (settings.selfDestructAtLimit) { + queue = boost::shared_ptr<Queue>(new SelfDestructQueue(name, settings, settings.durable ? store : 0, parent, broker)); } else if (settings.lvqKey.size()) { std::auto_ptr<MessageMap> map(new MessageMap(settings.lvqKey)); queue = boost::shared_ptr<Queue>(new Lvq(name, map, settings, settings.durable ? store : 0, parent, broker)); diff --git a/qpid/cpp/src/qpid/broker/QueueRegistry.cpp b/qpid/cpp/src/qpid/broker/QueueRegistry.cpp index 13f9bbe23c..606a8cceae 100644 --- a/qpid/cpp/src/qpid/broker/QueueRegistry.cpp +++ b/qpid/cpp/src/qpid/broker/QueueRegistry.cpp @@ -59,8 +59,8 @@ QueueRegistry::declare(const string& name, const QueueSettings& settings, QueueMap::iterator i = queues.find(name); if (i == queues.end()) { Queue::shared_ptr queue = create(name, settings); - // Allow ConfigurationObserver to modify settings before storing the message. - if (getBroker()) getBroker()->getConfigurationObservers().queueCreate(queue); + // Allow BrokerObserver to modify settings before storing the message. + if (getBroker()) getBroker()->getBrokerObservers().queueCreate(queue); //Move this to factory also? if (alternate) queue->setAlternateExchange(alternate);//need to do this *before* create @@ -100,7 +100,7 @@ void QueueRegistry::destroy( // NOTE: queueDestroy and raiseEvent must be called with the // lock held in order to ensure events are generated // in the correct order. - getBroker()->getConfigurationObservers().queueDestroy(q); + getBroker()->getBrokerObservers().queueDestroy(q); if (getBroker()->getManagementAgent()) getBroker()->getManagementAgent()->raiseEvent( _qmf::EventQueueDelete(connectionId, userId, name)); @@ -121,7 +121,9 @@ Queue::shared_ptr QueueRegistry::find(const string& name){ Queue::shared_ptr QueueRegistry::get(const string& name) { Queue::shared_ptr q = find(name); - if (!q) throw framing::NotFoundException(QPID_MSG("Queue not found: "<<name)); + if (!q) { + throw framing::NotFoundException(QPID_MSG("Queue not found: "<<name)); + } return q; } diff --git a/qpid/cpp/src/qpid/broker/QueueSettings.cpp b/qpid/cpp/src/qpid/broker/QueueSettings.cpp index fd90d11d76..c505217dbb 100644 --- a/qpid/cpp/src/qpid/broker/QueueSettings.cpp +++ b/qpid/cpp/src/qpid/broker/QueueSettings.cpp @@ -38,6 +38,7 @@ const std::string MAX_FILE_SIZE("qpid.file_size"); const std::string POLICY_TYPE("qpid.policy_type"); const std::string POLICY_TYPE_REJECT("reject"); const std::string POLICY_TYPE_RING("ring"); +const std::string POLICY_TYPE_SELF_DESTRUCT("self-destruct"); const std::string NO_LOCAL("no-local"); const std::string BROWSE_ONLY("qpid.browse-only"); const std::string TRACE_ID("qpid.trace.id"); @@ -96,6 +97,7 @@ QueueSettings::QueueSettings(bool d, bool a) : shareGroups(false), addTimestamp(false), dropMessagesAtLimit(false), + selfDestructAtLimit(false), paging(false), maxPages(0), pageFactor(0), @@ -120,6 +122,9 @@ bool QueueSettings::handle(const std::string& key, const qpid::types::Variant& v if (value.getString() == POLICY_TYPE_RING) { dropMessagesAtLimit = true; return true; + } else if (value.getString() == POLICY_TYPE_SELF_DESTRUCT) { + selfDestructAtLimit = true; + return true; } else if (value.getString() == POLICY_TYPE_REJECT) { //do nothing, thats the default return true; @@ -168,6 +173,7 @@ bool QueueSettings::handle(const std::string& key, const qpid::types::Variant& v return true; } else if (key == AUTO_DELETE_TIMEOUT) { autoDeleteDelay = value; + if (autoDeleteDelay) autodelete = true; return true; } else if (key == QueueFlowLimit::flowStopCountKey) { flowStop.setCount(value); diff --git a/qpid/cpp/src/qpid/broker/QueueSettings.h b/qpid/cpp/src/qpid/broker/QueueSettings.h index 166445be18..8d72115e18 100644 --- a/qpid/cpp/src/qpid/broker/QueueSettings.h +++ b/qpid/cpp/src/qpid/broker/QueueSettings.h @@ -70,6 +70,7 @@ struct QueueSettings QueueDepth maxDepth; bool dropMessagesAtLimit;//aka ring queue policy + bool selfDestructAtLimit; //PagedQueue: bool paging; diff --git a/qpid/cpp/src/qpid/broker/RecoverableMessageImpl.h b/qpid/cpp/src/qpid/broker/RecoverableMessageImpl.h index 7cef5fd265..900eae4e1e 100644 --- a/qpid/cpp/src/qpid/broker/RecoverableMessageImpl.h +++ b/qpid/cpp/src/qpid/broker/RecoverableMessageImpl.h @@ -33,7 +33,7 @@ class RecoverableMessageImpl : public RecoverableMessage { Message msg; public: - RecoverableMessageImpl(const Message& _msg); + QPID_BROKER_EXTERN RecoverableMessageImpl(const Message& _msg); ~RecoverableMessageImpl() {}; void setPersistenceId(uint64_t id); void setRedelivered(); diff --git a/qpid/cpp/src/qpid/broker/RecoveredDequeue.h b/qpid/cpp/src/qpid/broker/RecoveredDequeue.h index 87f768eefd..b85919975c 100644 --- a/qpid/cpp/src/qpid/broker/RecoveredDequeue.h +++ b/qpid/cpp/src/qpid/broker/RecoveredDequeue.h @@ -41,6 +41,8 @@ namespace qpid { virtual bool prepare(TransactionContext* ctxt) throw(); virtual void commit() throw(); virtual void rollback() throw(); + // TODO aconway 2013-07-08: revisit + virtual void callObserver(const boost::shared_ptr<TransactionObserver>&) {} virtual ~RecoveredDequeue(){} boost::shared_ptr<Queue> getQueue() const { return queue; } diff --git a/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h b/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h index d1f8e1106c..01c350af92 100644 --- a/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h +++ b/qpid/cpp/src/qpid/broker/RecoveredEnqueue.h @@ -41,6 +41,8 @@ class RecoveredEnqueue : public TxOp{ virtual bool prepare(TransactionContext* ctxt) throw(); virtual void commit() throw(); virtual void rollback() throw(); + // TODO aconway 2013-07-08: revisit + virtual void callObserver(const boost::shared_ptr<TransactionObserver>&) {} virtual ~RecoveredEnqueue(){} boost::shared_ptr<Queue> getQueue() const { return queue; } diff --git a/qpid/cpp/src/qpid/broker/Selector.h b/qpid/cpp/src/qpid/broker/Selector.h index 1d98f6ea8f..0e151ecd0e 100644 --- a/qpid/cpp/src/qpid/broker/Selector.h +++ b/qpid/cpp/src/qpid/broker/Selector.h @@ -64,7 +64,7 @@ public: * @param msg message to filter against selector * @return true if msg meets the selector specification */ - bool filter(const Message& msg); + QPID_BROKER_EXTERN bool filter(const Message& msg); }; /** diff --git a/qpid/cpp/src/qpid/broker/SelfDestructQueue.cpp b/qpid/cpp/src/qpid/broker/SelfDestructQueue.cpp new file mode 100644 index 0000000000..f8b26a62ad --- /dev/null +++ b/qpid/cpp/src/qpid/broker/SelfDestructQueue.cpp @@ -0,0 +1,45 @@ +/* + * + * 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 "SelfDestructQueue.h" +#include "AclModule.h" +#include "Broker.h" +#include "QueueDepth.h" +#include "qpid/log/Statement.h" + +namespace qpid { +namespace broker { +SelfDestructQueue::SelfDestructQueue(const std::string& n, const QueueSettings& s, MessageStore* const ms, management::Manageable* p, Broker* b) : Queue(n, s, ms, p, b) +{ + QPID_LOG_CAT(debug, model, "Self-destruct queue created: " << name); +} +bool SelfDestructQueue::checkDepth(const QueueDepth& increment, const Message&) +{ + if (settings.maxDepth && (settings.maxDepth - current < increment)) { + broker->getQueues().destroy(name); + if (broker->getAcl()) + broker->getAcl()->recordDestroyQueue(name); + QPID_LOG_CAT(debug, model, "Queue " << name << " deleted itself due to reaching limit: " << current << " (policy is " << settings.maxDepth << ")"); + destroyed(); + } + current += increment; + return true; +} +}} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/console/SequenceManager.cpp b/qpid/cpp/src/qpid/broker/SelfDestructQueue.h index 86ea829749..110eb1dcf7 100644 --- a/qpid/cpp/src/qpid/console/SequenceManager.cpp +++ b/qpid/cpp/src/qpid/broker/SelfDestructQueue.h @@ -1,3 +1,6 @@ +#ifndef QPID_BROKER_SELFDESTRUCTQUEUE_H +#define QPID_BROKER_SELFDESTRUCTQUEUE_H + /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -7,9 +10,9 @@ * 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 @@ -18,31 +21,25 @@ * under the License. * */ +#include "qpid/broker/Queue.h" -#include "qpid/console/SequenceManager.h" - -using namespace qpid::console; -using namespace qpid::sys; -using std::string; -using std::cout; -using std::endl; +namespace qpid { +namespace broker { -uint32_t SequenceManager::reserve(const std::string& context) -{ - Mutex::ScopedLock l(lock); - uint32_t result = sequence++; - pending[result] = context; - return result; -} - -std::string SequenceManager::release(uint32_t seq) +/** + * Deletes itself when breaching specified maximum depth (useful as + * subscription queue for consumers that should be ejecetd from topic + * when they can't keep up). + */ +class SelfDestructQueue : public Queue { - Mutex::ScopedLock l(lock); - std::map<uint32_t, string>::iterator iter = pending.find(seq); - if (iter == pending.end()) - return string(); - string result(iter->second); - pending.erase(iter); - return result; -} + public: + public: + SelfDestructQueue(const std::string&, const QueueSettings&, MessageStore* const, management::Manageable*, Broker*); + bool checkDepth(const QueueDepth& increment, const Message&); + private: + private: +}; +}} // namespace qpid::broker +#endif /*!QPID_BROKER_SELFDESTRUCTQUEUE_H*/ diff --git a/qpid/cpp/src/qpid/broker/SemanticState.cpp b/qpid/cpp/src/qpid/broker/SemanticState.cpp index 4570e3bd87..18c29c09f9 100644 --- a/qpid/cpp/src/qpid/broker/SemanticState.cpp +++ b/qpid/cpp/src/qpid/broker/SemanticState.cpp @@ -31,6 +31,7 @@ #include "qpid/broker/Selector.h" #include "qpid/broker/SessionContext.h" #include "qpid/broker/SessionOutputException.h" +#include "qpid/broker/TransactionObserver.h" #include "qpid/broker/TxAccept.h" #include "qpid/broker/amqp_0_10/MessageTransfer.h" #include "qpid/framing/reply_exceptions.h" @@ -65,6 +66,7 @@ namespace broker { using namespace std; using boost::intrusive_ptr; +using boost::shared_ptr; using boost::bind; using namespace qpid::broker; using namespace qpid::framing; @@ -165,13 +167,15 @@ bool SemanticState::cancel(const string& tag) void SemanticState::startTx() { txBuffer = TxBuffer::shared_ptr(new TxBuffer()); + session.getBroker().getBrokerObservers().startTx(txBuffer); + session.startTx(); //just to update statistics } void SemanticState::commit(MessageStore* const store) { if (!txBuffer) throw CommandInvalidException(QPID_MSG("Session has not been selected for use with transactions")); - + session.commitTx(); //just to update statistics TxOp::shared_ptr txAck(static_cast<TxOp*>(new TxAccept(accumulatedAck, unacked))); txBuffer->enlist(txAck); if (txBuffer->commitLocal(store)) { @@ -185,7 +189,7 @@ void SemanticState::rollback() { if (!txBuffer) throw CommandInvalidException(QPID_MSG("Session has not been selected for use with transactions")); - + session.rollbackTx(); //just to update statistics txBuffer->rollback(); accumulatedAck.clear(); } @@ -202,6 +206,7 @@ void SemanticState::startDtx(const std::string& xid, DtxManager& mgr, bool join) } dtxBuffer.reset(new DtxBuffer(xid)); txBuffer = dtxBuffer; + session.getBroker().getBrokerObservers().startDtx(dtxBuffer); if (join) { mgr.join(xid, dtxBuffer); } else { @@ -432,8 +437,10 @@ bool SemanticStateConsumerImpl::checkCredit(const Message& msg) SemanticStateConsumerImpl::~SemanticStateConsumerImpl() { - if (mgmtObject != 0) + if (mgmtObject != 0) { + mgmtObject->debugStats("destroying"); mgmtObject->resourceDestroy (); + } } void SemanticState::disable(ConsumerImpl::shared_ptr c) @@ -658,9 +665,7 @@ Queue::shared_ptr SemanticState::getQueue(const string& name) const { if (name.empty()) { throw NotAllowedException(QPID_MSG("No queue name specified.")); } else { - queue = session.getBroker().getQueues().find(name); - if (!queue) - throw NotFoundException(QPID_MSG("Queue not found: "<<name)); + queue = session.getBroker().getQueues().get(name); } return queue; } @@ -767,7 +772,6 @@ void SemanticState::accepted(const SequenceSet& commands) { TxOp::shared_ptr txAck(new DtxAck(accumulatedAck, unacked)); accumulatedAck.clear(); dtxBuffer->enlist(txAck); - //mark the relevant messages as 'ended' in unacked //if the messages are already completed, they can be //removed from the record diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp index 0124e88832..64e3fe1b8a 100644 --- a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp +++ b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp @@ -685,9 +685,7 @@ Queue::shared_ptr SessionAdapter::HandlerHelper::getQueue(const string& name) co if (name.empty()) { throw framing::IllegalArgumentException(QPID_MSG("No queue name specified.")); } else { - queue = session.getBroker().getQueues().find(name); - if (!queue) - throw framing::NotFoundException(QPID_MSG("Queue not found: "<<name)); + queue = session.getBroker().getQueues().get(name); } return queue; } diff --git a/qpid/cpp/src/qpid/broker/SessionHandler.cpp b/qpid/cpp/src/qpid/broker/SessionHandler.cpp index 93977c8a6e..ff7693e93a 100644 --- a/qpid/cpp/src/qpid/broker/SessionHandler.cpp +++ b/qpid/cpp/src/qpid/broker/SessionHandler.cpp @@ -39,7 +39,11 @@ SessionHandler::SessionHandler(amqp_0_10::Connection& c, ChannelId ch) proxy(out) {} -SessionHandler::~SessionHandler() {} +SessionHandler::~SessionHandler() +{ + if (session.get()) + connection.getBroker().getSessionManager().forget(session->getId()); +} void SessionHandler::connectionException( framing::connection::CloseCode code, const std::string& msg) diff --git a/qpid/cpp/src/qpid/broker/SessionState.cpp b/qpid/cpp/src/qpid/broker/SessionState.cpp index 421dc008a9..3995eb85dc 100644 --- a/qpid/cpp/src/qpid/broker/SessionState.cpp +++ b/qpid/cpp/src/qpid/broker/SessionState.cpp @@ -79,7 +79,27 @@ void SessionState::addManagementObject() { } } +void SessionState::startTx() { + if (mgmtObject) { mgmtObject->inc_TxnStarts(); } +} + +void SessionState::commitTx() { + if (mgmtObject) { + mgmtObject->inc_TxnCommits(); + mgmtObject->inc_TxnCount(); + } +} + +void SessionState::rollbackTx() { + if (mgmtObject) { + mgmtObject->inc_TxnRejects(); + mgmtObject->inc_TxnCount(); + } +} + SessionState::~SessionState() { + if (mgmtObject != 0) + mgmtObject->debugStats("destroying"); asyncCommandCompleter->cancel(); semanticState.closed(); if (mgmtObject != 0) diff --git a/qpid/cpp/src/qpid/broker/SessionState.h b/qpid/cpp/src/qpid/broker/SessionState.h index daf3767969..500a211a6f 100644 --- a/qpid/cpp/src/qpid/broker/SessionState.h +++ b/qpid/cpp/src/qpid/broker/SessionState.h @@ -127,6 +127,11 @@ class SessionState : public qpid::SessionState, // belonging to inter-broker bridges void addManagementObject(); + // transaction-related methods just to update statistics + void startTx(); + void commitTx(); + void rollbackTx(); + private: void handleCommand(framing::AMQMethodBody* method, const framing::SequenceNumber& id); void handleContent(framing::AMQFrame& frame, const framing::SequenceNumber& id); diff --git a/qpid/cpp/src/qpid/broker/System.cpp b/qpid/cpp/src/qpid/broker/System.cpp index 8d54427fdc..f3b6f96d0c 100644 --- a/qpid/cpp/src/qpid/broker/System.cpp +++ b/qpid/cpp/src/qpid/broker/System.cpp @@ -80,3 +80,9 @@ System::System (string _dataDir, Broker* broker) } } +System::~System () +{ + if (mgmtObject != 0) + mgmtObject->debugStats("destroying"); +} + diff --git a/qpid/cpp/src/qpid/broker/System.h b/qpid/cpp/src/qpid/broker/System.h index 52643fb2d5..4a4af275c4 100644 --- a/qpid/cpp/src/qpid/broker/System.h +++ b/qpid/cpp/src/qpid/broker/System.h @@ -45,6 +45,8 @@ class System : public management::Manageable System (std::string _dataDir, Broker* broker = 0); + ~System (); + management::ManagementObject::shared_ptr GetManagementObject(void) const { return mgmtObject; } diff --git a/qpid/cpp/src/qpid/broker/TopicExchange.cpp b/qpid/cpp/src/qpid/broker/TopicExchange.cpp index d49464b4e1..6a081bf65f 100644 --- a/qpid/cpp/src/qpid/broker/TopicExchange.cpp +++ b/qpid/cpp/src/qpid/broker/TopicExchange.cpp @@ -333,7 +333,10 @@ bool TopicExchange::isBound(Queue::shared_ptr queue, const string* const routing return false; } -TopicExchange::~TopicExchange() {} +TopicExchange::~TopicExchange() { + if (mgmtExchange != 0) + mgmtExchange->debugStats("destroying"); +} const std::string TopicExchange::typeName("topic"); diff --git a/qpid/cpp/src/qpid/broker/TopicExchange.h b/qpid/cpp/src/qpid/broker/TopicExchange.h index 46871a1c6b..b8b67bdafa 100644 --- a/qpid/cpp/src/qpid/broker/TopicExchange.h +++ b/qpid/cpp/src/qpid/broker/TopicExchange.h @@ -81,7 +81,7 @@ class TopicExchange : public virtual Exchange { }; public: - static const std::string typeName; + QPID_BROKER_EXTERN static const std::string typeName; static QPID_BROKER_EXTERN std::string normalize(const std::string& pattern); diff --git a/qpid/cpp/src/qpid/broker/TransactionObserver.h b/qpid/cpp/src/qpid/broker/TransactionObserver.h new file mode 100644 index 0000000000..5333d7b8d6 --- /dev/null +++ b/qpid/cpp/src/qpid/broker/TransactionObserver.h @@ -0,0 +1,82 @@ +#ifndef QPID_BROKER_TRANSACTIONOBSERVER_H +#define QPID_BROKER_TRANSACTIONOBSERVER_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 "DeliveryRecord.h" +#include <boost/shared_ptr.hpp> + +namespace qpid { + +namespace framing { +class SequenceSet; +} + +namespace broker { +class Queue; +class Message; +class TxBuffer; +class DtxBuffer; + +/** + * Interface for intercepting events in a transaction. + */ +class TransactionObserver { + public: + typedef boost::shared_ptr<Queue> QueuePtr; + typedef framing::SequenceNumber SequenceNumber; + + virtual ~TransactionObserver() {} + + /** Message enqueued in the transaction. */ + virtual void enqueue(const QueuePtr&, const Message&) = 0; + + /** + * Message is dequeued in the transaction (it was accepted by a consumer.) + *@param queuePosition: Sequence number of message on queue. + *@param replicationId: Replication sequence number, may be different. + */ + virtual void dequeue(const QueuePtr& queue, + SequenceNumber queueSeq, + SequenceNumber replicationSeq) = 0; + + virtual bool prepare() = 0; + virtual void commit() = 0; + virtual void rollback() = 0; +}; + +/** + * No-op TransactionObserver. + */ +class NullTransactionObserver : public TransactionObserver { + public: + void enqueue(const QueuePtr&, const Message&) {} + void dequeue(const QueuePtr&, SequenceNumber, SequenceNumber) {} + bool prepare() { return true; } + void commit() {} + void rollback() {} +}; + +}} // namespace qpid::broker + +#endif /*!QPID_BROKER_TRANSACTIONOBSERVER_H*/ diff --git a/qpid/cpp/src/qpid/broker/TxAccept.cpp b/qpid/cpp/src/qpid/broker/TxAccept.cpp index 928ac12c10..ee30dff957 100644 --- a/qpid/cpp/src/qpid/broker/TxAccept.cpp +++ b/qpid/cpp/src/qpid/broker/TxAccept.cpp @@ -7,9 +7,9 @@ * 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 @@ -19,6 +19,8 @@ * */ #include "qpid/broker/TxAccept.h" +#include "qpid/broker/TransactionObserver.h" +#include "qpid/broker/Queue.h" #include "qpid/log/Statement.h" using std::bind1st; @@ -28,54 +30,23 @@ using namespace qpid::broker; using qpid::framing::SequenceSet; using qpid::framing::SequenceNumber; -TxAccept::RangeOp::RangeOp(const AckRange& r) : range(r) {} -void TxAccept::RangeOp::prepare(TransactionContext* ctxt) +TxAccept::TxAccept(const SequenceSet& _acked, DeliveryRecords& _unacked) : + acked(_acked), unacked(_unacked) { - for_each(range.start, range.end, bind(&DeliveryRecord::dequeue, _1, ctxt)); + for(SequenceSet::RangeIterator i = acked.rangesBegin(); i != acked.rangesEnd(); ++i) + ranges.push_back(DeliveryRecord::findRange(unacked, i->first(), i->last())); } -void TxAccept::RangeOp::commit() -{ - for_each(range.start, range.end, bind(&DeliveryRecord::committed, _1)); - for_each(range.start, range.end, bind(&DeliveryRecord::setEnded, _1)); -} - -TxAccept::RangeOps::RangeOps(DeliveryRecords& u) : unacked(u) {} - -void TxAccept::RangeOps::operator()(SequenceNumber start, SequenceNumber end) -{ - ranges.push_back(RangeOp(DeliveryRecord::findRange(unacked, start, end))); -} - -void TxAccept::RangeOps::prepare(TransactionContext* ctxt) -{ - std::for_each(ranges.begin(), ranges.end(), bind(&RangeOp::prepare, _1, ctxt)); -} - -void TxAccept::RangeOps::commit() -{ - std::for_each(ranges.begin(), ranges.end(), bind(&RangeOp::commit, _1)); - //now remove if isRedundant(): - if (!ranges.empty()) { - DeliveryRecords::iterator begin = ranges.front().range.start; - DeliveryRecords::iterator end = ranges.back().range.end; - DeliveryRecords::iterator removed = remove_if(begin, end, mem_fun_ref(&DeliveryRecord::isRedundant)); - unacked.erase(removed, end); - } -} - -TxAccept::TxAccept(const SequenceSet& _acked, DeliveryRecords& _unacked) : - acked(_acked), unacked(_unacked), ops(unacked) -{ - //populate the ops - acked.for_each(ops); +void TxAccept::each(boost::function<void(DeliveryRecord&)> f) { + for(AckRanges::iterator i = ranges.begin(); i != ranges.end(); ++i) + for_each(i->start, i->end, f); } bool TxAccept::prepare(TransactionContext* ctxt) throw() { try{ - ops.prepare(ctxt); + each(bind(&DeliveryRecord::dequeue, _1, ctxt)); return true; }catch(const std::exception& e){ QPID_LOG(error, "Failed to prepare: " << e.what()); @@ -86,10 +57,19 @@ bool TxAccept::prepare(TransactionContext* ctxt) throw() } } -void TxAccept::commit() throw() +void TxAccept::commit() throw() { try { - ops.commit(); + each(bind(&DeliveryRecord::committed, _1)); + each(bind(&DeliveryRecord::setEnded, _1)); + //now remove if isRedundant(): + if (!ranges.empty()) { + DeliveryRecords::iterator begin = ranges.front().start; + DeliveryRecords::iterator end = ranges.back().end; + DeliveryRecords::iterator removed = + remove_if(begin, end, mem_fun_ref(&DeliveryRecord::isRedundant)); + unacked.erase(removed, end); + } } catch (const std::exception& e) { QPID_LOG(error, "Failed to commit: " << e.what()); } catch(...) { @@ -98,3 +78,13 @@ void TxAccept::commit() throw() } void TxAccept::rollback() throw() {} + +namespace { +void callObserverDR(boost::shared_ptr<TransactionObserver> observer, DeliveryRecord& dr) { + observer->dequeue(dr.getQueue(), dr.getMessageId(), dr.getReplicationId()); +} +} // namespace + +void TxAccept::callObserver(const ObserverPtr& observer) { + each(boost::bind(&callObserverDR, observer, _1)); +} diff --git a/qpid/cpp/src/qpid/broker/TxAccept.h b/qpid/cpp/src/qpid/broker/TxAccept.h index daf192285a..b4d55155a8 100644 --- a/qpid/cpp/src/qpid/broker/TxAccept.h +++ b/qpid/cpp/src/qpid/broker/TxAccept.h @@ -7,9 +7,9 @@ * 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 @@ -21,58 +21,45 @@ #ifndef _TxAccept_ #define _TxAccept_ -#include <algorithm> -#include <functional> -#include <list> #include "qpid/framing/SequenceSet.h" +#include "qpid/broker/BrokerImportExport.h" #include "qpid/broker/DeliveryRecord.h" #include "qpid/broker/TxOp.h" +#include <boost/function.hpp> +#include <algorithm> +#include <functional> +#include <list> namespace qpid { - namespace broker { - /** - * Defines the transactional behaviour for accepts received by - * a transactional channel. - */ - class TxAccept : public TxOp { - struct RangeOp - { - AckRange range; - - RangeOp(const AckRange& r); - void prepare(TransactionContext* ctxt); - void commit(); - }; - - struct RangeOps - { - std::vector<RangeOp> ranges; - DeliveryRecords& unacked; - - RangeOps(DeliveryRecords& u); +namespace broker { +/** + * Defines the transactional behaviour for accepts received by + * a transactional channel. + */ +class TxAccept : public TxOp { + typedef std::vector<AckRange> AckRanges; + typedef boost::shared_ptr<TransactionObserver> ObserverPtr; - void operator()(framing::SequenceNumber start, framing::SequenceNumber end); - void prepare(TransactionContext* ctxt); - void commit(); - }; + void each(boost::function<void(DeliveryRecord&)>); - framing::SequenceSet acked; - DeliveryRecords& unacked; - RangeOps ops; + framing::SequenceSet acked; + DeliveryRecords& unacked; + AckRanges ranges; - public: - /** - * @param acked a representation of the accumulation of - * acks received - * @param unacked the record of delivered messages - */ - TxAccept(const framing::SequenceSet& acked, DeliveryRecords& unacked); - virtual bool prepare(TransactionContext* ctxt) throw(); - virtual void commit() throw(); - virtual void rollback() throw(); - virtual ~TxAccept(){} - }; - } + public: + /** + * @param acked a representation of the accumulation of + * acks received + * @param unacked the record of delivered messages + */ + QPID_BROKER_EXTERN TxAccept(const framing::SequenceSet& acked, DeliveryRecords& unacked); + virtual bool prepare(TransactionContext* ctxt) throw(); + virtual void commit() throw(); + virtual void rollback() throw(); + virtual void callObserver(const ObserverPtr&); + virtual ~TxAccept(){} +}; +} } diff --git a/qpid/cpp/src/qpid/broker/TxBuffer.cpp b/qpid/cpp/src/qpid/broker/TxBuffer.cpp index 7663cc525f..a8df4fb214 100644 --- a/qpid/cpp/src/qpid/broker/TxBuffer.cpp +++ b/qpid/cpp/src/qpid/broker/TxBuffer.cpp @@ -19,6 +19,7 @@ * */ #include "qpid/broker/TxBuffer.h" +#include "qpid/broker/TransactionObserver.h" #include "qpid/log/Statement.h" #include <boost/mem_fn.hpp> @@ -26,8 +27,11 @@ using boost::mem_fn; using namespace qpid::broker; +TxBuffer::TxBuffer() : observer(new NullTransactionObserver) {} + bool TxBuffer::prepare(TransactionContext* const ctxt) { + if (!observer->prepare()) return false; for(op_iterator i = ops.begin(); i != ops.end(); i++){ if(!(*i)->prepare(ctxt)){ return false; @@ -38,18 +42,21 @@ bool TxBuffer::prepare(TransactionContext* const ctxt) void TxBuffer::commit() { + observer->commit(); std::for_each(ops.begin(), ops.end(), mem_fn(&TxOp::commit)); ops.clear(); } void TxBuffer::rollback() { + observer->rollback(); std::for_each(ops.begin(), ops.end(), mem_fn(&TxOp::rollback)); ops.clear(); } void TxBuffer::enlist(TxOp::shared_ptr op) { + op->callObserver(observer); ops.push_back(op); } diff --git a/qpid/cpp/src/qpid/broker/TxBuffer.h b/qpid/cpp/src/qpid/broker/TxBuffer.h index 22e2f06be1..4570c570a2 100644 --- a/qpid/cpp/src/qpid/broker/TxBuffer.h +++ b/qpid/cpp/src/qpid/broker/TxBuffer.h @@ -7,9 +7,9 @@ * 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 @@ -34,21 +34,21 @@ * transaction. This work can be committed or rolled back. Committing * is a two-stage process: first all the operations should be * prepared, then if that succeeds they can be committed. - * + * * In the 2pc case, a successful prepare may be followed by either a * commit or a rollback. - * + * * Atomicity of prepare is ensured by using a lower level * transactional facility. This saves explicitly rolling back all the * successfully prepared ops when one of them fails. i.e. we do not * use 2pc internally, we instead ensure that prepare is atomic at a * lower level. This makes individual prepare operations easier to * code. - * + * * Transactions on a messaging broker effect three types of 'action': * (1) updates to persistent storage (2) updates to transient storage * or cached data (3) network writes. - * + * * Of these, (1) should always occur atomically during prepare to * ensure that if the broker crashes while a transaction is being * completed the persistent state (which is all that then remains) is @@ -58,59 +58,74 @@ * TransactionalStore in use. */ namespace qpid { - namespace broker { - class TxBuffer{ - typedef std::vector<TxOp::shared_ptr>::iterator op_iterator; - std::vector<TxOp::shared_ptr> ops; - protected: - - public: - typedef boost::shared_ptr<TxBuffer> shared_ptr; - /** - * Adds an operation to the transaction. - */ - QPID_BROKER_EXTERN void enlist(TxOp::shared_ptr op); - - /** - * Requests that all ops are prepared. This should - * primarily involve making sure that a persistent record - * of the operations is stored where necessary. - * - * Once prepared, a transaction can be committed (or in - * the 2pc case, rolled back). - * - * @returns true if all the operations prepared - * successfully, false if not. - */ - QPID_BROKER_EXTERN bool prepare(TransactionContext* const ctxt); - - /** - * Signals that the ops all prepared successfully and can - * now commit, i.e. the operation can now be fully carried - * out. - * - * Should only be called after a call to prepare() returns - * true. - */ - QPID_BROKER_EXTERN void commit(); - - /** - * Signals that all ops can be rolled back. - * - * Should only be called either after a call to prepare() - * returns true (2pc) or instead of a prepare call - * ('server-local') - */ - QPID_BROKER_EXTERN void rollback(); - - /** - * Helper method for managing the process of server local - * commit - */ - QPID_BROKER_EXTERN bool commitLocal(TransactionalStore* const store); - }; + +namespace broker { +class TransactionObserver; + +class TxBuffer { + private: + typedef std::vector<TxOp::shared_ptr>::iterator op_iterator; + std::vector<TxOp::shared_ptr> ops; + boost::shared_ptr<TransactionObserver> observer; + + public: + typedef boost::shared_ptr<TxBuffer> shared_ptr; + + QPID_BROKER_EXTERN TxBuffer(); + + /** + * Adds an operation to the transaction. + */ + QPID_BROKER_EXTERN void enlist(TxOp::shared_ptr op); + + /** + * Requests that all ops are prepared. This should + * primarily involve making sure that a persistent record + * of the operations is stored where necessary. + * + * Once prepared, a transaction can be committed (or in + * the 2pc case, rolled back). + * + * @returns true if all the operations prepared + * successfully, false if not. + */ + QPID_BROKER_EXTERN bool prepare(TransactionContext* const ctxt); + + /** + * Signals that the ops all prepared successfully and can + * now commit, i.e. the operation can now be fully carried + * out. + * + * Should only be called after a call to prepare() returns + * true. + */ + QPID_BROKER_EXTERN void commit(); + + /** + * Signals that all ops can be rolled back. + * + * Should only be called either after a call to prepare() + * returns true (2pc) or instead of a prepare call + * ('server-local') + */ + QPID_BROKER_EXTERN void rollback(); + + /** + * Helper method for managing the process of server local + * commit + */ + QPID_BROKER_EXTERN bool commitLocal(TransactionalStore* const store); + + + QPID_BROKER_EXTERN void setObserver(boost::shared_ptr<TransactionObserver> o) { + observer = o; + } + + QPID_BROKER_EXTERN boost::shared_ptr<TransactionObserver> getObserver() const { + return observer; } -} +}; +}} // namespace qpid::broker #endif diff --git a/qpid/cpp/src/qpid/broker/TxOp.h b/qpid/cpp/src/qpid/broker/TxOp.h index 775efc92f7..00303eb27c 100644 --- a/qpid/cpp/src/qpid/broker/TxOp.h +++ b/qpid/cpp/src/qpid/broker/TxOp.h @@ -25,17 +25,19 @@ #include <boost/shared_ptr.hpp> namespace qpid { - namespace broker { +namespace broker { +class TransactionObserver; - class TxOp{ - public: - typedef boost::shared_ptr<TxOp> shared_ptr; +class TxOp{ + public: + typedef boost::shared_ptr<TxOp> shared_ptr; - virtual bool prepare(TransactionContext*) throw() = 0; - virtual void commit() throw() = 0; - virtual void rollback() throw() = 0; - virtual ~TxOp(){} - }; + virtual bool prepare(TransactionContext*) throw() = 0; + virtual void commit() throw() = 0; + virtual void rollback() throw() = 0; + virtual void callObserver(const boost::shared_ptr<TransactionObserver>&) = 0; + virtual ~TxOp(){} +}; }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/broker/Vhost.cpp b/qpid/cpp/src/qpid/broker/Vhost.cpp index e72118b570..8fd88601f5 100644 --- a/qpid/cpp/src/qpid/broker/Vhost.cpp +++ b/qpid/cpp/src/qpid/broker/Vhost.cpp @@ -43,6 +43,11 @@ Vhost::Vhost (qpid::management::Manageable* parentBroker, Broker* broker) } } +Vhost::~Vhost () { + if (mgmtObject != 0) + mgmtObject->debugStats("destroying"); +} + void Vhost::setFederationTag(const std::string& tag) { mgmtObject->set_federationTag(tag); diff --git a/qpid/cpp/src/qpid/broker/Vhost.h b/qpid/cpp/src/qpid/broker/Vhost.h index 599b821870..06a11db8ea 100644 --- a/qpid/cpp/src/qpid/broker/Vhost.h +++ b/qpid/cpp/src/qpid/broker/Vhost.h @@ -40,6 +40,8 @@ class Vhost : public management::Manageable Vhost (management::Manageable* parentBroker, Broker* broker = 0); + ~Vhost (); + management::ManagementObject::shared_ptr GetManagementObject (void) const { return mgmtObject; } void setFederationTag(const std::string& tag); diff --git a/qpid/cpp/src/qpid/broker/amqp/Connection.cpp b/qpid/cpp/src/qpid/broker/amqp/Connection.cpp index 2cb0994138..d4221246c5 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Connection.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/Connection.cpp @@ -182,12 +182,9 @@ void Connection::open() void Connection::readPeerProperties() { - /** - * TODO: enable when proton 0.5 has been released: qpid::types::Variant::Map properties; DataReader::read(pn_connection_remote_properties(connection), properties); setPeerProperties(properties); - */ } void Connection::closed() diff --git a/qpid/cpp/src/qpid/broker/amqp/DataReader.cpp b/qpid/cpp/src/qpid/broker/amqp/DataReader.cpp index 957134d0e6..ca3e6daabd 100644 --- a/qpid/cpp/src/qpid/broker/amqp/DataReader.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/DataReader.cpp @@ -160,7 +160,7 @@ void DataReader::readArray(pn_data_t* /*data*/, const qpid::amqp::Descriptor* /* void DataReader::readList(pn_data_t* data, const qpid::amqp::Descriptor* descriptor) { size_t count = pn_data_get_list(data); - bool skip = reader.onStartList(count, qpid::amqp::CharSequence(), descriptor); + bool skip = reader.onStartList(count, qpid::amqp::CharSequence(), qpid::amqp::CharSequence(), descriptor); if (!skip) { pn_data_enter(data); for (size_t i = 0; i < count && pn_data_next(data); ++i) { @@ -174,7 +174,7 @@ void DataReader::readList(pn_data_t* data, const qpid::amqp::Descriptor* descrip void DataReader::readMap(pn_data_t* data, const qpid::amqp::Descriptor* descriptor) { size_t count = pn_data_get_map(data); - reader.onStartMap(count, qpid::amqp::CharSequence(), descriptor); + reader.onStartMap(count, qpid::amqp::CharSequence(), qpid::amqp::CharSequence(), descriptor); pn_data_enter(data); for (size_t i = 0; i < count && pn_data_next(data); ++i) { read(data); diff --git a/qpid/cpp/src/qpid/broker/amqp/Incoming.cpp b/qpid/cpp/src/qpid/broker/amqp/Incoming.cpp index 119d05af60..f54328bc2e 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Incoming.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/Incoming.cpp @@ -25,6 +25,7 @@ #include "qpid/amqp/descriptors.h" #include "qpid/broker/AsyncCompletion.h" #include "qpid/broker/Message.h" +#include "qpid/broker/Broker.h" namespace qpid { namespace broker { @@ -104,7 +105,7 @@ namespace { } DecodingIncoming::DecodingIncoming(pn_link_t* link, Broker& broker, Session& parent, const std::string& source, const std::string& target, const std::string& name) - : Incoming(link, broker, parent, source, target, name), session(parent.shared_from_this()) {} + : Incoming(link, broker, parent, source, target, name), session(parent.shared_from_this()), expiryPolicy(broker.getExpiryPolicy()) {} DecodingIncoming::~DecodingIncoming() {} void DecodingIncoming::readable(pn_delivery_t* delivery) @@ -116,6 +117,7 @@ void DecodingIncoming::readable(pn_delivery_t* delivery) qpid::broker::Message message(received, received); userid.verify(message.getUserId()); + message.computeExpiration(expiryPolicy); handle(message); --window; received->begin(); diff --git a/qpid/cpp/src/qpid/broker/amqp/Incoming.h b/qpid/cpp/src/qpid/broker/amqp/Incoming.h index 8852766eda..127f8cecf9 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Incoming.h +++ b/qpid/cpp/src/qpid/broker/amqp/Incoming.h @@ -77,6 +77,7 @@ class DecodingIncoming : public Incoming virtual void handle(qpid::broker::Message&) = 0; private: boost::shared_ptr<Session> session; + boost::intrusive_ptr<ExpiryPolicy> expiryPolicy; }; }}} // namespace qpid::broker::amqp diff --git a/qpid/cpp/src/qpid/broker/amqp/Message.cpp b/qpid/cpp/src/qpid/broker/amqp/Message.cpp index 3dcf1c14e6..572eea3881 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Message.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/Message.cpp @@ -21,9 +21,13 @@ #include "Message.h" #include "qpid/amqp/Decoder.h" #include "qpid/amqp/descriptors.h" -#include "qpid/amqp/Reader.h" -#include "qpid/amqp/MessageEncoder.h" +#include "qpid/amqp/ListBuilder.h" +#include "qpid/amqp/MapBuilder.h" #include "qpid/amqp/MapHandler.h" +#include "qpid/amqp/MessageEncoder.h" +#include "qpid/amqp/Reader.h" +#include "qpid/amqp/typecodes.h" +#include "qpid/types/encodings.h" #include "qpid/log/Statement.h" #include "qpid/framing/Buffer.h" #include <string.h> @@ -121,8 +125,8 @@ namespace { } } - bool onStartList(uint32_t, const CharSequence&, const Descriptor*) { return false; } - bool onStartMap(uint32_t, const CharSequence&, const Descriptor*) { return false; } + bool onStartList(uint32_t, const CharSequence&, const CharSequence&, const Descriptor*) { return false; } + bool onStartMap(uint32_t, const CharSequence&, const CharSequence&, const Descriptor*) { return false; } bool onStartArray(uint32_t, const CharSequence&, const Constructor&, const Descriptor*) { return false; } public: @@ -144,8 +148,12 @@ void Message::processProperties(MapHandler& mh) const { //and whether it should indeed only be the content that is thus //measured uint64_t Message::getContentSize() const { return data.size(); } -//getContent() is used primarily for decoding qmf messages in management and ha -std::string Message::getContent() const { return empty; } +//getContent() is used primarily for decoding qmf messages in +//management and ha, but also by the xml exchange +std::string Message::getContent() const +{ + return std::string(body.data, body.size); +} Message::Message(size_t size) : data(size) { @@ -253,12 +261,54 @@ void Message::onGroupId(const qpid::amqp::CharSequence&) {} void Message::onGroupSequence(uint32_t) {} void Message::onReplyToGroupId(const qpid::amqp::CharSequence&) {} -void Message::onApplicationProperties(const qpid::amqp::CharSequence& v) { applicationProperties = v; } -void Message::onDeliveryAnnotations(const qpid::amqp::CharSequence& v) { deliveryAnnotations = v; } -void Message::onMessageAnnotations(const qpid::amqp::CharSequence& v) { messageAnnotations = v; } -void Message::onBody(const qpid::amqp::CharSequence& v, const qpid::amqp::Descriptor&) { body = v; } -void Message::onBody(const qpid::types::Variant&, const qpid::amqp::Descriptor&) {} -void Message::onFooter(const qpid::amqp::CharSequence& v) { footer = v; } +void Message::onApplicationProperties(const qpid::amqp::CharSequence& v, const qpid::amqp::CharSequence&) { applicationProperties = v; } +void Message::onDeliveryAnnotations(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence& v) { deliveryAnnotations = v; } +void Message::onMessageAnnotations(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence& v) { messageAnnotations = v; } + +void Message::onData(const qpid::amqp::CharSequence& v) { body = v; } +void Message::onAmqpSequence(const qpid::amqp::CharSequence& v) { body = v; bodyType = qpid::amqp::typecodes::LIST_NAME; } +void Message::onAmqpValue(const qpid::amqp::CharSequence& v, const std::string& t) +{ + body = v; + if (t == qpid::amqp::typecodes::STRING_NAME) { + bodyType = qpid::types::encodings::UTF8; + } else if (t == qpid::amqp::typecodes::SYMBOL_NAME) { + bodyType = qpid::types::encodings::ASCII; + } else if (t == qpid::amqp::typecodes::BINARY_NAME) { + bodyType = qpid::types::encodings::BINARY; + } else { + bodyType = t; + } +} +void Message::onAmqpValue(const qpid::types::Variant& v) { typedBody = v; } + +void Message::onFooter(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence& v) { footer = v; } + +bool Message::isTypedBody() const +{ + return !typedBody.isVoid() || !bodyType.empty(); +} + +qpid::types::Variant Message::getTypedBody() const +{ + if (bodyType == qpid::amqp::typecodes::LIST_NAME) { + qpid::amqp::ListBuilder builder; + qpid::amqp::Decoder decoder(body.data, body.size); + decoder.read(builder); + return builder.getList(); + } else if (bodyType == qpid::amqp::typecodes::MAP_NAME) { + qpid::amqp::MapBuilder builder; + qpid::amqp::Decoder decoder(body.data, body.size); + decoder.read(builder); + return builder.getMap(); + } else if (!bodyType.empty()) { + qpid::types::Variant value(std::string(body.data, body.size)); + value.setEncoding(bodyType); + return value; + } else { + return typedBody; + } +} //PersistableMessage interface: @@ -292,31 +342,41 @@ void Message::decodeHeader(framing::Buffer& buffer) } void Message::decodeContent(framing::Buffer& /*buffer*/) {} -boost::intrusive_ptr<PersistableMessage> Message::merge(const std::map<std::string, qpid::types::Variant>& annotations) const +boost::intrusive_ptr<PersistableMessage> Message::merge(const std::map<std::string, qpid::types::Variant>& added) const { //message- or delivery- annotations? would have to determine that from the name, for now assume always message-annotations - size_t extra = 0; + std::map<std::string, qpid::types::Variant> combined; + const std::map<std::string, qpid::types::Variant>* annotations(0); if (messageAnnotations) { - //TODO: actual merge required + //combine existing and added annotations (TODO: this could be + //optimised by avoiding the decode and simply 'editing' the + //size and count in the raw data, then appending the new + //elements). + qpid::amqp::MapBuilder builder; + qpid::amqp::Decoder decoder(messageAnnotations.data, messageAnnotations.size); + decoder.read(builder); + combined = builder.getMap(); + for (std::map<std::string, qpid::types::Variant>::const_iterator i = added.begin(); i != added.end(); ++i) { + combined[i->first] = i->second; + } + annotations = &combined; } else { - //add whole new section - extra = qpid::amqp::MessageEncoder::getEncodedSize(annotations, true); + //additions form a whole new section + annotations = &added; } - boost::intrusive_ptr<Message> copy(new Message(data.size()+extra)); + size_t annotationsSize = qpid::amqp::MessageEncoder::getEncodedSize(*annotations, true) + 3/*descriptor*/; + + boost::intrusive_ptr<Message> copy(new Message(bareMessage.size+footer.size+deliveryAnnotations.size+annotationsSize)); size_t position(0); - if (deliveryAnnotations) { + if (deliveryAnnotations.size) { ::memcpy(©->data[position], deliveryAnnotations.data, deliveryAnnotations.size); position += deliveryAnnotations.size; } - if (messageAnnotations) { - //TODO: actual merge required - ::memcpy(©->data[position], messageAnnotations.data, messageAnnotations.size); - position += messageAnnotations.size; - } else { - qpid::amqp::MessageEncoder encoder(©->data[position], extra); - encoder.writeMap(annotations, &qpid::amqp::message::MESSAGE_ANNOTATIONS, true); - position += extra; - } + + qpid::amqp::Encoder encoder(©->data[position], annotationsSize); + encoder.writeMap(*annotations, &qpid::amqp::message::MESSAGE_ANNOTATIONS, true); + position += encoder.getPosition(); + if (bareMessage) { ::memcpy(©->data[position], bareMessage.data, bareMessage.size); position += bareMessage.size; @@ -325,7 +385,18 @@ boost::intrusive_ptr<PersistableMessage> Message::merge(const std::map<std::stri ::memcpy(©->data[position], footer.data, footer.size); position += footer.size; } + copy->data.resize(position);//annotationsSize may be slightly bigger than needed if optimisations are used (e.g. smallint) copy->scan(); + { + qpid::amqp::MapBuilder builder; + qpid::amqp::Decoder decoder(copy->messageAnnotations.data, copy->messageAnnotations.size); + decoder.read(builder); + QPID_LOG(notice, "Merged annotations are now: " << builder.getMap() << " raw=" << std::hex << std::string(copy->messageAnnotations.data, copy->messageAnnotations.size) << " " << copy->messageAnnotations.size << " bytes"); + } + assert(copy->messageAnnotations); + assert(copy->bareMessage.size == bareMessage.size); + assert(copy->footer.size == footer.size); + assert(copy->deliveryAnnotations.size == deliveryAnnotations.size); return copy; } diff --git a/qpid/cpp/src/qpid/broker/amqp/Message.h b/qpid/cpp/src/qpid/broker/amqp/Message.h index cbf8669fc1..3a7c4529de 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Message.h +++ b/qpid/cpp/src/qpid/broker/amqp/Message.h @@ -64,6 +64,8 @@ class Message : public qpid::broker::Message::Encoding, private qpid::amqp::Mess qpid::amqp::CharSequence getBareMessage() const; qpid::amqp::CharSequence getBody() const; qpid::amqp::CharSequence getFooter() const; + bool isTypedBody() const; + qpid::types::Variant getTypedBody() const; Message(size_t size); char* getData(); @@ -109,6 +111,8 @@ class Message : public qpid::broker::Message::Encoding, private qpid::amqp::Mess //body: qpid::amqp::CharSequence body; + qpid::types::Variant typedBody; + std::string bodyType; //footer: qpid::amqp::CharSequence footer; @@ -136,12 +140,16 @@ class Message : public qpid::broker::Message::Encoding, private qpid::amqp::Mess void onGroupSequence(uint32_t); void onReplyToGroupId(const qpid::amqp::CharSequence&); - void onApplicationProperties(const qpid::amqp::CharSequence&); - void onDeliveryAnnotations(const qpid::amqp::CharSequence&); - void onMessageAnnotations(const qpid::amqp::CharSequence&); - void onBody(const qpid::amqp::CharSequence&, const qpid::amqp::Descriptor&); - void onBody(const qpid::types::Variant&, const qpid::amqp::Descriptor&); - void onFooter(const qpid::amqp::CharSequence&); + void onApplicationProperties(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence&); + void onDeliveryAnnotations(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence&); + void onMessageAnnotations(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence&); + + void onData(const qpid::amqp::CharSequence&); + void onAmqpSequence(const qpid::amqp::CharSequence&); + void onAmqpValue(const qpid::amqp::CharSequence&, const std::string& type); + void onAmqpValue(const qpid::types::Variant&); + + void onFooter(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence&); }; }}} // namespace qpid::broker::amqp diff --git a/qpid/cpp/src/qpid/broker/amqp/Outgoing.cpp b/qpid/cpp/src/qpid/broker/amqp/Outgoing.cpp index 68ff979aa4..e8c05ed7b0 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Outgoing.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/Outgoing.cpp @@ -29,6 +29,7 @@ #include "qpid/sys/OutputControl.h" #include "qpid/amqp/descriptors.h" #include "qpid/amqp/MessageEncoder.h" +#include "qpid/framing/Buffer.h" #include "qpid/framing/reply_exceptions.h" #include "qpid/log/Statement.h" @@ -44,14 +45,16 @@ void Outgoing::wakeup() session.wakeup(); } -OutgoingFromQueue::OutgoingFromQueue(Broker& broker, const std::string& source, const std::string& target, boost::shared_ptr<Queue> q, pn_link_t* l, Session& session, qpid::sys::OutputControl& o, bool e, bool p) +OutgoingFromQueue::OutgoingFromQueue(Broker& broker, const std::string& source, const std::string& target, boost::shared_ptr<Queue> q, pn_link_t* l, Session& session, + qpid::sys::OutputControl& o, SubscriptionType type, bool e, bool p) : Outgoing(broker, session, source, target, pn_link_name(l)), - Consumer(pn_link_name(l), /*FIXME*/CONSUMER), + Consumer(pn_link_name(l), type), exclusive(e), isControllingUser(p), queue(q), deliveries(5000), link(l), out(o), current(0), outstanding(0), - buffer(1024)/*used only for header at present*/ + buffer(1024)/*used only for header at present*/, + unreliable(pn_link_remote_snd_settle_mode(link) == PN_SND_SETTLED) { for (size_t i = 0 ; i < deliveries.capacity(); ++i) { deliveries[i].init(i); @@ -91,8 +94,7 @@ void OutgoingFromQueue::write(const char* data, size_t size) void OutgoingFromQueue::handle(pn_delivery_t* delivery) { - pn_delivery_tag_t tag = pn_delivery_tag(delivery); - size_t i = *reinterpret_cast<const size_t*>(tag.bytes); + size_t i = Record::getIndex(pn_delivery_tag(delivery)); Record& r = deliveries[i]; if (pn_delivery_writable(delivery)) { assert(r.msg); @@ -104,6 +106,7 @@ void OutgoingFromQueue::handle(pn_delivery_t* delivery) write(&buffer[0], encoder.getPosition()); Translation t(r.msg); t.write(*this); + if (unreliable) pn_delivery_settle(delivery); if (pn_link_advance(link)) { --outstanding; outgoingMessageSent(); @@ -112,26 +115,28 @@ void OutgoingFromQueue::handle(pn_delivery_t* delivery) QPID_LOG(error, "Failed to send message " << r.msg.getSequence() << " from " << queue->getName() << ", index=" << r.index); } } - if (pn_delivery_updated(delivery)) { + if (unreliable) { + if (preAcquires()) queue->dequeue(0, r.cursor); + r.reset(); + } else if (pn_delivery_updated(delivery)) { assert(r.delivery == delivery); r.disposition = pn_delivery_remote_state(delivery); if (r.disposition) { switch (r.disposition) { case PN_ACCEPTED: - //TODO: only if consuming - queue->dequeue(0, r.cursor); + if (preAcquires()) queue->dequeue(0, r.cursor); outgoingMessageAccepted(); break; case PN_REJECTED: - queue->reject(r.cursor); + if (preAcquires()) queue->reject(r.cursor); outgoingMessageRejected(); break; case PN_RELEASED: - queue->release(r.cursor, false);//TODO: for PN_RELEASED, delivery count should not be incremented + if (preAcquires()) queue->release(r.cursor, false);//TODO: for PN_RELEASED, delivery count should not be incremented outgoingMessageRejected();//TODO: not quite true... break; case PN_MODIFIED: - queue->release(r.cursor, true);//TODO: proper handling of modified + if (preAcquires()) queue->release(r.cursor, true);//TODO: proper handling of modified outgoingMessageRejected();//TODO: not quite true... break; default: @@ -251,12 +256,17 @@ qpid::broker::OwnershipToken* OutgoingFromQueue::getSession() return 0; } -OutgoingFromQueue::Record::Record() : delivery(0), disposition(0), index(0) {} +OutgoingFromQueue::Record::Record() : delivery(0), disposition(0), index(0) +{ + tag.bytes = tagData; + tag.size = TAG_WIDTH; +} void OutgoingFromQueue::Record::init(size_t i) { index = i; - tag.bytes = reinterpret_cast<const char*>(&index); - tag.size = sizeof(index); + qpid::framing::Buffer buffer(tagData, tag.size); + assert(index <= std::numeric_limits<uint32_t>::max()); + buffer.putLong(index); } void OutgoingFromQueue::Record::reset() { @@ -266,5 +276,13 @@ void OutgoingFromQueue::Record::reset() disposition = 0; } +size_t OutgoingFromQueue::Record::getIndex(pn_delivery_tag_t t) +{ + assert(t.size == TAG_WIDTH); + qpid::framing::Buffer buffer(const_cast<char*>(t.bytes)/*won't ever be written to*/, t.size); + return (size_t) buffer.getLong(); +} + + }}} // namespace qpid::broker::amqp diff --git a/qpid/cpp/src/qpid/broker/amqp/Outgoing.h b/qpid/cpp/src/qpid/broker/amqp/Outgoing.h index 86d7d46111..81994f2b66 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Outgoing.h +++ b/qpid/cpp/src/qpid/broker/amqp/Outgoing.h @@ -88,7 +88,8 @@ class Outgoing : public ManagedOutgoingLink class OutgoingFromQueue : public Outgoing, public qpid::broker::Consumer, public boost::enable_shared_from_this<OutgoingFromQueue> { public: - OutgoingFromQueue(Broker&, const std::string& source, const std::string& target, boost::shared_ptr<Queue> q, pn_link_t* l, Session&, qpid::sys::OutputControl& o, bool exclusive, bool isControllingUser); + OutgoingFromQueue(Broker&, const std::string& source, const std::string& target, boost::shared_ptr<Queue> q, pn_link_t* l, Session&, + qpid::sys::OutputControl& o, SubscriptionType type, bool exclusive, bool isControllingUser); void setSubjectFilter(const std::string&); void setSelectorFilter(const std::string&); void init(); @@ -117,10 +118,17 @@ class OutgoingFromQueue : public Outgoing, public qpid::broker::Consumer, public int disposition; size_t index; pn_delivery_tag_t tag; + //The delivery tag is a 4 byte value representing the + //index. It is encoded separately to avoid alignment issues. + //The number of deliveries held here is always strictly + //bounded, so 4 bytes is more than enough. + static const size_t TAG_WIDTH = sizeof(uint32_t); + char tagData[TAG_WIDTH]; Record(); void init(size_t i); void reset(); + static size_t getIndex(pn_delivery_tag_t); }; const bool exclusive; @@ -134,6 +142,7 @@ class OutgoingFromQueue : public Outgoing, public qpid::broker::Consumer, public std::vector<char> buffer; std::string subjectFilter; boost::scoped_ptr<Selector> selector; + bool unreliable; }; }}} // namespace qpid::broker::amqp diff --git a/qpid/cpp/src/qpid/broker/amqp/Relay.cpp b/qpid/cpp/src/qpid/broker/amqp/Relay.cpp index a08971cb5c..83b3e64ee6 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Relay.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/Relay.cpp @@ -105,14 +105,14 @@ void Relay::detached(Outgoing*) { out = 0; isDetached = true; - std::cerr << "Outgoing link detached from relay" << std::endl; + QPID_LOG(info, "Outgoing link detached from relay [" << this << "]"); if (in) in->wakeup(); } void Relay::detached(Incoming*) { in = 0; isDetached = true; - std::cerr << "Incoming link detached from relay" << std::endl; + QPID_LOG(info, "Incoming link detached from relay [" << this << "]"); if (out) out->wakeup(); } @@ -139,13 +139,13 @@ void OutgoingFromRelay::handle(pn_delivery_t* delivery) if (pn_delivery_writable(delivery)) { if (transfer->write(link)) { outgoingMessageSent(); - QPID_LOG(debug, "Sent relayed message " << name); + QPID_LOG(debug, "Sent relayed message " << name << " [" << relay.get() << "]"); } else { - QPID_LOG(error, "Failed to send relayed message " << name); + QPID_LOG(error, "Failed to send relayed message " << name << " [" << relay.get() << "]"); } } if (pn_delivery_updated(delivery)) { - pn_disposition_t d = transfer->updated(); + uint64_t d = transfer->updated(); switch (d) { case PN_ACCEPTED: outgoingMessageAccepted(); @@ -226,6 +226,7 @@ void IncomingToRelay::detached() relay->detached(this); } +BufferedTransfer::BufferedTransfer() : disposition(0) {} void BufferedTransfer::initIn(pn_link_t* link, pn_delivery_t* d) { in.handle = d; @@ -264,7 +265,7 @@ void BufferedTransfer::initOut(pn_link_t* link) pn_delivery_set_context(out.handle, this); } -pn_disposition_t BufferedTransfer::updated() +uint64_t BufferedTransfer::updated() { disposition = pn_delivery_remote_state(out.handle); if (disposition) { diff --git a/qpid/cpp/src/qpid/broker/amqp/Relay.h b/qpid/cpp/src/qpid/broker/amqp/Relay.h index 0c2d48b346..ef700690fd 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Relay.h +++ b/qpid/cpp/src/qpid/broker/amqp/Relay.h @@ -45,10 +45,11 @@ struct Delivery class BufferedTransfer { public: + BufferedTransfer(); void initIn(pn_link_t* link, pn_delivery_t* d); bool settle(); void initOut(pn_link_t* link); - pn_disposition_t updated(); + uint64_t updated(); bool write(pn_link_t*); private: std::vector<char> data; @@ -56,7 +57,7 @@ class BufferedTransfer Delivery out; pn_delivery_tag_t dt; std::vector<char> tag; - pn_disposition_t disposition; + uint64_t disposition; }; /** diff --git a/qpid/cpp/src/qpid/broker/amqp/SaslClient.cpp b/qpid/cpp/src/qpid/broker/amqp/SaslClient.cpp index 678fddbba9..4317d18525 100644 --- a/qpid/cpp/src/qpid/broker/amqp/SaslClient.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/SaslClient.cpp @@ -36,7 +36,7 @@ namespace amqp { SaslClient::SaslClient(qpid::sys::OutputControl& out_, const std::string& id, boost::shared_ptr<Interconnect> c, std::auto_ptr<qpid::Sasl> s, const std::string& hostname_, const std::string& mechs, const qpid::sys::SecuritySettings& t) : qpid::amqp::SaslClient(id), out(out_), connection(c), sasl(s), - hostname(hostname_), allowedMechanisms(mechs), transport(t), readHeader(true), writeHeader(false), haveOutput(false), state(NONE) {} + hostname(hostname_), allowedMechanisms(mechs), transport(t), readHeader(true), writeHeader(false), haveOutput(false), initialised(false), state(NONE) {} SaslClient::~SaslClient() { @@ -67,8 +67,10 @@ std::size_t SaslClient::encode(char* buffer, std::size_t size) encoded += writeProtocolHeader(buffer, size); writeHeader = !encoded; } - if (state == NONE && encoded < size) { - encoded += write(buffer + encoded, size - encoded); + if ((!initialised || state == NONE) && encoded < size) { + size_t extra = write(buffer + encoded, size - encoded); + encoded += extra; + initialised = extra > 0; } else if (state == SUCCEEDED) { if (securityLayer.get()) encoded += securityLayer->encode(buffer + encoded, size - encoded); else encoded += connection->encode(buffer + encoded, size - encoded); diff --git a/qpid/cpp/src/qpid/broker/amqp/SaslClient.h b/qpid/cpp/src/qpid/broker/amqp/SaslClient.h index 4d802f6f65..fca293879e 100644 --- a/qpid/cpp/src/qpid/broker/amqp/SaslClient.h +++ b/qpid/cpp/src/qpid/broker/amqp/SaslClient.h @@ -64,6 +64,7 @@ class SaslClient : public qpid::sys::ConnectionCodec, qpid::amqp::SaslClient bool readHeader; bool writeHeader; bool haveOutput; + bool initialised; enum { NONE, FAILED, SUCCEEDED } state; diff --git a/qpid/cpp/src/qpid/broker/amqp/Session.cpp b/qpid/cpp/src/qpid/broker/amqp/Session.cpp index e6ea694d54..4627d724a5 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Session.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/Session.cpp @@ -36,6 +36,7 @@ #include "qpid/broker/TopicExchange.h" #include "qpid/broker/FanOutExchange.h" #include "qpid/broker/Queue.h" +#include "qpid/broker/QueueCursor.h" #include "qpid/broker/Selector.h" #include "qpid/broker/TopicExchange.h" #include "qpid/broker/amqp/Filter.h" @@ -56,15 +57,16 @@ namespace broker { namespace amqp { namespace { -bool is_capability_requested(const std::string& name, pn_data_t* capabilities) +pn_bytes_t convert(const std::string& s) { - pn_data_rewind(capabilities); - while (pn_data_next(capabilities)) { - pn_bytes_t c = pn_data_get_symbol(capabilities); - std::string s(c.start, c.size); - if (s == name) return true; - } - return false; + pn_bytes_t result; + result.start = const_cast<char*>(s.data()); + result.size = s.size(); + return result; +} +std::string convert(pn_bytes_t in) +{ + return std::string(in.start, in.size); } //capabilities const std::string CREATE_ON_DEMAND("create-on-demand"); @@ -75,40 +77,90 @@ const std::string DIRECT_FILTER("legacy-amqp-direct-binding"); const std::string TOPIC_FILTER("legacy-amqp-topic-binding"); const std::string SHARED("shared"); -void setCapabilities(pn_data_t* in, pn_data_t* out, boost::shared_ptr<Queue> node) +void writeCapabilities(pn_data_t* out, const std::vector<std::string>& supported) { - pn_data_rewind(in); - while (pn_data_next(in)) { - pn_bytes_t c = pn_data_get_symbol(in); - std::string s(c.start, c.size); - if (s == DURABLE) { - if (node->isDurable()) pn_data_put_symbol(out, c); - } else if (s == CREATE_ON_DEMAND || s == QUEUE || s == DIRECT_FILTER || s == TOPIC_FILTER) { - pn_data_put_symbol(out, c); + if (supported.size() == 1) { + pn_data_put_symbol(out, convert(supported.front())); + } else if (supported.size() > 1) { + pn_data_put_array(out, false, PN_SYMBOL); + pn_data_enter(out); + for (std::vector<std::string>::const_iterator i = supported.begin(); i != supported.end(); ++i) { + pn_data_put_symbol(out, convert(*i)); } + pn_data_exit(out); } } -void setCapabilities(pn_data_t* in, pn_data_t* out, boost::shared_ptr<Exchange> node) +template <class F> +void readCapabilities(pn_data_t* data, F f) { - pn_data_rewind(in); - while (pn_data_next(in)) { - pn_bytes_t c = pn_data_get_symbol(in); - std::string s(c.start, c.size); - if (s == DURABLE) { - if (node->isDurable()) pn_data_put_symbol(out, c); - } else if (s == SHARED) { - pn_data_put_symbol(out, c); - } else if (s == CREATE_ON_DEMAND || s == TOPIC) { - pn_data_put_symbol(out, c); - } else if (s == DIRECT_FILTER) { - if (node->getType() == DirectExchange::typeName) pn_data_put_symbol(out, c); - } else if (s == TOPIC_FILTER) { - if (node->getType() == TopicExchange::typeName) pn_data_put_symbol(out, c); + pn_data_rewind(data); + if (pn_data_next(data)) { + pn_type_t type = pn_data_type(data); + if (type == PN_ARRAY) { + pn_data_enter(data); + while (pn_data_next(data)) { + f(convert(pn_data_get_symbol(data))); + } + pn_data_exit(data); + } else if (type == PN_SYMBOL) { + f(convert(pn_data_get_symbol(data))); + } else { + QPID_LOG(error, "Skipping capabilities field of type " << pn_type_name(type)); } } } +void matchCapability(const std::string& name, bool* result, const std::string& s) +{ + if (s == name) *result = true; +} + +bool is_capability_requested(const std::string& name, pn_data_t* capabilities) +{ + bool result(false); + readCapabilities(capabilities, boost::bind(&matchCapability, name, &result, _1)); + return result; +} + +void collectQueueCapabilities(boost::shared_ptr<Queue> node, std::vector<std::string>* supported, const std::string& s) +{ + if (s == DURABLE) { + if (node->isDurable()) supported->push_back(s); + } else if (s == CREATE_ON_DEMAND || s == QUEUE || s == DIRECT_FILTER || s == TOPIC_FILTER) { + supported->push_back(s); + } +} + +void collectExchangeCapabilities(boost::shared_ptr<Exchange> node, std::vector<std::string>* supported, const std::string& s) +{ + if (s == DURABLE) { + if (node->isDurable()) supported->push_back(s); + } else if (s == SHARED) { + supported->push_back(s); + } else if (s == CREATE_ON_DEMAND || s == TOPIC) { + supported->push_back(s); + } else if (s == DIRECT_FILTER) { + if (node->getType() == DirectExchange::typeName) supported->push_back(s); + } else if (s == TOPIC_FILTER) { + if (node->getType() == TopicExchange::typeName) supported->push_back(s); + } +} + +void setCapabilities(pn_data_t* in, pn_data_t* out, boost::shared_ptr<Queue> node) +{ + std::vector<std::string> supported; + readCapabilities(in, boost::bind(&collectQueueCapabilities, node, &supported, _1)); + writeCapabilities(out, supported); +} + +void setCapabilities(pn_data_t* in, pn_data_t* out, boost::shared_ptr<Exchange> node) +{ + std::vector<std::string> supported; + readCapabilities(in, boost::bind(&collectExchangeCapabilities, node, &supported, _1)); + writeCapabilities(out, supported); +} + } class IncomingToQueue : public DecodingIncoming @@ -149,6 +201,12 @@ Session::ResolvedNode Session::resolve(const std::string name, pn_terminus_t* te node.queue = connection.getBroker().getQueues().find(name); node.topic = connection.getTopics().get(name); if (node.topic) node.exchange = node.topic->getExchange(); + if (node.exchange && !node.queue && is_capability_requested(CREATE_ON_DEMAND, pn_terminus_capabilities(terminus))) { + node.properties.read(pn_terminus_properties(terminus)); + if (!node.properties.getExchangeType().empty() && node.properties.getExchangeType() != node.exchange->getType()) { + throw Exception(qpid::amqp::error_conditions::PRECONDITION_FAILED, "Exchange of different type already exists"); + } + } if (!node.queue && !node.exchange) { if (pn_terminus_is_dynamic(terminus) || is_capability_requested(CREATE_ON_DEMAND, pn_terminus_capabilities(terminus))) { //is it a queue or an exchange? @@ -316,10 +374,10 @@ void Session::setupOutgoing(pn_link_t* link, pn_terminus_t* source, const std::s target = targetAddress; } - if (node.queue) { authorise.outgoing(node.queue); - boost::shared_ptr<Outgoing> q(new OutgoingFromQueue(connection.getBroker(), name, target, node.queue, link, *this, out, false, node.properties.trackControllingLink())); + SubscriptionType type = pn_terminus_get_distribution_mode(source) == PN_DIST_MODE_COPY ? BROWSER : CONSUMER; + boost::shared_ptr<Outgoing> q(new OutgoingFromQueue(connection.getBroker(), name, target, node.queue, link, *this, out, type, false, node.properties.trackControllingLink())); q->init(); filter.apply(q); outgoing[link] = q; @@ -333,8 +391,12 @@ void Session::setupOutgoing(pn_link_t* link, pn_terminus_t* source, const std::s settings.durable = durable; settings.autodelete = !durable; } + settings.autoDeleteDelay = pn_terminus_get_timeout(source); + if (settings.autoDeleteDelay) { + settings.autodelete = true; + settings.original["qpid.auto_delete_timeout"] = settings.autoDeleteDelay; + } filter.configure(settings); - //TODO: populate settings from source details when available from engine std::stringstream queueName; if (shared) { //just use link name (TODO: could allow this to be @@ -350,9 +412,9 @@ void Session::setupOutgoing(pn_link_t* link, pn_terminus_t* source, const std::s if (!shared) queue->setExclusiveOwner(this); authorise.outgoing(node.exchange, queue, filter); filter.bind(node.exchange, queue); - boost::shared_ptr<Outgoing> q(new OutgoingFromQueue(connection.getBroker(), name, target, queue, link, *this, out, !shared, false)); - outgoing[link] = q; + boost::shared_ptr<Outgoing> q(new OutgoingFromQueue(connection.getBroker(), name, target, queue, link, *this, out, CONSUMER, !shared, false)); q->init(); + outgoing[link] = q; } else if (node.relay) { boost::shared_ptr<Outgoing> out(new OutgoingFromRelay(link, connection.getBroker(), *this, name, target, pn_link_name(link), node.relay)); outgoing[link] = out; @@ -503,7 +565,6 @@ bool Session::dispatch() void Session::close() { - exclusiveQueues.clear(); for (OutgoingLinks::iterator i = outgoing.begin(); i != outgoing.end(); ++i) { i->second->detached(); } @@ -516,6 +577,7 @@ void Session::close() for (std::set< boost::shared_ptr<Queue> >::const_iterator i = exclusiveQueues.begin(); i != exclusiveQueues.end(); ++i) { (*i)->releaseExclusiveOwnership(); } + exclusiveQueues.clear(); qpid::sys::Mutex::ScopedLock l(lock); deleted = true; } diff --git a/qpid/cpp/src/qpid/broker/amqp/Topic.cpp b/qpid/cpp/src/qpid/broker/amqp/Topic.cpp index 7d77343f26..4bb581628b 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Topic.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/Topic.cpp @@ -47,6 +47,13 @@ bool testProperty(const std::string& k, const qpid::types::Variant::Map& m) else return i->second; } +qpid::types::Variant::Map filter(const qpid::types::Variant::Map& properties) +{ + qpid::types::Variant::Map filtered = properties; + filtered.erase(DURABLE); + filtered.erase(EXCHANGE); + return filtered; +} } Topic::Topic(Broker& broker, const std::string& n, const qpid::types::Variant::Map& properties) @@ -60,7 +67,7 @@ Topic::Topic(Broker& broker, const std::string& n, const qpid::types::Variant::M qpid::management::ManagementAgent* agent = broker.getManagementAgent(); if (agent != 0) { topic = _qmf::Topic::shared_ptr(new _qmf::Topic(agent, this, name, exchange->GetManagementObject()->getObjectId(), durable)); - topic->set_properties(policy.asMap()); + topic->set_properties(filter(properties)); agent->addObject(topic); } } @@ -117,8 +124,12 @@ bool TopicRegistry::deleteObject(Broker& broker, const std::string& type, const { if (type == TOPIC) { boost::shared_ptr<Topic> topic = remove(name); - if (topic->isDurable()) broker.getStore().destroy(*topic); - return true; + if (topic) { + if (topic->isDurable()) broker.getStore().destroy(*topic); + return true; + } else { + return false; + } } else { return false; } diff --git a/qpid/cpp/src/qpid/broker/amqp/Translation.cpp b/qpid/cpp/src/qpid/broker/amqp/Translation.cpp index e04d44d2c8..2196c8ff3d 100644 --- a/qpid/cpp/src/qpid/broker/amqp/Translation.cpp +++ b/qpid/cpp/src/qpid/broker/amqp/Translation.cpp @@ -27,6 +27,7 @@ #include "qpid/amqp/MessageEncoder.h" #include "qpid/amqp_0_10/Codecs.h" #include "qpid/types/Variant.h" +#include "qpid/types/encodings.h" #include "qpid/framing/MessageTransferBody.h" #include "qpid/log/Statement.h" #include <boost/lexical_cast.hpp> @@ -38,6 +39,9 @@ namespace { const std::string EMPTY; const std::string FORWARD_SLASH("/"); +const std::string TEXT_PLAIN("text/plain"); +const std::string SUBJECT_KEY("qpid.subject"); +const std::string APP_ID("x-amqp-0-10.app-id"); qpid::framing::ReplyTo translate(const std::string address, Broker* broker) { @@ -98,8 +102,25 @@ class Properties_0_10 : public qpid::amqp::MessageEncoder::Properties std::string getUserId() const { return messageProperties ? messageProperties->getUserId() : EMPTY; } bool hasTo() const { return getDestination().size() || hasSubject(); } std::string getTo() const { return getDestination().size() ? getDestination() : getSubject(); } - bool hasSubject() const { return deliveryProperties && getDestination().size() && deliveryProperties->hasRoutingKey(); } - std::string getSubject() const { return deliveryProperties && getDestination().size() ? deliveryProperties->getRoutingKey() : EMPTY; } + bool hasSubject() const + { + if (getDestination().empty()) { + return getApplicationProperties().isSet(SUBJECT_KEY); + } else { + return deliveryProperties && deliveryProperties->hasRoutingKey(); + } + } + std::string getSubject() const + { + if (getDestination().empty()) { + //message was sent to default exchange, routing key is the queue name + return getApplicationProperties().getAsString(SUBJECT_KEY); + } else if (deliveryProperties) { + return deliveryProperties->getRoutingKey(); + } else { + return EMPTY; + } + } bool hasReplyTo() const { return messageProperties && messageProperties->hasReplyTo(); } std::string getReplyTo() const { return messageProperties ? translate(messageProperties->getReplyTo()) : EMPTY; } bool hasCorrelationId() const { return messageProperties && messageProperties->hasCorrelationId(); } @@ -119,7 +140,7 @@ class Properties_0_10 : public qpid::amqp::MessageEncoder::Properties bool hasReplyToGroupId() const { return false; } std::string getReplyToGroupId() const { return EMPTY; } - const qpid::framing::FieldTable& getApplicationProperties() { return messageProperties->getApplicationHeaders(); } + const qpid::framing::FieldTable& getApplicationProperties() const { return messageProperties->getApplicationHeaders(); } Properties_0_10(const qpid::broker::amqp_0_10::MessageTransfer& t) : transfer(t), messageProperties(transfer.getProperties<qpid::framing::MessageProperties>()), deliveryProperties(transfer.getProperties<qpid::framing::DeliveryProperties>()) @@ -138,7 +159,6 @@ class Properties_0_10 : public qpid::amqp::MessageEncoder::Properties Translation::Translation(const qpid::broker::Message& m, Broker* b) : original(m), broker(b) {} - boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> Translation::getTransfer() { boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> t = @@ -161,13 +181,38 @@ boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> Translation transfer->getFrames().append(method); transfer->getFrames().append(header); - qpid::amqp::CharSequence body = message->getBody(); - content.castBody<qpid::framing::AMQContentBody>()->getData().assign(body.data, body.size); - transfer->getFrames().append(content); - qpid::framing::MessageProperties* props = transfer->getFrames().getHeaders()->get<qpid::framing::MessageProperties>(true); - props->setContentLength(body.size); + + if (message->isTypedBody()) { + qpid::types::Variant body = message->getTypedBody(); + std::string& data = content.castBody<qpid::framing::AMQContentBody>()->getData(); + if (body.getType() == qpid::types::VAR_MAP) { + qpid::amqp_0_10::MapCodec::encode(body.asMap(), data); + props->setContentType(qpid::amqp_0_10::MapCodec::contentType); + } else if (body.getType() == qpid::types::VAR_LIST) { + qpid::amqp_0_10::ListCodec::encode(body.asList(), data); + props->setContentType(qpid::amqp_0_10::ListCodec::contentType); + } else if (body.getType() == qpid::types::VAR_STRING) { + data = body.getString(); + if (body.getEncoding() == qpid::types::encodings::UTF8 || body.getEncoding() == qpid::types::encodings::ASCII) { + props->setContentType(TEXT_PLAIN); + } + } else { + qpid::types::Variant::List container; + container.push_back(body); + qpid::amqp_0_10::ListCodec::encode(container, data); + props->setContentType(qpid::amqp_0_10::ListCodec::contentType); + } + transfer->getFrames().append(content); + props->setContentLength(data.size()); + } else { + qpid::amqp::CharSequence body = message->getBody(); + content.castBody<qpid::framing::AMQContentBody>()->getData().assign(body.data, body.size); + transfer->getFrames().append(content); + + props->setContentLength(body.size); + } qpid::amqp::MessageId mid = message->getMessageId(); qpid::framing::Uuid uuid; @@ -209,13 +254,25 @@ boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> Translation if (ap) { qpid::amqp::Decoder d(ap.data, ap.size); qpid::amqp_0_10::translate(d.readMap(), props->getApplicationHeaders()); + std::string appid = props->getApplicationHeaders().getAsString(APP_ID); + if (!appid.empty()) { + props->setAppId(appid); + } } qpid::framing::DeliveryProperties* dp = transfer->getFrames().getHeaders()->get<qpid::framing::DeliveryProperties>(true); dp->setPriority(message->getPriority()); if (message->isPersistent()) dp->setDeliveryMode(2); - if (message->getRoutingKey().size()) dp->setRoutingKey(message->getRoutingKey()); + if (message->getRoutingKey().size()) { + if (message->getRoutingKey().size() > std::numeric_limits<uint8_t>::max()) { + //have to truncate routing key as it is specified to be a str8 + dp->setRoutingKey(message->getRoutingKey().substr(0,std::numeric_limits<uint8_t>::max())); + } else { + dp->setRoutingKey(message->getRoutingKey()); + } + props->getApplicationHeaders().setString(SUBJECT_KEY, message->getRoutingKey()); + } return transfer.get(); } else { @@ -226,10 +283,11 @@ boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> Translation void Translation::write(OutgoingFromQueue& out) { - const Message* message = dynamic_cast<const Message*>(&original.getEncoding()); + const Message* message = dynamic_cast<const Message*>(original.getPersistentContext().get()); + //persistent context will contain any newly added annotations + if (!message) message = dynamic_cast<const Message*>(&original.getEncoding()); if (message) { //write annotations - //TODO: merge in any newly added annotations qpid::amqp::CharSequence deliveryAnnotations = message->getDeliveryAnnotations(); qpid::amqp::CharSequence messageAnnotations = message->getMessageAnnotations(); if (deliveryAnnotations.size) out.write(deliveryAnnotations.data, deliveryAnnotations.size); @@ -246,14 +304,40 @@ void Translation::write(OutgoingFromQueue& out) Properties_0_10 properties(*transfer); qpid::types::Variant::Map applicationProperties; qpid::amqp_0_10::translate(properties.getApplicationProperties(), applicationProperties); - std::string content = transfer->getContent(); - size_t size = qpid::amqp::MessageEncoder::getEncodedSize(properties, applicationProperties, content); - std::vector<char> buffer(size); - qpid::amqp::MessageEncoder encoder(&buffer[0], buffer.size()); - encoder.writeProperties(properties); - encoder.writeApplicationProperties(applicationProperties); - if (content.size()) encoder.writeBinary(content, &qpid::amqp::message::DATA); - out.write(&buffer[0], encoder.getPosition()); + if (properties.getContentType() == qpid::amqp_0_10::MapCodec::contentType) { + qpid::types::Variant::Map content; + qpid::amqp_0_10::MapCodec::decode(transfer->getContent(), content); + size_t size = qpid::amqp::MessageEncoder::getEncodedSize(properties); + size += qpid::amqp::MessageEncoder::getEncodedSize(applicationProperties, true) + 3;/*descriptor*/ + size += qpid::amqp::MessageEncoder::getEncodedSize(content, true) + 3/*descriptor*/; + std::vector<char> buffer(size); + qpid::amqp::MessageEncoder encoder(&buffer[0], buffer.size()); + encoder.writeProperties(properties); + encoder.writeApplicationProperties(applicationProperties); + encoder.writeMap(content, &qpid::amqp::message::AMQP_VALUE); + out.write(&buffer[0], encoder.getPosition()); + } else if (properties.getContentType() == qpid::amqp_0_10::ListCodec::contentType) { + qpid::types::Variant::List content; + qpid::amqp_0_10::ListCodec::decode(transfer->getContent(), content); + size_t size = qpid::amqp::MessageEncoder::getEncodedSize(properties); + size += qpid::amqp::MessageEncoder::getEncodedSize(applicationProperties, true) + 3;/*descriptor*/ + size += qpid::amqp::MessageEncoder::getEncodedSize(content, true) + 3/*descriptor*/; + std::vector<char> buffer(size); + qpid::amqp::MessageEncoder encoder(&buffer[0], buffer.size()); + encoder.writeProperties(properties); + encoder.writeApplicationProperties(applicationProperties); + encoder.writeList(content, &qpid::amqp::message::AMQP_VALUE); + out.write(&buffer[0], encoder.getPosition()); + } else { + std::string content = transfer->getContent(); + size_t size = qpid::amqp::MessageEncoder::getEncodedSize(properties, applicationProperties, content); + std::vector<char> buffer(size); + qpid::amqp::MessageEncoder encoder(&buffer[0], buffer.size()); + encoder.writeProperties(properties); + encoder.writeApplicationProperties(applicationProperties); + if (content.size()) encoder.writeBinary(content, &qpid::amqp::message::DATA); + out.write(&buffer[0], encoder.getPosition()); + } } else { QPID_LOG(error, "Could not write message data in AMQP 1.0 format"); } diff --git a/qpid/cpp/src/qpid/broker/amqp_0_10/Connection.cpp b/qpid/cpp/src/qpid/broker/amqp_0_10/Connection.cpp index 6732b66ed4..4cfe988b72 100644 --- a/qpid/cpp/src/qpid/broker/amqp_0_10/Connection.cpp +++ b/qpid/cpp/src/qpid/broker/amqp_0_10/Connection.cpp @@ -174,6 +174,7 @@ void Connection::requestIOProcessing(boost::function0<void> callback) Connection::~Connection() { if (mgmtObject != 0) { + mgmtObject->debugStats("destroying"); if (!link) agent->raiseEvent(_qmf::EventClientDisconnect(mgmtId, getUserId(), mgmtObject->get_remoteProperties())); QPID_LOG_CAT(debug, model, "Delete connection. user:" << getUserId() diff --git a/qpid/cpp/src/qpid/client/AsyncSession.h b/qpid/cpp/src/qpid/client/AsyncSession.h new file mode 100644 index 0000000000..d91efeb4f1 --- /dev/null +++ b/qpid/cpp/src/qpid/client/AsyncSession.h @@ -0,0 +1,38 @@ +#ifndef QPID_CLIENT_ASYNCSESSION_H +#define QPID_CLIENT_ASYNCSESSION_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/AsyncSession_0_10.h" + +namespace qpid { +namespace client { + +/** + * AsyncSession is an alias for Session_0_10 + * + * \ingroup clientapi + */ +typedef AsyncSession_0_10 AsyncSession; + +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_ASYNCSESSION_H*/ diff --git a/qpid/cpp/src/qpid/client/ClientImportExport.h b/qpid/cpp/src/qpid/client/ClientImportExport.h new file mode 100644 index 0000000000..2a3a5a52e9 --- /dev/null +++ b/qpid/cpp/src/qpid/client/ClientImportExport.h @@ -0,0 +1,35 @@ +#ifndef QPID_CLIENT_IMPORT_EXPORT_H +#define QPID_CLIENT_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. + */ + +#include "qpid/ImportExport.h" + +#if defined(CLIENT_EXPORT) || defined (qpidclient_EXPORTS) +# define QPID_CLIENT_EXTERN QPID_EXPORT +# define QPID_CLIENT_CLASS_EXTERN QPID_CLASS_EXPORT +# define QPID_CLIENT_INLINE_EXTERN QPID_INLINE_EXPORT +#else +# define QPID_CLIENT_EXTERN QPID_IMPORT +# define QPID_CLIENT_CLASS_EXTERN QPID_CLASS_IMPORT +# define QPID_CLIENT_INLINE_EXTERN QPID_INLINE_IMPORT +#endif + +#endif diff --git a/qpid/cpp/src/qpid/client/Completion.h b/qpid/cpp/src/qpid/client/Completion.h new file mode 100644 index 0000000000..9546db9258 --- /dev/null +++ b/qpid/cpp/src/qpid/client/Completion.h @@ -0,0 +1,71 @@ +#ifndef QPID_CLIENT_COMPLETION_H +#define QPID_CLIENT_COMPLETION_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/Handle.h" +#include "qpid/client/ClientImportExport.h" +#include <string> + +namespace qpid { +namespace client { + +class CompletionImpl; +template <class T> class PrivateImplRef; + +/** + * Asynchronous commands that do not return a result will return a + * Completion. You can use the completion to wait for that specific + * command to complete. + * + *@see TypedResult + * + *\ingroup clientapi + */ +class QPID_CLIENT_CLASS_EXTERN Completion : public Handle<CompletionImpl> +{ +public: + QPID_CLIENT_EXTERN Completion(CompletionImpl* = 0); + QPID_CLIENT_EXTERN Completion(const Completion&); + QPID_CLIENT_EXTERN ~Completion(); + QPID_CLIENT_EXTERN Completion& operator=(const Completion&); + + /** Wait for the asynchronous command that returned this + *Completion to complete. + * + *@exception If the command returns an error. + */ + QPID_CLIENT_EXTERN void wait(); + QPID_CLIENT_EXTERN bool isComplete(); + + protected: + QPID_CLIENT_EXTERN std::string getResult(); + + private: + typedef CompletionImpl Impl; + friend class PrivateImplRef<Completion>; +}; + +}} + + +#endif /*!QPID_CLIENT_COMPLETION_H*/ diff --git a/qpid/cpp/src/qpid/client/Connection.cpp b/qpid/cpp/src/qpid/client/Connection.cpp index 8b4eafccaa..26e69233af 100644 --- a/qpid/cpp/src/qpid/client/Connection.cpp +++ b/qpid/cpp/src/qpid/client/Connection.cpp @@ -127,7 +127,7 @@ void Connection::open(const ConnectionSettings& settings) impl->registerFailureCallback ( failureCallback ); } -const ConnectionSettings& Connection::getNegotiatedSettings() +const ConnectionSettings& Connection::getNegotiatedSettings() const { if (!isOpen()) throw Exception(QPID_MSG("Connection is not open.")); diff --git a/qpid/cpp/src/qpid/client/Connection.h b/qpid/cpp/src/qpid/client/Connection.h new file mode 100644 index 0000000000..fb502cb40a --- /dev/null +++ b/qpid/cpp/src/qpid/client/Connection.h @@ -0,0 +1,228 @@ +#ifndef QPID_CLIENT_CONNECTION_H +#define QPID_CLIENT_CONNECTION_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <map> +#include <string> +#include "qpid/client/Session.h" +#include "qpid/client/ClientImportExport.h" +#include "qpid/client/ConnectionSettings.h" +#include "qpid/framing/ProtocolVersion.h" + +#include "boost/function.hpp" + +namespace qpid { + +struct Url; + +namespace client { + +class ConnectionImpl; + +/** + * Represents a connection to an AMQP broker. All communication is + * initiated by establishing a connection, then creating one or more + * Session objects using the connection. @see newSession() + * + * \ingroup clientapi + * + * Some methods use an AMQP 0-10 URL to specify connection parameters. + * This is defined in the AMQP 0-10 specification (http://jira.amqp.org/confluence/display/AMQP/AMQP+Specification). + * + * amqp_url = "amqp:" prot_addr_list + * prot_addr_list = [prot_addr ","]* prot_addr + * prot_addr = tcp_prot_addr | tls_prot_addr + * + * tcp_prot_addr = tcp_id tcp_addr + * tcp_id = "tcp:" | "" + * tcp_addr = [host [":" port] ] + * host = <as per http://www.ietf.org/rfc/rfc3986.txt> + * port = number]]> + * + */ + +class QPID_CLIENT_CLASS_EXTERN Connection +{ + framing::ProtocolVersion version; + + boost::function<void ()> failureCallback; + + + protected: + boost::shared_ptr<ConnectionImpl> impl; + + + public: + /** + * Creates a Connection object, but does not open the connection. + * @see open() + */ + QPID_CLIENT_EXTERN Connection(); + + /** + * Destroys a Connection object but does not close the connection if it + * was open. @see close() + */ + QPID_CLIENT_EXTERN ~Connection(); + + /** + * Opens a connection to a broker. + * + * @param host the host on which the broker is running. + * + * @param port the port on the which the broker is listening. + * + * @param uid the userid to connect with. + * + * @param pwd the password to connect with (currently SASL + * PLAIN is the only authentication method supported so this + * is sent in clear text). + * + * @param virtualhost the AMQP virtual host to use (virtual + * hosts, where implemented(!), provide namespace partitioning + * within a single broker). + */ + QPID_CLIENT_EXTERN void open(const std::string& host, int port = 5672, + const std::string& uid = "", + const std::string& pwd = "", + const std::string& virtualhost = "/", uint16_t maxFrameSize=65535); + + /** + * Opens a connection to a broker using a URL. + * If the URL contains multiple addresses, try each in turn + * till connection is successful. + * + * @url address of the broker to connect to. + * + * @param uid the userid to connect with. + * + * @param pwd the password to connect with (currently SASL + * PLAIN is the only authentication method supported so this + * is sent in clear text). + * + * @param virtualhost the AMQP virtual host to use (virtual + * hosts, where implemented(!), provide namespace partitioning + * within a single broker). + */ + QPID_CLIENT_EXTERN void open(const Url& url, + const std::string& uid = "", + const std::string& pwd = "", + const std::string& virtualhost = "/", uint16_t maxFrameSize=65535); + + /** + * Opens a connection to a broker using a URL. + * If the URL contains multiple addresses, try each in turn + * till connection is successful. + * + * @url address of the broker to connect to. + * + * @param settings used for any settings not provided by the URL. + * Settings provided by the url (e.g. host, port) are ignored. + */ + QPID_CLIENT_EXTERN void open(const Url& url, const ConnectionSettings& settings); + + /** + * Opens a connection to a broker. + * + * @param the settings to use (host, port etc). @see ConnectionSettings. + */ + QPID_CLIENT_EXTERN void open(const ConnectionSettings& settings); + + /** + * Close the connection. + * + * Any further use of this connection (without reopening it) will + * not succeed. + */ + QPID_CLIENT_EXTERN void close(); + + /** + * Create a new session on this connection. Sessions allow + * multiple streams of work to be multiplexed over the same + * connection. The returned Session provides functions to send + * commands to the broker. + * + * Session functions are synchronous. In other words, a Session + * function will send a command to the broker and does not return + * until it receives the broker's response confirming the command + * was executed. + * + * AsyncSession provides asynchronous versions of the same + * functions. These functions send a command to the broker but do + * not wait for a response. + * + * You can convert a Session s into an AsyncSession as follows: + * @code + * #include <qpid/client/AsyncSession.h> + * AsyncSession as = async(s); + * @endcode + * + * You can execute a single command asynchronously will a Session s + * like ths: + * @code + * async(s).messageTransfer(...); + * @endcode + * + * Using an AsyncSession is faster for sending large numbers of + * commands, since each command is sent as soon as possible + * without waiting for the previous command to be confirmed. + * + * However with AsyncSession you cannot assume that a command has + * completed until you explicitly synchronize. The simplest way to + * do this is to call Session::sync() or AsyncSession::sync(). + * Both of these functions wait for the broker to confirm all + * commands issued so far on the session. + * + *@param name: A name to identify the session. @see qpid::SessionId + * If the name is empty (the default) then a unique name will be + * chosen using a Universally-unique identifier (UUID) algorithm. + */ + QPID_CLIENT_EXTERN Session newSession(const std::string& name=std::string(), uint32_t timeoutSeconds = 0); + + /** + * Resume a suspended session. A session may be resumed + * on a different connection to the one that created it. + */ + QPID_CLIENT_EXTERN void resume(Session& session); + + QPID_CLIENT_EXTERN bool isOpen() const; + + /** In a cluster, returns the initial set of known broker URLs + * at the time of connection. + */ + QPID_CLIENT_EXTERN std::vector<Url> getInitialBrokers(); + + QPID_CLIENT_EXTERN void registerFailureCallback ( boost::function<void ()> fn ); + + /** + * Return the set of client negotiated settings + */ + QPID_CLIENT_EXTERN const ConnectionSettings& getNegotiatedSettings() const; + + friend struct ConnectionAccess; ///<@internal + friend class SessionBase_0_10; ///<@internal +}; + +}} // namespace qpid::client + + +#endif /*!QPID_CLIENT_CONNECTION_H*/ diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp index 4f88cb97ee..3ee3f1cd40 100644 --- a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp +++ b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp @@ -50,6 +50,7 @@ using qpid::sys::Mutex; namespace { const std::string OK("OK"); const std::string PLAIN("PLAIN"); +const std::string ANONYMOUS("ANONYMOUS"); const std::string en_US("en_US"); const std::string INVALID_STATE_START("start received in invalid state"); @@ -244,6 +245,7 @@ void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& me std::vector<std::string> mechlist; mechlist.reserve(mechanisms.size()); + if (mechanism.empty()) { //mechlist is simply what the server offers std::transform(mechanisms.begin(), mechanisms.end(), std::back_inserter(mechlist), Array::get<std::string, Array::ValuePtr>); @@ -273,9 +275,25 @@ void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& me proxy.send(body); } } else { - //TODO: verify that desired mechanism and locale are supported - std::string response = ((char)0) + username + ((char)0) + password; - proxy.startOk(properties, mechanism, response, locale); + bool haveAnonymous(false); + bool havePlain(false); + for (std::vector<std::string>::const_iterator i = mechlist.begin(); i != mechlist.end(); ++i) { + if (*i == ANONYMOUS) { + haveAnonymous = true; + break; + } else if (*i == PLAIN) { + havePlain = true; + } + } + if (haveAnonymous && (mechanism.empty() || mechanism.find(ANONYMOUS) != std::string::npos)) { + proxy.startOk(properties, ANONYMOUS, username, locale); + } else if (havePlain && (mechanism.empty() || mechanism.find(PLAIN) !=std::string::npos)) { + std::string response = ((char)0) + username + ((char)0) + password; + proxy.startOk(properties, PLAIN, response, locale); + } else { + if (!mechanism.empty()) throw Exception(QPID_MSG("Desired mechanism(s) not valid: " << mechanism << "; client supports PLAIN or ANONYMOUS, broker supports: " << join(mechlist))); + throw Exception(QPID_MSG("No valid mechanism; client supports PLAIN or ANONYMOUS, broker supports: " << join(mechlist))); + } } } diff --git a/qpid/cpp/src/qpid/client/ConnectionSettings.h b/qpid/cpp/src/qpid/client/ConnectionSettings.h new file mode 100644 index 0000000000..a0c209badf --- /dev/null +++ b/qpid/cpp/src/qpid/client/ConnectionSettings.h @@ -0,0 +1,140 @@ +#ifndef QPID_CLIENT_CONNECTIONSETTINGS_H +#define QPID_CLIENT_CONNECTIONSETTINGS_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/client/ClientImportExport.h" +#include "qpid/framing/FieldTable.h" +#include "qpid/sys/IntegerTypes.h" +#include <string> + +namespace qpid { + +namespace sys { +class Socket; +} + +namespace client { + +/** + * Settings for a Connection. + */ +struct QPID_CLIENT_CLASS_EXTERN ConnectionSettings { + + QPID_CLIENT_EXTERN ConnectionSettings(); + QPID_CLIENT_EXTERN virtual ~ConnectionSettings(); + + /** + * Allows socket to be configured; default only sets tcp-nodelay + * based on the flag set. Can be overridden. + */ + QPID_CLIENT_EXTERN virtual void configureSocket(qpid::sys::Socket&) const; + + /** + * The protocol used for the connection (defaults to 'tcp') + */ + std::string protocol; + + /** + * The host (or ip address) to connect to (defaults to 'localhost'). + */ + std::string host; + /** + * The port to connect to (defaults to 5672). + */ + uint16_t port; + /** + * Allows an AMQP 'virtual host' to be specified for the + * connection. + */ + std::string virtualhost; + + /** + * The username to use when authenticating the connection. If not + * specified the current users login is used if available. + */ + std::string username; + /** + * The password to use when authenticating the connection. + */ + std::string password; + /** + * The SASL mechanism to use when authenticating the connection; + * the options are currently PLAIN or ANONYMOUS. + */ + std::string mechanism; + /** + * Allows a locale to be specified for the connection. + */ + std::string locale; + /** + * Allows a heartbeat frequency to be specified + */ + uint16_t heartbeat; + /** + * The maximum number of channels that the client will request for + * use on this connection. + */ + uint16_t maxChannels; + /** + * The maximum frame size that the client will request for this + * connection. + */ + uint16_t maxFrameSize; + /** + * Limit the size of the connections send buffer . The buffer + * is limited to bounds * maxFrameSize. + */ + unsigned int bounds; + /** + * If true, TCP_NODELAY will be set for the connection. + */ + bool tcpNoDelay; + /** + * SASL service name + */ + std::string service; + /** + * Minimum acceptable strength of any SASL negotiated security + * layer. 0 means no security layer required. + */ + unsigned int minSsf; + /** + * Maximum acceptable strength of any SASL negotiated security + * layer. 0 means no security layer allowed. + */ + unsigned int maxSsf; + /** + * SSL cert-name for the connection. Overrides global SSL + * settings. Used only when a client connects to the broker. + */ + std::string sslCertName; + + /** + * Passed as client-propreties on opening the connecction. + */ + framing::FieldTable clientProperties; +}; + +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_CONNECTIONSETTINGS_H*/ diff --git a/qpid/cpp/src/qpid/client/FailoverListener.h b/qpid/cpp/src/qpid/client/FailoverListener.h new file mode 100644 index 0000000000..53c7c26211 --- /dev/null +++ b/qpid/cpp/src/qpid/client/FailoverListener.h @@ -0,0 +1,88 @@ +#ifndef QPID_CLIENT_FAILOVERLISTENER_H +#define QPID_CLIENT_FAILOVERLISTENER_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/client/ClientImportExport.h" +#include "qpid/client/MessageListener.h" +#include "qpid/client/Connection.h" +#include "qpid/client/Session.h" +#include "qpid/client/SubscriptionManager.h" +#include "qpid/Url.h" +#include "qpid/sys/Mutex.h" +#include "qpid/sys/Runnable.h" +#include "qpid/sys/Thread.h" +#include <vector> + +namespace qpid { +namespace client { + + +/** + * Listen for updates from the amq.failover exchange. + * + * In a cluster, the amq.failover exchange provides updates whenever + * the cluster membership changes. This class subscribes to the + * failover exchange and providees the latest list of known brokers. + * + * You can also subscribe to amq.failover yourself and use + * FailoverListener::decode to extract a list of broker URLs from a + * failover exchange message. + */ +class QPID_CLIENT_CLASS_EXTERN FailoverListener : private MessageListener, private qpid::sys::Runnable +{ + public: + /** The name of the standard failover exchange amq.failover */ + static QPID_CLIENT_EXTERN const std::string AMQ_FAILOVER; + + /** Extract the broker list from a failover exchange message */ + static QPID_CLIENT_EXTERN std::vector<Url> getKnownBrokers(const Message& m); + + /** Subscribe to amq.failover exchange. */ + QPID_CLIENT_EXTERN FailoverListener(Connection); + + /** Subscribe to amq.failover exchange. + *@param useInitial If true use the connection's initial brokers as + * the initial value of getKnownBrokers + */ + QPID_CLIENT_EXTERN FailoverListener(Connection, bool useInitial); + + QPID_CLIENT_EXTERN ~FailoverListener(); + + /** Returns the latest list of known broker URLs. */ + QPID_CLIENT_EXTERN std::vector<Url> getKnownBrokers() const; + + private: + void received(Message& msg); + void run(); + void init(bool); + + mutable sys::Mutex lock; + Connection connection; + Session session; + SubscriptionManager subscriptions; + sys::Thread thread; + std::vector<Url> knownBrokers; +}; +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_FAILOVERLISTENER_H*/ diff --git a/qpid/cpp/src/qpid/client/FailoverManager.h b/qpid/cpp/src/qpid/client/FailoverManager.h new file mode 100644 index 0000000000..bc739fd0f5 --- /dev/null +++ b/qpid/cpp/src/qpid/client/FailoverManager.h @@ -0,0 +1,138 @@ +#ifndef QPID_CLIENT_FAILOVERMANAGER_H +#define QPID_CLIENT_FAILOVERMANAGER_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/Exception.h" +#include "qpid/client/AsyncSession.h" +#include "qpid/client/ClientImportExport.h" +#include "qpid/client/Connection.h" +#include "qpid/client/ConnectionSettings.h" +#include "qpid/client/FailoverListener.h" +#include "qpid/sys/Monitor.h" +#include <vector> + +namespace qpid { +namespace client { + +struct CannotConnectException : qpid::Exception +{ + CannotConnectException(const std::string& m) : qpid::Exception(m) {} +}; + +/** + * Utility to manage failover. + */ +class QPID_CLIENT_CLASS_EXTERN FailoverManager +{ + public: + /** + * Interface to implement for doing work that can be resumed on + * failover + */ + struct Command + { + /** + * This method will be called with isRetry=false when the + * command is first executed. The session to use for the work + * will be passed to the implementing class. If the connection + * fails while the execute call is in progress, the + * FailoverManager controlling the execution will re-establish + * a connection, open a new session and call back to the + * Command implementations execute method with the new session + * and isRetry=true. + */ + virtual void execute(AsyncSession& session, bool isRetry) = 0; + virtual ~Command() {} + }; + + struct ReconnectionStrategy + { + /** + * This method is called by the FailoverManager prior to + * establishing a connection (or re-connection) and can be + * used if the application wishes to edit or re-order the list + * which will default to the list of known brokers for the + * last connection. + */ + virtual void editUrlList(std::vector<Url>& urls) = 0; + virtual ~ReconnectionStrategy() {} + }; + + /** + * Create a manager to control failover for a logical connection. + * + * @param settings the initial connection settings + * @param strategy optional stratgey callback allowing application + * to edit or reorder the list of urls to which reconnection is + * attempted + */ + QPID_CLIENT_EXTERN FailoverManager(const ConnectionSettings& settings, ReconnectionStrategy* strategy = 0); + QPID_CLIENT_EXTERN ~FailoverManager(); + /** + * Return the current connection if open or attept to reconnect to + * the specified list of urls. If no list is specified the list of + * known brokers from the last connection will be used. If no list + * is specified and this is the first connect attempt, the host + * and port from the initial settings will be used. + * + * If the full list is tried and all attempts fail, + * CannotConnectException is thrown. + */ + QPID_CLIENT_EXTERN Connection& connect(std::vector<Url> brokers = std::vector<Url>()); + /** + * Return the current connection whether open or not + */ + QPID_CLIENT_EXTERN Connection& getConnection(); + /** + * Close the current connection + */ + QPID_CLIENT_EXTERN void close(); + /** + * Reliably execute the specified command. This involves creating + * a session on which to carry out the work of the command, + * handling failover occuring while exeuting that command and + * re-starting the work. + * + * Multiple concurrent threads can call execute with different + * commands; each thread will be allocated its own + * session. FailoverManager will coordinate the different threads + * on failover to ensure they continue to use the same logical + * connection. + */ + QPID_CLIENT_EXTERN void execute(Command&); + private: + enum State {IDLE, CONNECTING, CANT_CONNECT}; + + qpid::sys::Monitor lock; + Connection connection; + std::auto_ptr<FailoverListener> failoverListener; + ConnectionSettings settings; + ReconnectionStrategy* strategy; + State state; + + void attempt(Connection&, ConnectionSettings settings, std::vector<Url> urls); + void attempt(Connection&, ConnectionSettings settings); +}; +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_FAILOVERMANAGER_H*/ diff --git a/qpid/cpp/src/qpid/client/FlowControl.h b/qpid/cpp/src/qpid/client/FlowControl.h new file mode 100644 index 0000000000..bff7071b3b --- /dev/null +++ b/qpid/cpp/src/qpid/client/FlowControl.h @@ -0,0 +1,75 @@ +#ifndef QPID_CLIENT_FLOWCONTROL_H +#define QPID_CLIENT_FLOWCONTROL_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> + +namespace qpid { +namespace client { + +/** + * Flow control works by associating a finite amount of "credit" + * with a subscription. + * + * Credit includes a message count and a byte count. Each message + * received decreases the message count by one, and the byte count by + * the size of the message. Either count can have the special value + * UNLIMITED which is never decreased. + * + * A subscription's credit is exhausted when the message count is 0 or + * the byte count is too small for the next available message. The + * subscription will not receive any further messages until is credit + * is renewed. + * + * In "window mode" credit is automatically renewed when a message is + * completed (which by default happens when it is accepted). In + * non-window mode credit is not automatically renewed, it must be + * explicitly re-set (@see Subscription) + */ +struct FlowControl { + static const uint32_t UNLIMITED=0xFFFFFFFF; + FlowControl(uint32_t messages_=0, uint32_t bytes_=0, bool window_=false) + : messages(messages_), bytes(bytes_), window(window_) {} + + static FlowControl messageCredit(uint32_t messages_) { return FlowControl(messages_,UNLIMITED,false); } + static FlowControl messageWindow(uint32_t messages_) { return FlowControl(messages_,UNLIMITED,true); } + static FlowControl byteCredit(uint32_t bytes_) { return FlowControl(UNLIMITED,bytes_,false); } + static FlowControl byteWindow(uint32_t bytes_) { return FlowControl(UNLIMITED,bytes_,true); } + static FlowControl unlimited() { return FlowControl(UNLIMITED, UNLIMITED, false); } + static FlowControl zero() { return FlowControl(0, 0, false); } + + /** Message credit: subscription can accept up to this many messages. */ + uint32_t messages; + /** Byte credit: subscription can accept up to this many bytes of message content. */ + uint32_t bytes; + /** Window mode. If true credit is automatically renewed as messages are acknowledged. */ + bool window; + + bool operator==(const FlowControl& x) { + return messages == x.messages && bytes == x.bytes && window == x.window; + }; +}; + +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_FLOWCONTROL_H*/ diff --git a/qpid/cpp/src/qpid/client/Future.h b/qpid/cpp/src/qpid/client/Future.h new file mode 100644 index 0000000000..630a7e03c0 --- /dev/null +++ b/qpid/cpp/src/qpid/client/Future.h @@ -0,0 +1,59 @@ +/* + * + * 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. + * + */ + +#ifndef _Future_ +#define _Future_ + +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include "qpid/Exception.h" +#include "qpid/framing/SequenceNumber.h" +#include "qpid/client/FutureCompletion.h" +#include "qpid/client/FutureResult.h" +#include "qpid/client/ClientImportExport.h" + +namespace qpid { +namespace client { + +/**@internal */ +class QPID_CLIENT_CLASS_EXTERN Future +{ + framing::SequenceNumber command; + boost::shared_ptr<FutureResult> result; + bool complete; + +public: + Future() : complete(false) {} + Future(const framing::SequenceNumber& id) : command(id), complete(false) {} + + std::string getResult(SessionImpl& session) { + if (result) return result->getResult(session); + else throw Exception("Result not expected"); + } + + QPID_CLIENT_EXTERN void wait(SessionImpl& session); + QPID_CLIENT_EXTERN bool isComplete(SessionImpl& session); + QPID_CLIENT_EXTERN void setFutureResult(boost::shared_ptr<FutureResult> r); +}; + +}} + +#endif diff --git a/qpid/cpp/src/qmf/engine/MessageImpl.cpp b/qpid/cpp/src/qpid/client/FutureCompletion.h index 0047d3eb9d..0970f494b7 100644 --- a/qpid/cpp/src/qmf/engine/MessageImpl.cpp +++ b/qpid/cpp/src/qpid/client/FutureCompletion.h @@ -1,4 +1,5 @@ /* + * * 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 @@ -6,38 +7,43 @@ * 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/MessageImpl.h" -#include <string.h> +#ifndef _FutureCompletion_ +#define _FutureCompletion_ -using namespace std; -using namespace qmf::engine; +#include "qpid/framing/amqp_framing.h" +#include "qpid/sys/Monitor.h" -#define STRING_REF(s) {if (!s.empty()) item.s = const_cast<char*>(s.c_str());} +namespace qpid { +namespace client { -Message MessageImpl::copy() +///@internal +class FutureCompletion { - Message item; +protected: + mutable sys::Monitor lock; + bool complete; - ::memset(&item, 0, sizeof(Message)); - item.body = const_cast<char*>(body.c_str()); - item.length = body.length(); - STRING_REF(destination); - STRING_REF(routingKey); - STRING_REF(replyExchange); - STRING_REF(replyKey); - STRING_REF(userId); +public: + FutureCompletion(); + virtual ~FutureCompletion(){} + bool isComplete() const; + void waitForCompletion() const; + void completed(); +}; - return item; -} +}} + +#endif diff --git a/qpid/cpp/src/qpid/client/FutureResult.h b/qpid/cpp/src/qpid/client/FutureResult.h new file mode 100644 index 0000000000..ead4929571 --- /dev/null +++ b/qpid/cpp/src/qpid/client/FutureResult.h @@ -0,0 +1,49 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#ifndef _FutureResult_ +#define _FutureResult_ + +#include <string> + +#include "qpid/client/ClientImportExport.h" +#include "qpid/framing/amqp_framing.h" +#include "qpid/client/FutureCompletion.h" + +namespace qpid { +namespace client { + +class SessionImpl; + +///@internal +class QPID_CLIENT_CLASS_EXTERN FutureResult : public FutureCompletion +{ + std::string result; +public: + QPID_CLIENT_EXTERN const std::string& getResult(SessionImpl& session) const; + void received(const std::string& result); +}; + +}} + + + +#endif diff --git a/qpid/cpp/src/qpid/client/Handle.h b/qpid/cpp/src/qpid/client/Handle.h new file mode 100644 index 0000000000..b8315481a9 --- /dev/null +++ b/qpid/cpp/src/qpid/client/Handle.h @@ -0,0 +1,71 @@ +#ifndef QPID_CLIENT_HANDLE_H +#define QPID_CLIENT_HANDLE_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/client/ClientImportExport.h" + +namespace qpid { +namespace client { + +template <class> class PrivateImplRef; + +/** + * A handle is like a pointer: refers to an underlying implementation object. + * Copying the handle does not copy the object. + * + * Handles can be null, like a 0 pointer. Use isValid(), isNull() or the + * conversion to bool to test for a null handle. + */ +template <class T> class Handle { + public: + + /**@return true if handle is valid, i.e. not null. */ + QPID_CLIENT_INLINE_EXTERN bool isValid() const { return impl; } + + /**@return true if handle is null. It is an error to call any function on a null handle. */ + QPID_CLIENT_INLINE_EXTERN bool isNull() const { return !impl; } + + /** Conversion to bool supports idiom if (handle) { handle->... } */ + QPID_CLIENT_INLINE_EXTERN operator bool() const { return impl; } + + /** Operator ! supports idiom if (!handle) { do_if_handle_is_null(); } */ + QPID_CLIENT_INLINE_EXTERN bool operator !() const { return !impl; } + + void swap(Handle<T>& h) { T* t = h.impl; h.impl = impl; impl = t; } + + protected: + typedef T Impl; + QPID_CLIENT_INLINE_EXTERN Handle() :impl() {} + + // Not implemented,subclasses must implement. + QPID_CLIENT_EXTERN Handle(const Handle&); + QPID_CLIENT_EXTERN Handle& operator=(const Handle&); + + Impl* impl; + + friend class PrivateImplRef<T>; // FIXME aconway 2009-04-30: Specify +}; + +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_HANDLE_H*/ diff --git a/qpid/cpp/src/qpid/client/LocalQueue.h b/qpid/cpp/src/qpid/client/LocalQueue.h new file mode 100644 index 0000000000..1a19a8499d --- /dev/null +++ b/qpid/cpp/src/qpid/client/LocalQueue.h @@ -0,0 +1,120 @@ +#ifndef QPID_CLIENT_LOCALQUEUE_H +#define QPID_CLIENT_LOCALQUEUE_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/client/ClientImportExport.h" +#include "qpid/client/Handle.h" +#include "qpid/client/Message.h" +#include "qpid/sys/Time.h" + +namespace qpid { +namespace client { + +class LocalQueueImpl; +template <class T> class PrivateImplRef; + +/** + * A local queue to collect messages retrieved from a remote broker + * queue. Create a queue and subscribe it using the SubscriptionManager. + * Messages from the remote queue on the broker will be stored in the + * local queue until you retrieve them. + * + * \ingroup clientapi + * + * \details Using a Local Queue + * + * <pre> + * LocalQueue local_queue; + * subscriptions.subscribe(local_queue, string("message_queue")); + * for (int i=0; i<10; i++) { + * Message message = local_queue.get(); + * std::cout << message.getData() << std::endl; + * } + * </pre> + * + * <h2>Getting Messages</h2> + * + * <ul><li> + * <p>get()</p> + * <pre>Message message = local_queue.get();</pre> + * <pre>// Specifying timeouts (TIME_SEC, TIME_MSEC, TIME_USEC, TIME_NSEC) + *#include <qpid/sys/Time.h> + *Message message; + *local_queue.get(message, 5*sys::TIME_SEC);</pre></li></ul> + * + * <h2>Checking size</h2> + * <ul><li> + * <p>empty()</p> + * <pre>if (local_queue.empty()) { ... }</pre></li> + * <li><p>size()</p> + * <pre>std::cout << local_queue.size();</pre></li> + * </ul> + */ + +class QPID_CLIENT_CLASS_EXTERN LocalQueue : public Handle<LocalQueueImpl> { + public: + /** Create a local queue. Subscribe the local queue to a remote broker + * queue with a SubscriptionManager. + * + * LocalQueue is an alternative to implementing a MessageListener. + */ + QPID_CLIENT_EXTERN LocalQueue(); + QPID_CLIENT_EXTERN LocalQueue(const LocalQueue&); + QPID_CLIENT_EXTERN ~LocalQueue(); + QPID_CLIENT_EXTERN LocalQueue& operator=(const LocalQueue&); + + /** Wait up to timeout for the next message from the local queue. + *@param result Set to the message from the queue. + *@param timeout wait up this timeout for a message to appear. + *@return true if result was set, false if queue was empty after timeout. + */ + QPID_CLIENT_EXTERN bool get(Message& result, sys::Duration timeout=0); + + /** Get the next message off the local queue, or wait up to the timeout + * for message from the broker queue. + *@param timeout wait up this timeout for a message to appear. + *@return message from the queue. + *@throw ClosedException if subscription is closed or timeout exceeded. + */ + QPID_CLIENT_EXTERN Message get(sys::Duration timeout=sys::TIME_INFINITE); + + /** Synonym for get() */ + QPID_CLIENT_EXTERN Message pop(sys::Duration timeout=sys::TIME_INFINITE); + + /** Return true if local queue is empty. */ + QPID_CLIENT_EXTERN bool empty() const; + + /** Number of messages on the local queue */ + QPID_CLIENT_EXTERN size_t size() const; + + LocalQueue(LocalQueueImpl*); ///<@internal + + + private: + typedef LocalQueueImpl Impl; + friend class PrivateImplRef<LocalQueue>; +}; + +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_LOCALQUEUE_H*/ diff --git a/qpid/cpp/src/qpid/client/Message.h b/qpid/cpp/src/qpid/client/Message.h new file mode 100644 index 0000000000..ba50dda9ba --- /dev/null +++ b/qpid/cpp/src/qpid/client/Message.h @@ -0,0 +1,175 @@ +#ifndef QPID_CLIENT_MESSAGE_H +#define QPID_CLIENT_MESSAGE_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/client/ClientImportExport.h" +#include "qpid/framing/MessageProperties.h" +#include "qpid/framing/DeliveryProperties.h" +#include <string> + +namespace qpid { + +namespace framing { +class FieldTable; +class SequenceNumber; // FIXME aconway 2009-04-17: remove with getID? +} + +namespace client { + +class MessageImpl; + +/** + * A message sent to or received from the broker. + * + * \ingroup clientapi + * \details + * + * <h2>Getting and setting message contents</h2> + * + * <ul> + * <li> + * <p>getData()</p> + * <pre>std::cout << "Response: " << message.getData() << std::endl;</pre> + * </li> + * <li> + * <p>setData()</p> + * <pre>message.setData("That's all, folks!");</pre></li> + * <li> + * <p>appendData()</p> + * <pre>message.appendData(" ... let's add a bit more ...");</pre></li> + * </ul> + * + * <h2>Getting and Setting Delivery Properties</h2> + * + * <ul> + * <li> + * <p>getDeliveryProperties()</p> + * <pre>message.getDeliveryProperties().setRoutingKey("control");</pre> + * <pre>message.getDeliveryProperties().setDeliveryMode(PERSISTENT);</pre> + * <pre>message.getDeliveryProperties().setPriority(9);</pre> + * <pre>message.getDeliveryProperties().setTtl(100);</pre></li> + * + * <li> + * <p>hasDeliveryProperties()</p> + * <pre>if (! message.hasDeliveryProperties()) { + * ... + *}</pre></li> + * </ul> + * + * <h2>Getting and Setting Message Properties</h2> + * + * <ul> + * <li> + * <p>getMessageProperties()</p> + * <pre> + *request.getMessageProperties().setReplyTo(ReplyTo("amq.direct", response_queue.str())); + * </pre> + * <pre> + *routingKey = request.getMessageProperties().getReplyTo().getRoutingKey(); + *exchange = request.getMessageProperties().getReplyTo().getExchange(); + * </pre> + * <pre>message.getMessageProperties().setContentType("text/plain");</pre> + * <pre>message.getMessageProperties().setContentEncoding("text/plain");</pre> + * </li> + * <li> + * <p>hasMessageProperties()</p> + * <pre>request.getMessageProperties().hasReplyTo();</pre> + * </li> + * </ul> + * + * <h2>Getting and Setting Application Headers</h2> + * + * <ul> + * <li> + * <p>getHeaders()</p> + * <pre> + *message.getHeaders().getString("control"); + * </pre> + * <pre> + *message.getHeaders().setString("control","continue"); + * </pre></li> + * </ul> + * + * + */ +class QPID_CLIENT_CLASS_EXTERN Message +{ +public: + /** Create a Message. + *@param data Data for the message body. + *@param routingKey Passed to the exchange that routes the message. + */ + QPID_CLIENT_EXTERN Message( + const std::string& data=std::string(), + const std::string& routingKey=std::string()); + Message(MessageImpl*); ///< @internal + QPID_CLIENT_EXTERN Message(const Message&); + QPID_CLIENT_EXTERN ~Message(); + QPID_CLIENT_EXTERN Message& operator=(const Message&); + QPID_CLIENT_EXTERN void swap(Message&); + + QPID_CLIENT_EXTERN void setData(const std::string&); + QPID_CLIENT_EXTERN const std::string& getData() const; + QPID_CLIENT_EXTERN std::string& getData(); + + QPID_CLIENT_EXTERN void appendData(const std::string&); + + QPID_CLIENT_EXTERN bool hasMessageProperties() const; + QPID_CLIENT_EXTERN framing::MessageProperties& getMessageProperties(); + QPID_CLIENT_EXTERN const framing::MessageProperties& getMessageProperties() const; + + QPID_CLIENT_EXTERN bool hasDeliveryProperties() const; + QPID_CLIENT_EXTERN framing::DeliveryProperties& getDeliveryProperties(); + QPID_CLIENT_EXTERN const framing::DeliveryProperties& getDeliveryProperties() const; + + + /** The destination of messages sent to the broker is the exchange + * name. The destination of messages received from the broker is + * the delivery tag identifyig the local subscription (often this + * is the name of the subscribed queue.) + */ + QPID_CLIENT_EXTERN std::string getDestination() const; + + /** Check the redelivered flag. */ + QPID_CLIENT_EXTERN bool isRedelivered() const; + /** Set the redelivered flag. */ + QPID_CLIENT_EXTERN void setRedelivered(bool redelivered); + + /** Get a modifyable reference to the message headers. */ + QPID_CLIENT_EXTERN framing::FieldTable& getHeaders(); + + /** Get a non-modifyable reference to the message headers. */ + QPID_CLIENT_EXTERN const framing::FieldTable& getHeaders() const; + + // FIXME aconway 2009-04-17: does this need to be in public API? + ///@internal + QPID_CLIENT_EXTERN const framing::SequenceNumber& getId() const; + + private: + MessageImpl* impl; + friend class MessageImpl; // Helper template for implementation +}; + +}} + +#endif /*!QPID_CLIENT_MESSAGE_H*/ diff --git a/qpid/cpp/src/qpid/client/MessageListener.h b/qpid/cpp/src/qpid/client/MessageListener.h new file mode 100644 index 0000000000..3ca2fa964a --- /dev/null +++ b/qpid/cpp/src/qpid/client/MessageListener.h @@ -0,0 +1,101 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <string> +#include "qpid/client/ClientImportExport.h" + +#ifndef _MessageListener_ +#define _MessageListener_ + +#include "qpid/client/Message.h" + +namespace qpid { +namespace client { + + /** + * Implement a subclass of MessageListener and subscribe it using + * the SubscriptionManager to receive messages. + * + * Another way to receive messages is by using a LocalQueue. + * + * \ingroup clientapi + * \details + * + * <h2>Using a MessageListener</h2> + * + * <ul> + * <li> + * <p>The received() function is called when a message arrives:</p> + * <pre>virtual void received(Message& message)=0;</pre> + * </li> + * <li> + * <p>Derive your own listener, implement the received() function:</p> + * <pre> + * class Listener : public MessageListener { + * private: + * SubscriptionManager& subscriptions; + * public: + * Listener(SubscriptionManager& subscriptions); + * virtual void received(Message& message); + * }; + * + * Listener::Listener(SubscriptionManager& subs) : subscriptions(subs) + * {} + * + * void Listener::received(Message& message) { + * std::cout << "Message: " << message.getData() << std::endl; + * if (message.getData() == "That's all, folks!") { + * std::cout << "Shutting down listener for " << message.getDestination() + * << std::endl; + * subscriptions.cancel(message.getDestination()); + * } + * } + *</pre> + * <pre> + * SubscriptionManager subscriptions(session); + * + * // Create a listener and subscribe it to the queue named "message_queue" + * Listener listener(subscriptions); + * subscriptions.subscribe(listener, "message_queue"); + * + * // Receive messages until the subscription is cancelled + * // by Listener::received() + * subscriptions.run(); + * </pre> + * </li> + * </ul> + * + */ + + class QPID_CLIENT_CLASS_EXTERN MessageListener{ + public: + QPID_CLIENT_EXTERN virtual ~MessageListener(); + + /** Called for each message arriving from the broker. Override + * in your own subclass to process messages. + */ + virtual void received(Message& msg) = 0; + }; + +} +} + + +#endif diff --git a/qpid/cpp/src/qpid/client/MessageReplayTracker.h b/qpid/cpp/src/qpid/client/MessageReplayTracker.h new file mode 100644 index 0000000000..06a3f29c7d --- /dev/null +++ b/qpid/cpp/src/qpid/client/MessageReplayTracker.h @@ -0,0 +1,73 @@ +#ifndef QPID_CLIENT_MESSAGEREPLAYTRACKER_H +#define QPID_CLIENT_MESSAGEREPLAYTRACKER_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/AsyncSession.h" +#include "qpid/client/Message.h" +#include "qpid/client/ClientImportExport.h" +#include <list> +#include <string> + +namespace qpid { +namespace client { + +/** + * Utility to track messages sent asynchronously, allowing those that + * are indoubt to be replayed over a new session. + */ +class QPID_CLIENT_CLASS_EXTERN MessageReplayTracker +{ + public: + QPID_CLIENT_EXTERN MessageReplayTracker(uint flushInterval); + QPID_CLIENT_EXTERN void send(const Message& message, const std::string& destination = ""); + QPID_CLIENT_EXTERN void init(AsyncSession session); + QPID_CLIENT_EXTERN void replay(AsyncSession session); + QPID_CLIENT_EXTERN void setFlushInterval(uint interval); + QPID_CLIENT_EXTERN uint getFlushInterval(); + QPID_CLIENT_EXTERN void checkCompletion(); + + template <class F> void foreach(F& f) { + for (std::list<ReplayRecord>::const_iterator i = buffer.begin(); i != buffer.end(); i++) { + f(i->message); + } + } + + private: + struct ReplayRecord + { + Completion status; + Message message; + std::string destination; + + ReplayRecord(const Message& message, const std::string& destination); + void send(MessageReplayTracker&); + bool isComplete(); + }; + + AsyncSession session; + uint flushInterval; + uint count; + std::list<ReplayRecord> buffer; +}; +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_MESSAGEREPLAYTRACKER_H*/ diff --git a/qpid/cpp/src/qpid/client/QueueOptions.h b/qpid/cpp/src/qpid/client/QueueOptions.h new file mode 100644 index 0000000000..3984b63fdd --- /dev/null +++ b/qpid/cpp/src/qpid/client/QueueOptions.h @@ -0,0 +1,129 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/client/ClientImportExport.h" +#include "qpid/framing/FieldTable.h" + +#ifndef _QueueOptions_ +#define _QueueOptions_ + +namespace qpid { +namespace client { + +enum QueueSizePolicy {NONE, REJECT, FLOW_TO_DISK, RING, RING_STRICT}; +enum QueueOrderingPolicy {FIFO, LVQ, LVQ_NO_BROWSE}; + +/** + * A help class to set options on the Queue. Create a configured args while + * still allowing any custom configuration via the FieldTable base class + */ +class QPID_CLIENT_CLASS_EXTERN QueueOptions: public framing::FieldTable +{ + public: + QPID_CLIENT_EXTERN QueueOptions(); + QPID_CLIENT_EXTERN virtual ~QueueOptions(); + + /** + * Sets the queue sizing policy + * + * @param sp SizePolicy + * REJECT - reject if queue greater than size/count + * FLOW_TO_DISK - page messages to disk from this point is greater than size/count + * RING - limit the queue to size/count and over-write old messages round a ring + * RING_STRICT - limit the queue to size/count and reject is head == tail + * NONE - Use default broker sizing policy + * @param maxSize Set the max number of bytes for the sizing policies + * @param setMaxCount Set the max number of messages for the sizing policies + */ + QPID_CLIENT_EXTERN void setSizePolicy(QueueSizePolicy sp, uint64_t maxSize, uint32_t maxCount ); + + /** + * Enables the persisting of a queue to the store module when a cluster fails down to it's last + * node. Does so optimistically. Will start persisting when cluster count >1 again. + */ + QPID_CLIENT_EXTERN void setPersistLastNode(); + + /** + * Sets the odering policy on the Queue, default ordering is FIFO. + */ + QPID_CLIENT_EXTERN void setOrdering(QueueOrderingPolicy op); + + /** + * Use broker defualt sizing ploicy + */ + QPID_CLIENT_EXTERN void clearSizePolicy(); + + /** + * Clear Persist Last Node Policy + */ + QPID_CLIENT_EXTERN void clearPersistLastNode(); + + /** + * get the key used match LVQ in args for message transfer + */ + QPID_CLIENT_EXTERN void getLVQKey(std::string& key); + + /** + * Use default odering policy + */ + QPID_CLIENT_EXTERN void clearOrdering(); + + /** + * 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; + static QPID_CLIENT_EXTERN const std::string strMaxSizeKey; + static QPID_CLIENT_EXTERN const std::string strTypeKey; + static QPID_CLIENT_EXTERN const std::string strREJECT; + static QPID_CLIENT_EXTERN const std::string strFLOW_TO_DISK; + static QPID_CLIENT_EXTERN const std::string strRING; + static QPID_CLIENT_EXTERN const std::string strRING_STRICT; + static QPID_CLIENT_EXTERN const std::string strLastValueQueue; + static QPID_CLIENT_EXTERN const std::string strPersistLastNode; + static QPID_CLIENT_EXTERN const std::string strLVQMatchProperty; + static QPID_CLIENT_EXTERN const std::string strLastValueQueueNoBrowse; + static QPID_CLIENT_EXTERN const std::string strQueueEventMode; +}; + +} +} + + +#endif diff --git a/qpid/cpp/src/qpid/client/Session.h b/qpid/cpp/src/qpid/client/Session.h new file mode 100644 index 0000000000..c40549bbc5 --- /dev/null +++ b/qpid/cpp/src/qpid/client/Session.h @@ -0,0 +1,39 @@ +#ifndef QPID_CLIENT_SESSION_H +#define QPID_CLIENT_SESSION_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "qpid/client/Session_0_10.h" + +namespace qpid { +namespace client { + +/** + * Session is an alias for Session_0_10 + * + * \ingroup clientapi + */ +typedef Session_0_10 Session; + + +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_SESSION_H*/ diff --git a/qpid/cpp/src/qpid/client/SessionBase_0_10.h b/qpid/cpp/src/qpid/client/SessionBase_0_10.h new file mode 100644 index 0000000000..630987c11d --- /dev/null +++ b/qpid/cpp/src/qpid/client/SessionBase_0_10.h @@ -0,0 +1,109 @@ +#ifndef QPID_CLIENT_SESSIONBASE_H +#define QPID_CLIENT_SESSIONBASE_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/SessionId.h" +#include "qpid/framing/amqp_structs.h" +#include "qpid/client/Message.h" +#include "qpid/client/Completion.h" +#include "qpid/client/TypedResult.h" +#include "qpid/client/ClientImportExport.h" +#include <string> + +namespace qpid { +namespace client { + +class Connection; +class SessionImpl; + +using qpid::framing::Content; +using qpid::framing::FieldTable; +using qpid::framing::SequenceNumber; +using qpid::framing::SequenceSet; +using qpid::framing::SequenceNumberSet; +using qpid::SessionId; +using qpid::framing::Xid; + +/** Unit of message credit: messages or bytes */ +enum CreditUnit { MESSAGE_CREDIT=0, BYTE_CREDIT=1, UNLIMITED_CREDIT=0xFFFFFFFF }; + +/** + * Base class for handles to an AMQP session. + * + * Subclasses provide the AMQP commands for a given + * version of the protocol. + */ +class QPID_CLIENT_CLASS_EXTERN SessionBase_0_10 { + public: + + ///@internal + QPID_CLIENT_EXTERN SessionBase_0_10(); + QPID_CLIENT_EXTERN ~SessionBase_0_10(); + + /** Get the session ID */ + QPID_CLIENT_EXTERN SessionId getId() const; + + /** Close the session. + * A session is automatically closed when all handles to it are destroyed. + */ + QPID_CLIENT_EXTERN void close(); + + /** + * Synchronize the session: sync() waits until all commands issued + * on this session so far have been completed by the broker. + * + * Note sync() is always synchronous, even on an AsyncSession object + * because that's almost always what you want. You can call + * AsyncSession::executionSync() directly in the unusual event + * that you want to do an asynchronous sync. + */ + QPID_CLIENT_EXTERN void sync(); + + /** Set the timeout for this session. */ + QPID_CLIENT_EXTERN uint32_t timeout(uint32_t seconds); + + /** Suspend the session - detach it from its connection */ + QPID_CLIENT_EXTERN void suspend(); + + /** Resume a suspended session with a new connection */ + QPID_CLIENT_EXTERN void resume(Connection); + + /** Get the channel associated with this session */ + QPID_CLIENT_EXTERN uint16_t getChannel() const; + + QPID_CLIENT_EXTERN void flush(); + QPID_CLIENT_EXTERN void markCompleted(const framing::SequenceSet& ids, bool notifyPeer); + QPID_CLIENT_EXTERN void markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer); + QPID_CLIENT_EXTERN void sendCompletion(); + + QPID_CLIENT_EXTERN bool isValid() const; + + QPID_CLIENT_EXTERN Connection getConnection(); + protected: + boost::shared_ptr<SessionImpl> impl; + friend class SessionBase_0_10Access; +}; + +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_SESSIONBASE_H*/ diff --git a/qpid/cpp/src/qpid/client/Subscription.h b/qpid/cpp/src/qpid/client/Subscription.h new file mode 100644 index 0000000000..bb9b98e8ff --- /dev/null +++ b/qpid/cpp/src/qpid/client/Subscription.h @@ -0,0 +1,123 @@ +#ifndef QPID_CLIENT_SUBSCRIPTION_H +#define QPID_CLIENT_SUBSCRIPTION_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/Handle.h" +#include "qpid/client/Session.h" +#include "qpid/client/SubscriptionSettings.h" +#include "qpid/client/Message.h" +#include "qpid/client/ClientImportExport.h" + +namespace qpid { +namespace client { + +template <class> class PrivateImplRef; +class SubscriptionImpl; +class SubscriptionManager; + +/** + * A handle to an active subscription. Provides methods to query the subscription status + * and control acknowledgement (acquire and accept) of messages. + */ +class QPID_CLIENT_CLASS_EXTERN Subscription : public Handle<SubscriptionImpl> { + public: + QPID_CLIENT_EXTERN Subscription(SubscriptionImpl* = 0); + QPID_CLIENT_EXTERN Subscription(const Subscription&); + QPID_CLIENT_EXTERN ~Subscription(); + QPID_CLIENT_EXTERN Subscription& operator=(const Subscription&); + + + /** The name of the subscription, used as the "destination" for messages from the broker. + * Usually the same as the queue name but can be set differently. + */ + QPID_CLIENT_EXTERN std::string getName() const; + + /** Name of the queue this subscription subscribes to */ + QPID_CLIENT_EXTERN std::string getQueue() const; + + /** Get the flow control and acknowledgement settings for this subscription */ + QPID_CLIENT_EXTERN const SubscriptionSettings& getSettings() const; + + /** Set the flow control parameters */ + QPID_CLIENT_EXTERN void setFlowControl(const FlowControl&); + + /** Automatically acknowledge (acquire and accept) batches of n messages. + * You can disable auto-acknowledgement by setting n=0, and use acquire() and accept() + * to manually acquire and accept messages. + */ + QPID_CLIENT_EXTERN void setAutoAck(unsigned int n); + + /** Get the set of ID's for messages received by this subscription but not yet acquired. + * This will always be empty if getSettings().acquireMode=ACQUIRE_MODE_PRE_ACQUIRED + */ + QPID_CLIENT_EXTERN SequenceSet getUnacquired() const; + + /** Get the set of ID's for messages received by this subscription but not yet accepted. */ + QPID_CLIENT_EXTERN SequenceSet getUnaccepted() const; + + /** Acquire messageIds and remove them from the unacquired set. + * oAdd them to the unaccepted set if getSettings().acceptMode == ACCEPT_MODE_EXPLICIT. + */ + QPID_CLIENT_EXTERN void acquire(const SequenceSet& messageIds); + + /** Accept messageIds and remove them from the unaccepted set. + *@pre messageIds is a subset of getUnaccepted() + */ + QPID_CLIENT_EXTERN void accept(const SequenceSet& messageIds); + + /** Release messageIds and remove them from the unaccepted set. + *@pre messageIds is a subset of getUnaccepted() + */ + QPID_CLIENT_EXTERN void release(const SequenceSet& messageIds); + + /* Acquire a single message */ + QPID_CLIENT_INLINE_EXTERN void acquire(const Message& m) { acquire(SequenceSet(m.getId())); } + + /* Accept a single message */ + QPID_CLIENT_INLINE_EXTERN void accept(const Message& m) { accept(SequenceSet(m.getId())); } + + /* Release a single message */ + QPID_CLIENT_INLINE_EXTERN void release(const Message& m) { release(SequenceSet(m.getId())); } + + /** Get the session associated with this subscription */ + QPID_CLIENT_EXTERN Session getSession() const; + + /** Get the subscription manager associated with this subscription */ + QPID_CLIENT_EXTERN SubscriptionManager getSubscriptionManager(); + + /** Cancel the subscription. */ + QPID_CLIENT_EXTERN void cancel(); + + /** Grant the specified amount of message credit */ + QPID_CLIENT_EXTERN void grantMessageCredit(uint32_t); + + /** Grant the specified amount of byte credit */ + QPID_CLIENT_EXTERN void grantByteCredit(uint32_t); + + private: + friend class PrivateImplRef<Subscription>; + friend class SubscriptionManager; +}; +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_SUBSCRIPTION_H*/ diff --git a/qpid/cpp/src/qpid/client/SubscriptionManager.h b/qpid/cpp/src/qpid/client/SubscriptionManager.h new file mode 100644 index 0000000000..404a9c6eb9 --- /dev/null +++ b/qpid/cpp/src/qpid/client/SubscriptionManager.h @@ -0,0 +1,292 @@ +#ifndef QPID_CLIENT_SUBSCRIPTIONMANAGER_H +#define QPID_CLIENT_SUBSCRIPTIONMANAGER_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/Session.h" +#include "qpid/client/Subscription.h" +#include "qpid/sys/Runnable.h" +#include "qpid/sys/Thread.h" +#include "qpid/client/ClientImportExport.h" +#include "qpid/client/MessageListener.h" +#include "qpid/client/LocalQueue.h" +#include "qpid/client/Handle.h" +#include <string> + +namespace qpid { +namespace client { + +class SubscriptionManagerImpl; + +/** + * A class to help create and manage subscriptions. + * + * Set up your subscriptions, then call run() to have messages + * delivered. + * + * \ingroup clientapi + * + * \details + * + * <h2>Subscribing and canceling subscriptions</h2> + * + * <ul> + * <li> + * <p>subscribe()</p> + * <pre> SubscriptionManager subscriptions(session); + * Listener listener(subscriptions); + * subscriptions.subscribe(listener, myQueue);</pre> + * <pre> SubscriptionManager subscriptions(session); + * LocalQueue local_queue; + * subscriptions.subscribe(local_queue, string("message_queue"));</pre></li> + * <li> + * <p>cancel()</p> + * <pre>subscriptions.cancel();</pre></li> + * </ul> + * + * <h2>Waiting for messages (and returning)</h2> + * + * <ul> + * <li> + * <p>run()</p> + * <pre> // Give up control to receive messages + * subscriptions.run();</pre></li> + * <li> + * <p>stop()</p> + * <pre>.// Use this code in a listener to return from run() + * subscriptions.stop();</pre></li> + * <li> + * <p>setAutoStop()</p> + * <pre>.// Return from subscriptions.run() when last subscription is cancelled + *.subscriptions.setAutoStop(true); + *.subscriptons.run(); + * </pre></li> + * <li> + * <p>Ending a subscription in a listener</p> + * <pre> + * void Listener::received(Message& message) { + * + * if (message.getData() == "That's all, folks!") { + * subscriptions.cancel(message.getDestination()); + * } + * } + * </pre> + * </li> + * </ul> + * + */ +class QPID_CLIENT_CLASS_EXTERN SubscriptionManager : public sys::Runnable, public Handle<SubscriptionManagerImpl> +{ + public: + /** Create a new SubscriptionManager associated with a session */ + QPID_CLIENT_EXTERN SubscriptionManager(const Session& session); + QPID_CLIENT_EXTERN SubscriptionManager(const SubscriptionManager&); + QPID_CLIENT_EXTERN ~SubscriptionManager(); + QPID_CLIENT_EXTERN SubscriptionManager& operator=(const SubscriptionManager&); + + /** + * Subscribe a MessagesListener to receive messages from queue. + * + * Provide your own subclass of MessagesListener to process + * incoming messages. It will be called for each message received. + * + *@param listener Listener object to receive messages. + *@param queue Name of the queue to subscribe to. + *@param settings settings for the subscription. + *@param name unique destination name for the subscription, defaults to queue name. + */ + QPID_CLIENT_EXTERN Subscription subscribe(MessageListener& listener, + const std::string& queue, + const SubscriptionSettings& settings, + const std::string& name=std::string()); + + /** + * Subscribe a LocalQueue to receive messages from queue. + * + * Incoming messages are stored in the queue for you to retrieve. + * + *@param queue Name of the queue to subscribe to. + *@param flow initial FlowControl for the subscription. + *@param name unique destination name for the subscription, defaults to queue name. + * If not specified, the queue name is used. + */ + QPID_CLIENT_EXTERN Subscription subscribe(LocalQueue& localQueue, + const std::string& queue, + const SubscriptionSettings& settings, + const std::string& name=std::string()); + + /** + * Subscribe a MessagesListener to receive messages from queue. + * + * Provide your own subclass of MessagesListener to process + * incoming messages. It will be called for each message received. + * + *@param listener Listener object to receive messages. + *@param queue Name of the queue to subscribe to. + *@param name unique destination name for the subscription, defaults to queue name. + * If not specified, the queue name is used. + */ + QPID_CLIENT_EXTERN Subscription subscribe(MessageListener& listener, + const std::string& queue, + const std::string& name=std::string()); + + /** + * Subscribe a LocalQueue to receive messages from queue. + * + * Incoming messages are stored in the queue for you to retrieve. + * + *@param queue Name of the queue to subscribe to. + *@param name unique destination name for the subscription, defaults to queue name. + * If not specified, the queue name is used. + */ + QPID_CLIENT_EXTERN Subscription subscribe(LocalQueue& localQueue, + const std::string& queue, + const std::string& name=std::string()); + + + /** Get a single message from a queue. + * (Note: this currently uses a subscription per invocation and is + * thus relatively expensive. The subscription is cancelled as + * part of each call which can trigger auto-deletion). + *@param result is set to the message from the queue. + *@param timeout wait up this timeout for a message to appear. + *@return true if result was set, false if no message available after timeout. + */ + QPID_CLIENT_EXTERN bool get(Message& result, const std::string& queue, sys::Duration timeout=0); + + /** Get a single message from a queue. + * (Note: this currently uses a subscription per invocation and is + * thus relatively expensive. The subscription is cancelled as + * part of each call which can trigger auto-deletion). + *@param timeout wait up this timeout for a message to appear. + *@return message from the queue. + *@throw Exception if the timeout is exceeded. + */ + QPID_CLIENT_EXTERN Message get(const std::string& queue, sys::Duration timeout=sys::TIME_INFINITE); + + /** Get a subscription by name. + *@throw Exception if not found. + */ + QPID_CLIENT_EXTERN Subscription getSubscription(const std::string& name) const; + + /** Cancel a subscription. See also: Subscription.cancel() */ + QPID_CLIENT_EXTERN void cancel(const std::string& name); + + /** Deliver messages in the current thread until stop() is called. + * Only one thread may be running in a SubscriptionManager at a time. + * @see run + */ + QPID_CLIENT_EXTERN void run(); + + /** Start a new thread to deliver messages. + * Only one thread may be running in a SubscriptionManager at a time. + * @see start + */ + QPID_CLIENT_EXTERN void start(); + + /** + * Wait for the thread started by a call to start() to complete. + */ + QPID_CLIENT_EXTERN void wait(); + + /** If set true, run() will stop when all subscriptions + * are cancelled. If false, run will only stop when stop() + * is called. True by default. + */ + QPID_CLIENT_EXTERN void setAutoStop(bool set=true); + + /** Stop delivery. Causes run() to return, or the thread started with start() to exit. */ + QPID_CLIENT_EXTERN void stop(); + + static const uint32_t UNLIMITED=0xFFFFFFFF; + + /** Set the flow control for a subscription. */ + QPID_CLIENT_EXTERN void setFlowControl(const std::string& name, const FlowControl& flow); + + /** Set the flow control for a subscription. + *@param name: name of the subscription. + *@param messages: message credit. + *@param bytes: byte credit. + *@param window: if true use window-based flow control. + */ + QPID_CLIENT_EXTERN void setFlowControl(const std::string& name, uint32_t messages, uint32_t bytes, bool window=true); + + /** Set the default settings for subscribe() calls that don't + * include a SubscriptionSettings parameter. + */ + QPID_CLIENT_EXTERN void setDefaultSettings(const SubscriptionSettings& s); + + /** Get the default settings for subscribe() calls that don't + * include a SubscriptionSettings parameter. + */ + QPID_CLIENT_EXTERN const SubscriptionSettings& getDefaultSettings() const; + + /** Get the default settings for subscribe() calls that don't + * include a SubscriptionSettings parameter. + */ + QPID_CLIENT_EXTERN SubscriptionSettings& getDefaultSettings(); + + /** + * Set the default flow control settings for subscribe() calls + * that don't include a SubscriptionSettings parameter. + * + *@param messages: message credit. + *@param bytes: byte credit. + *@param window: if true use window-based flow control. + */ + QPID_CLIENT_EXTERN void setFlowControl(uint32_t messages, uint32_t bytes, bool window=true); + + /** + *Set the default accept-mode for subscribe() calls that don't + *include a SubscriptionSettings parameter. + */ + QPID_CLIENT_EXTERN void setAcceptMode(AcceptMode mode); + + /** + * Set the default acquire-mode subscribe()s that don't specify SubscriptionSettings. + */ + QPID_CLIENT_EXTERN void setAcquireMode(AcquireMode mode); + + QPID_CLIENT_EXTERN void registerFailoverHandler ( boost::function<void ()> fh ); + + QPID_CLIENT_EXTERN Session getSession() const; + + SubscriptionManager(SubscriptionManagerImpl*); ///<@internal + + private: + typedef SubscriptionManagerImpl Impl; + friend class PrivateImplRef<SubscriptionManager>; +}; + +/** AutoCancel cancels a subscription in its destructor */ +class AutoCancel { + public: + AutoCancel(SubscriptionManager&, const std::string& tag); + ~AutoCancel(); + private: + SubscriptionManager& sm; + std::string tag; +}; + +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_SUBSCRIPTIONMANAGER_H*/ diff --git a/qpid/cpp/src/qpid/client/SubscriptionSettings.h b/qpid/cpp/src/qpid/client/SubscriptionSettings.h new file mode 100644 index 0000000000..bee39f6816 --- /dev/null +++ b/qpid/cpp/src/qpid/client/SubscriptionSettings.h @@ -0,0 +1,135 @@ +#ifndef QPID_CLIENT_SUBSCRIPTIONSETTINGS_H +#define QPID_CLIENT_SUBSCRIPTIONSETTINGS_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/FlowControl.h" +#include "qpid/framing/enum.h" + +namespace qpid { +namespace client { + +/** Bring AMQP enum definitions for message class into this namespace. */ +using qpid::framing::message::AcceptMode; +using qpid::framing::message::AcquireMode; +using qpid::framing::message::ACCEPT_MODE_EXPLICIT; +using qpid::framing::message::ACCEPT_MODE_NONE; +using qpid::framing::message::ACQUIRE_MODE_NOT_ACQUIRED; +using qpid::framing::message::ACQUIRE_MODE_PRE_ACQUIRED; +using qpid::framing::message::CREDIT_UNIT_BYTE; +using qpid::framing::message::CREDIT_UNIT_MESSAGE; +using qpid::framing::message::DELIVERY_MODE_NON_PERSISTENT; +using qpid::framing::message::DELIVERY_MODE_PERSISTENT; +using qpid::framing::message::FLOW_MODE_CREDIT; +using qpid::framing::message::FLOW_MODE_WINDOW; + + +enum CompletionMode { + MANUAL_COMPLETION = 0, + COMPLETE_ON_DELIVERY = 1, + COMPLETE_ON_ACCEPT = 2 +}; +/** + * Settings for a subscription. + */ +struct SubscriptionSettings +{ + SubscriptionSettings( + FlowControl flow=FlowControl::unlimited(), + AcceptMode accept=ACCEPT_MODE_EXPLICIT, + AcquireMode acquire=ACQUIRE_MODE_PRE_ACQUIRED, + unsigned int autoAck_=1, + CompletionMode completion=COMPLETE_ON_DELIVERY + ) : flowControl(flow), acceptMode(accept), acquireMode(acquire), autoAck(autoAck_), completionMode(completion), exclusive(false) {} + + FlowControl flowControl; ///@< Flow control settings. @see FlowControl + /** + * The acceptMode determines whether the broker should expect + * delivery of messages to be acknowledged by the client + * indicating that it accepts them. A value of + * ACCEPT_MODE_EXPLICIT means that messages must be accepted + * (note: this may be done automatically by the library - see + * autoAck - or through an explicit call be the application - see + * Subscription::accept()) before they can be dequeued. A value of + * ACCEPT_MODE_NONE means that the broker can dequeue a message as + * soon as it is acquired. + */ + AcceptMode acceptMode; ///@< ACCEPT_MODE_EXPLICIT or ACCEPT_MODE_NONE + /** + * The acquireMode determines whether messages are locked for the + * subscriber when delivered, and thus are not delivered to any + * other subscriber unless this subscriber releases them. + * + * The default is ACQUIRE_MODE_PRE_ACQUIRED meaning that the + * subscriber expects to have been given that message exclusively + * (i.e. the message will not be given to any other subscriber + * unless released explicitly or by this subscribers session + * failing without having accepted the message). + * + * Delivery of message in ACQUIRE_MODE_NOT_ACQUIRED mode means the + * message will still be available for other subscribers to + * receive. The application can if desired acquire a (set of) + * messages through an explicit acquire call - see + * Subscription::acquire(). + */ + AcquireMode acquireMode; ///@< ACQUIRE_MODE_PRE_ACQUIRED or ACQUIRE_MODE_NOT_ACQUIRED + + /** + * Configures the frequency at which messages are automatically + * accepted (e.g. a value of 5 means that messages are accepted in + * batches of 5). A value of 0 means no automatic acknowledgement + * will occur and the application will itself be responsible for + * accepting messages. + */ + unsigned int autoAck; + /** + * In windowing mode, completion of a message will cause the + * credit used up by that message to be reallocated. The + * subscriptions completion mode controls how completion is + * managed. + * + * If set to COMPLETE_ON_DELIVERY (which is the default), messages + * will be marked as completed once they have been received. The + * server will be explicitly notified of all completed messages + * for the session when the next accept is sent through the + * subscription (either explictly or through autAck). However the + * server may also periodically request information on the + * completed messages. + * + * If set to COMPLETE_ON_ACCEPT, messages will be marked as + * completed once they are accepted (via the Subscription class) + * and the server will also be notified of all completed messages + * for the session. + * + * If set to MANUAL_COMPLETION the application is responsible for + * completing messages (@see Session::markCompleted()). + */ + CompletionMode completionMode; + /** + * If set, requests that no other subscriber be allowed to access + * the queue while this subscription is active. + */ + bool exclusive; +}; + +}} // namespace qpid::client + +#endif /*!QPID_CLIENT_SUBSCRIPTIONSETTINGS_H*/ diff --git a/qpid/cpp/src/qpid/client/TypedResult.h b/qpid/cpp/src/qpid/client/TypedResult.h new file mode 100644 index 0000000000..8e1a16580c --- /dev/null +++ b/qpid/cpp/src/qpid/client/TypedResult.h @@ -0,0 +1,65 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#ifndef _TypedResult_ +#define _TypedResult_ + +#include "qpid/client/Completion.h" +#include "qpid/framing/StructHelper.h" + +namespace qpid { +namespace client { + +/** + * Returned by asynchronous commands that return a result. + * You can use get() to wait for completion and get the result value. + * \ingroup clientapi + */ +template <class T> class TypedResult : public Completion +{ + T result; + bool decoded; + +public: + ///@internal + TypedResult(const Completion& c) : Completion(c), decoded(false) {} + + /** + * Wait for the asynchronous command that returned this TypedResult to complete + * and return its result. + * + *@return The result returned by the command. + *@exception If the command returns an error, get() throws an exception. + * + */ + T& get() { + if (!decoded) { + framing::StructHelper helper; + helper.decode(result, getResult()); + decoded = true; + } + return result; + } +}; + +}} + +#endif diff --git a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp index dac2a4a6d9..872e1d59df 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp +++ b/qpid/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp @@ -89,6 +89,7 @@ const std::string NODE("node"); const std::string LINK("link"); const std::string MODE("mode"); const std::string RELIABILITY("reliability"); +const std::string TIMEOUT("timeout"); const std::string NAME("name"); const std::string DURABLE("durable"); const std::string X_DECLARE("x-declare"); @@ -240,8 +241,8 @@ class Subscription : public Exchange, public MessageSource void cancel(qpid::client::AsyncSession& session, const std::string& destination); private: const std::string queue; - const bool reliable; const bool durable; + const bool reliable; const std::string actualType; const bool exclusiveQueue; const bool exclusiveSubscription; @@ -516,13 +517,25 @@ std::string Subscription::getSubscriptionName(const std::string& base, const std Subscription::Subscription(const Address& address, const std::string& type) : Exchange(address), queue(getSubscriptionName(name, (Opt(address)/LINK/NAME).str())), - reliable(AddressResolution::is_reliable(address)), durable(Opt(address)/LINK/DURABLE), + //if the link is durable, then assume it is also reliable unless explicitly stated otherwise + //if not assume it is unreliable unless explicitly stated otherwise + reliable(durable ? !AddressResolution::is_unreliable(address) : AddressResolution::is_reliable(address)), actualType(type.empty() ? (specifiedType.empty() ? TOPIC_EXCHANGE : specifiedType) : type), exclusiveQueue((Opt(address)/LINK/X_DECLARE/EXCLUSIVE).asBool(true)), exclusiveSubscription((Opt(address)/LINK/X_SUBSCRIBE/EXCLUSIVE).asBool(exclusiveQueue)), alternateExchange((Opt(address)/LINK/X_DECLARE/ALTERNATE_EXCHANGE).str()) { + const Variant* timeout = (Opt(address)/LINK/TIMEOUT).value; + if (timeout) { + if (timeout->asUint32()) queueOptions.setInt("qpid.auto_delete_timeout", timeout->asUint32()); + } else if (durable && !(Opt(address)/LINK/RELIABILITY).value) { + //if durable but not explicitly reliable, then set a non-zero + //default for the autodelete timeout (previously this would + //have defaulted to autodelete immediately anyway, so the risk + //of the change causing problems is mitigated) + queueOptions.setInt("qpid.auto_delete_delay", 15*60); + } (Opt(address)/LINK/X_DECLARE/ARGUMENTS).collect(queueOptions); (Opt(address)/LINK/X_SUBSCRIBE/ARGUMENTS).collect(subscriptionOptions); std::string selector = Opt(address)/LINK/SELECTOR; @@ -584,7 +597,7 @@ void Subscription::subscribe(qpid::client::AsyncSession& session, const std::str //create subscription queue: session.queueDeclare(arg::queue=queue, arg::exclusive=exclusiveQueue, - arg::autoDelete=!reliable, arg::durable=durable, + arg::autoDelete=!(durable || reliable), arg::durable=durable, arg::alternateExchange=alternateExchange, arg::arguments=queueOptions); //'default' binding: @@ -997,6 +1010,7 @@ Verifier::Verifier() link[NAME] = true; link[DURABLE] = true; link[RELIABILITY] = true; + link[TIMEOUT] = true; link[X_SUBSCRIBE] = true; link[X_DECLARE] = true; link[X_BINDINGS] = true; diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp index 668b500570..9406c992fe 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp +++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp @@ -43,6 +43,7 @@ using qpid::framing::Uuid; namespace { const std::string TCP("tcp"); +const std::string COLON(":"); double FOREVER(std::numeric_limits<double>::max()); // Time values in seconds can be specified as integer or floating point values. @@ -86,9 +87,9 @@ bool expired(const sys::AbsTime& start, double timeout) } // namespace ConnectionImpl::ConnectionImpl(const std::string& url, const Variant::Map& options) : - replaceUrls(false), reconnect(false), timeout(FOREVER), limit(-1), + replaceUrls(false), autoReconnect(false), timeout(FOREVER), limit(-1), minReconnectInterval(0.001), maxReconnectInterval(2), - retries(0), reconnectOnLimitExceeded(true) + retries(0), reconnectOnLimitExceeded(true), disableAutoDecode(false) { setOptions(options); urls.insert(urls.begin(), url); @@ -106,7 +107,7 @@ void ConnectionImpl::setOption(const std::string& name, const Variant& value) { sys::Mutex::ScopedLock l(lock); if (name == "reconnect") { - reconnect = value; + autoReconnect = value; } else if (name == "reconnect-timeout" || name == "reconnect_timeout") { timeout = timeValue(value); } else if (name == "reconnect-limit" || name == "reconnect_limit") { @@ -157,8 +158,10 @@ void ConnectionImpl::setOption(const std::string& name, const Variant& value) settings.sslCertName = value.asString(); } else if (name == "x-reconnect-on-limit-exceeded" || name == "x_reconnect_on_limit_exceeded") { reconnectOnLimitExceeded = value; - } else if (name == "client-properties") { + } else if (name == "client-properties" || name == "client_properties") { amqp_0_10::translate(value.asMap(), settings.clientProperties); + } else if (name == "disable-auto-decode" || name == "disable_auto_decode") { + disableAutoDecode = value; } else { throw qpid::messaging::MessagingException(QPID_MSG("Invalid option: " << name << " not recognised")); } @@ -254,7 +257,7 @@ void ConnectionImpl::open() void ConnectionImpl::reopen() { - if (!reconnect) { + if (!autoReconnect) { throw qpid::messaging::TransportFailure("Failed to connect (reconnect disabled)"); } open(); @@ -265,7 +268,7 @@ void ConnectionImpl::connect(const qpid::sys::AbsTime& started) { QPID_LOG(debug, "Starting connection, urls=" << asString(urls)); for (double i = minReconnectInterval; !tryConnect(); i = std::min(i*2, maxReconnectInterval)) { - if (!reconnect) { + if (!autoReconnect) { throw qpid::messaging::TransportFailure("Failed to connect (reconnect disabled)"); } if (limit >= 0 && retries++ >= limit) { @@ -341,9 +344,52 @@ bool ConnectionImpl::backoff() } } +void ConnectionImpl::reconnect(const std::string& u) +{ + sys::Mutex::ScopedLock l(lock); + try { + QPID_LOG(info, "Trying to connect to " << u << "..."); + Url url(u, settings.protocol.size() ? settings.protocol : TCP); + if (url.getUser().size()) settings.username = url.getUser(); + if (url.getPass().size()) settings.password = url.getPass(); + connection.open(url, settings); + QPID_LOG(info, "Connected to " << u); + mergeUrls(connection.getInitialBrokers(), l); + if (!resetSessions(l)) throw qpid::messaging::TransportFailure("Could not re-establish sessions"); + } catch (const qpid::TransportFailure& e) { + QPID_LOG(info, "Failed to connect to " << u << ": " << e.what()); + throw qpid::messaging::TransportFailure(e.what()); + } catch (const std::exception& e) { + QPID_LOG(info, "Error while connecting to " << u << ": " << e.what()); + throw qpid::messaging::MessagingException(e.what()); + } +} + +void ConnectionImpl::reconnect() +{ + if (!tryConnect()) { + throw qpid::messaging::TransportFailure("Could not reconnect"); + } +} +std::string ConnectionImpl::getUrl() const +{ + if (isOpen()) { + std::stringstream u; + u << connection.getNegotiatedSettings().protocol << COLON << connection.getNegotiatedSettings().host << COLON << connection.getNegotiatedSettings().port; + return u.str(); + } else { + return std::string(); + } +} + std::string ConnectionImpl::getAuthenticatedUsername() { return connection.getNegotiatedSettings().username; } +bool ConnectionImpl::getAutoDecode() const +{ + return !disableAutoDecode; +} + }}} // namespace qpid::client::amqp0_10 diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h index d1ac4533d5..ae839dc690 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h +++ b/qpid/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h @@ -53,6 +53,10 @@ class ConnectionImpl : public qpid::messaging::ConnectionImpl void setOption(const std::string& name, const qpid::types::Variant& value); bool backoff(); std::string getAuthenticatedUsername(); + void reconnect(const std::string& url); + void reconnect(); + std::string getUrl() const; + bool getAutoDecode() const; private: typedef std::map<std::string, qpid::messaging::Session> Sessions; @@ -63,13 +67,14 @@ class ConnectionImpl : public qpid::messaging::ConnectionImpl bool replaceUrls; // Replace rather than merging with reconnect-urls std::vector<std::string> urls; qpid::client::ConnectionSettings settings; - bool reconnect; + bool autoReconnect; double timeout; int32_t limit; double minReconnectInterval; double maxReconnectInterval; int32_t retries; bool reconnectOnLimitExceeded; + bool disableAutoDecode; void setOptions(const qpid::types::Variant::Map& options); void connect(const qpid::sys::AbsTime& started); diff --git a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp index db6e843cf6..27a2107702 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp +++ b/qpid/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp @@ -399,7 +399,7 @@ void populate(qpid::messaging::Message& message, FrameSet& command) //need to be able to link the message back to the transfer it was delivered by //e.g. for rejecting. MessageImplAccess::get(message).setInternalId(command.getId()); - + message.setContent(command.getContent()); populateHeaders(message, command.getHeaders()); diff --git a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp index 348f9e160c..834ba1fe9f 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp +++ b/qpid/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp @@ -21,6 +21,7 @@ #include "qpid/client/amqp0_10/OutgoingMessage.h" #include "qpid/client/amqp0_10/AddressResolution.h" #include "qpid/amqp_0_10/Codecs.h" +#include "qpid/types/encodings.h" #include "qpid/types/Variant.h" #include "qpid/messaging/Address.h" #include "qpid/messaging/Message.h" @@ -45,13 +46,30 @@ const std::string SUBJECT("qpid.subject"); const std::string X_APP_ID("x-amqp-0-10.app-id"); const std::string X_ROUTING_KEY("x-amqp-0-10.routing-key"); const std::string X_CONTENT_ENCODING("x-amqp-0-10.content-encoding"); +const std::string TEXT_PLAIN("text/plain"); } void OutgoingMessage::convert(const qpid::messaging::Message& from) { //TODO: need to avoid copying as much as possible - message.setData(from.getContent()); - message.getMessageProperties().setContentType(from.getContentType()); + if (from.getContentObject().getType() == qpid::types::VAR_MAP) { + std::string content; + qpid::amqp_0_10::MapCodec::encode(from.getContentObject().asMap(), content); + message.getMessageProperties().setContentType(qpid::amqp_0_10::MapCodec::contentType); + message.setData(content); + } else if (from.getContentObject().getType() == qpid::types::VAR_LIST) { + std::string content; + qpid::amqp_0_10::ListCodec::encode(from.getContentObject().asList(), content); + message.getMessageProperties().setContentType(qpid::amqp_0_10::ListCodec::contentType); + message.setData(content); + } else if (from.getContentObject().getType() == qpid::types::VAR_STRING && + (from.getContentObject().getEncoding() == qpid::types::encodings::UTF8 || from.getContentObject().getEncoding() == qpid::types::encodings::ASCII)) { + message.getMessageProperties().setContentType(TEXT_PLAIN); + message.setData(from.getContent()); + } else { + message.setData(from.getContent()); + message.getMessageProperties().setContentType(from.getContentType()); + } if ( !from.getCorrelationId().empty() ) message.getMessageProperties().setCorrelationId(from.getCorrelationId()); message.getMessageProperties().setUserId(from.getUserId()); diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp index 7e8de21247..c356bc298b 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp +++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.cpp @@ -25,6 +25,8 @@ #include "qpid/messaging/exceptions.h" #include "qpid/messaging/Receiver.h" #include "qpid/messaging/Session.h" +#include "qpid/amqp_0_10/Codecs.h" +#include "qpid/types/encodings.h" namespace qpid { namespace client { @@ -83,6 +85,7 @@ void ReceiverImpl::start() if (state == STOPPED) { state = STARTED; startFlow(l); + session.sendCompletion(); } } @@ -148,18 +151,42 @@ qpid::messaging::Address ReceiverImpl::getAddress() const } ReceiverImpl::ReceiverImpl(SessionImpl& p, const std::string& name, - const qpid::messaging::Address& a) : + const qpid::messaging::Address& a, bool autoDecode_) : - parent(&p), destination(name), address(a), byteCredit(0xFFFFFFFF), + parent(&p), destination(name), address(a), byteCredit(0xFFFFFFFF), autoDecode(autoDecode_), state(UNRESOLVED), capacity(0), window(0) {} +namespace { +const std::string TEXT_PLAIN("text/plain"); +} + bool ReceiverImpl::getImpl(qpid::messaging::Message& message, qpid::messaging::Duration timeout) { { sys::Mutex::ScopedLock l(lock); if (state == CANCELLED) return false; } - return parent->get(*this, message, timeout); + if (parent->get(*this, message, timeout)) { + if (autoDecode) { + if (message.getContentType() == qpid::amqp_0_10::MapCodec::contentType) { + message.getContentObject() = qpid::types::Variant::Map(); + decode(message, message.getContentObject().asMap()); + } else if (message.getContentType() == qpid::amqp_0_10::ListCodec::contentType) { + message.getContentObject() = qpid::types::Variant::List(); + decode(message, message.getContentObject().asList()); + } else if (!message.getContentBytes().empty()) { + message.getContentObject() = message.getContentBytes(); + if (message.getContentType() == TEXT_PLAIN) { + message.getContentObject().setEncoding(qpid::types::encodings::UTF8); + } else { + message.getContentObject().setEncoding(qpid::types::encodings::BINARY); + } + } + } + return true; + } else { + return false; + } } bool ReceiverImpl::fetchImpl(qpid::messaging::Message& message, qpid::messaging::Duration timeout) diff --git a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h index 4dba76c8d9..0d3366907b 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h +++ b/qpid/cpp/src/qpid/client/amqp0_10/ReceiverImpl.h @@ -48,7 +48,7 @@ class ReceiverImpl : public qpid::messaging::ReceiverImpl enum State {UNRESOLVED, STOPPED, STARTED, CANCELLED}; ReceiverImpl(SessionImpl& parent, const std::string& name, - const qpid::messaging::Address& address); + const qpid::messaging::Address& address, bool autoDecode); void init(qpid::client::AsyncSession session, AddressResolution& resolver); bool get(qpid::messaging::Message& message, qpid::messaging::Duration timeout); @@ -74,6 +74,7 @@ class ReceiverImpl : public qpid::messaging::ReceiverImpl const std::string destination; const qpid::messaging::Address address; const uint32_t byteCredit; + const bool autoDecode; State state; std::auto_ptr<MessageSource> source; diff --git a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp index e4c2c6afb8..982bfa3503 100644 --- a/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp +++ b/qpid/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp @@ -207,7 +207,7 @@ Receiver SessionImpl::createReceiverImpl(const qpid::messaging::Address& address ScopedLock l(lock); std::string name = address.getName(); getFreeKey(name, receivers); - Receiver receiver(new ReceiverImpl(*this, name, address)); + Receiver receiver(new ReceiverImpl(*this, name, address, connection->getAutoDecode())); getImplPtr<Receiver, ReceiverImpl>(receiver)->init(session, resolver); receivers[name] = receiver; return receiver; diff --git a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp index 53d825771b..5ffd14596f 100644 --- a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp +++ b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp @@ -26,6 +26,7 @@ #include "qpid/sys/SecurityLayer.h" #include "qpid/sys/SecuritySettings.h" #include "qpid/log/Statement.h" +#include "qpid/NullSaslServer.h" #include "boost/tokenizer.hpp" @@ -107,6 +108,12 @@ std::auto_ptr<Sasl> SaslFactory::create( const std::string & username, const std return sasl; } +std::auto_ptr<SaslServer> SaslFactory::createServer( const std::string& realm, bool /*encryptionRequired*/, const qpid::sys::SecuritySettings& ) +{ + std::auto_ptr<SaslServer> server(new NullSaslServer(realm)); + return server; +} + namespace { const std::string ANONYMOUS = "ANONYMOUS"; const std::string PLAIN = "PLAIN"; diff --git a/qpid/cpp/src/qpid/console/Broker.cpp b/qpid/cpp/src/qpid/console/Broker.cpp deleted file mode 100644 index 86a17d4a10..0000000000 --- a/qpid/cpp/src/qpid/console/Broker.cpp +++ /dev/null @@ -1,333 +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 "qpid/console/Broker.h" -#include "qpid/console/Object.h" -#include "qpid/console/Value.h" -#include "qpid/console/SessionManager.h" -#include "qpid/console/ConsoleListener.h" -#include "qpid/log/Statement.h" -#include "qpid/sys/SystemInfo.h" - -using namespace qpid::client; -using namespace qpid::console; -using namespace qpid::framing; -using namespace qpid::sys; -using namespace std; - -Broker::Broker(SessionManager& sm, ConnectionSettings& settings) : - sessionManager(sm), connected(false), connectionSettings(settings), - reqsOutstanding(1), syncInFlight(false), topicBound(false), methodObject(0), - connThreadBody(*this), connThread(connThreadBody) -{ - string osName; - string nodeName; - string release; - string version; - string machine; - - sys::SystemInfo::getSystemId(osName, nodeName, release, version, machine); - uint32_t pid = sys::SystemInfo::getParentProcessId(); - - stringstream text; - - text << "qmfc-cpp-" << nodeName << "-" << pid; - amqpSessionId = string(text.str()); - - QPID_LOG(debug, "Broker::Broker: constructed, amqpSessionId=" << amqpSessionId); -} - -Broker::~Broker() -{ - connThreadBody.shutdown(); - connThread.join(); - resetAgents(); - // resetAgents() does not delete the broker agent... - for (AgentMap::iterator iter = agents.begin(); iter != agents.end(); iter++) { - delete iter->second; - } -} - -string Broker::getUrl() const -{ - stringstream url; - url << connectionSettings.host << ":" << connectionSettings.port; - return url.str(); -} - -void Broker::encodeHeader(Buffer& buf, uint8_t opcode, uint32_t seq) const -{ - buf.putOctet('A'); - buf.putOctet('M'); - buf.putOctet('2'); - buf.putOctet(opcode); - buf.putLong (seq); -} - -bool Broker::checkHeader(Buffer& buf, uint8_t *opcode, uint32_t *seq) const -{ - if (buf.getSize() < 8) - return false; - - uint8_t h1 = buf.getOctet(); - uint8_t h2 = buf.getOctet(); - uint8_t h3 = buf.getOctet(); - - *opcode = buf.getOctet(); - *seq = buf.getLong(); - - return h1 == 'A' && h2 == 'M' && h3 == '2'; -} - -void Broker::received(qpid::client::Message& msg) -{ -#define QMF_HEADER_SIZE 8 - string data = msg.getData(); - Buffer inBuffer(const_cast<char*>(data.c_str()), data.size()); - uint8_t opcode; - uint32_t sequence; - - while (inBuffer.available() >= QMF_HEADER_SIZE) { - if (checkHeader(inBuffer, &opcode, &sequence)) { - QPID_LOG(trace, "Broker::received: opcode=" << opcode << " seq=" << sequence); - - if (opcode == 'b') sessionManager.handleBrokerResp(this, inBuffer, sequence); - else if (opcode == 'p') sessionManager.handlePackageInd(this, inBuffer, sequence); - else if (opcode == 'z') sessionManager.handleCommandComplete(this, inBuffer, sequence); - else if (opcode == 'q') sessionManager.handleClassInd(this, inBuffer, sequence); - else if (opcode == 'm') sessionManager.handleMethodResp(this, inBuffer, sequence); - else if (opcode == 'h') sessionManager.handleHeartbeatInd(this, inBuffer, sequence); - else if (opcode == 'e') sessionManager.handleEventInd(this, inBuffer, sequence); - else if (opcode == 's') sessionManager.handleSchemaResp(this, inBuffer, sequence); - else if (opcode == 'c') sessionManager.handleContentInd(this, inBuffer, sequence, true, false); - else if (opcode == 'i') sessionManager.handleContentInd(this, inBuffer, sequence, false, true); - else if (opcode == 'g') sessionManager.handleContentInd(this, inBuffer, sequence, true, true); - } else - return; - } -} - -void Broker::resetAgents() -{ - for (AgentMap::iterator iter = agents.begin(); iter != agents.end(); iter++) { - if (sessionManager.listener != 0) - sessionManager.listener->delAgent(*(iter->second)); - delete iter->second; - } - - agents.clear(); - agents[0x0000000100000000LL] = new Agent(this, 0, "BrokerAgent"); -} - -void Broker::updateAgent(const Object& object) -{ - uint32_t brokerBank = object.attrUint("brokerBank"); - uint32_t agentBank = object.attrUint("agentBank"); - uint64_t agentKey = ((uint64_t) brokerBank << 32) | (uint64_t) agentBank; - AgentMap::iterator iter = agents.find(agentKey); - - if (object.isDeleted()) { - if (iter != agents.end()) { - if (sessionManager.listener != 0) - sessionManager.listener->delAgent(*(iter->second)); - delete iter->second; - agents.erase(iter); - } - } else { - if (iter == agents.end()) { - Agent* agent = new Agent(this, agentBank, object.attrString("label")); - agents[agentKey] = agent; - if (sessionManager.listener != 0) - sessionManager.listener->newAgent(*agent); - } - } -} - -void Broker::ConnectionThread::run() -{ - static const int delayMin(1); - static const int delayMax(128); - static const int delayFactor(2); - int delay(delayMin); - string dest("qmfc"); - - sessionId.generate(); - queueName << "qmfc-" << sessionId; - - while (true) { - try { - broker.topicBound = false; - broker.reqsOutstanding = 1; - connection.open(broker.connectionSettings); - session = connection.newSession(queueName.str()); - subscriptions = new client::SubscriptionManager(session); - - session.queueDeclare(arg::queue=queueName.str(), arg::autoDelete=true, - arg::exclusive=true); - session.exchangeBind(arg::exchange="amq.direct", arg::queue=queueName.str(), - arg::bindingKey=queueName.str()); - - subscriptions->setAcceptMode(ACCEPT_MODE_NONE); - subscriptions->setAcquireMode(ACQUIRE_MODE_PRE_ACQUIRED); - subscriptions->subscribe(broker, queueName.str(), dest); - subscriptions->setFlowControl(dest, FlowControl::unlimited()); - { - Mutex::ScopedLock _lock(connLock); - if (shuttingDown) - return; - operational = true; - broker.resetAgents(); - broker.connected = true; - broker.sessionManager.handleBrokerConnect(&broker); - broker.sessionManager.startProtocol(&broker); - try { - Mutex::ScopedUnlock _unlock(connLock); - subscriptions->run(); - } catch (std::exception) {} - - operational = false; - broker.connected = false; - broker.sessionManager.handleBrokerDisconnect(&broker); - } - delay = delayMin; - connection.close(); - delete subscriptions; - subscriptions = 0; - } catch (std::exception &e) { - QPID_LOG(debug, " outer exception: " << e.what()); - if (delay < delayMax) - delay *= delayFactor; - } - - { - Mutex::ScopedLock _lock(connLock); - if (shuttingDown) - return; - { - Mutex::ScopedUnlock _unlock(connLock); - ::sleep(delay); - } - if (shuttingDown) - return; - } - } -} - -Broker::ConnectionThread::~ConnectionThread() -{ - if (subscriptions != 0) { - delete subscriptions; - } -} - -void Broker::ConnectionThread::sendBuffer(Buffer& buf, uint32_t length, - const string& exchange, const string& routingKey) -{ - { - Mutex::ScopedLock _lock(connLock); - if (!operational) - return; - } - - client::Message msg; - string data; - - buf.getRawData(data, length); - msg.getDeliveryProperties().setRoutingKey(routingKey); - msg.getMessageProperties().setReplyTo(ReplyTo("amq.direct", queueName.str())); - msg.setData(data); - try { - session.messageTransfer(arg::content=msg, arg::destination=exchange); - } catch(std::exception&) {} -} - -void Broker::ConnectionThread::bindExchange(const std::string& exchange, const std::string& key) -{ - { - Mutex::ScopedLock _lock(connLock); - if (!operational) - return; - } - - QPID_LOG(debug, "Broker::ConnectionThread::bindExchange: exchange=" << exchange << " key=" << key); - session.exchangeBind(arg::exchange=exchange, arg::queue=queueName.str(), - arg::bindingKey=key); -} - -void Broker::ConnectionThread::shutdown() -{ - { - Mutex::ScopedLock _lock(connLock); - shuttingDown = true; - } - if (subscriptions) - subscriptions->stop(); -} - -void Broker::waitForStable() -{ - Mutex::ScopedLock l(lock); - if (reqsOutstanding == 0) - return; - syncInFlight = true; - while (reqsOutstanding != 0) { - bool result = cond.wait(lock, AbsTime(now(), TIME_SEC * sessionManager.settings.getTimeout)); - if (!result) - throw(Exception("Timed out waiting for broker to synchronize")); - } -} - -void Broker::incOutstanding() -{ - Mutex::ScopedLock l(lock); - reqsOutstanding++; -} - -void Broker::decOutstanding() -{ - Mutex::ScopedLock l(lock); - reqsOutstanding--; - if (reqsOutstanding == 0) { - if (!topicBound) { - topicBound = true; - for (vector<string>::const_iterator iter = sessionManager.bindingKeyList.begin(); - iter != sessionManager.bindingKeyList.end(); iter++) - connThreadBody.bindExchange("qpid.management", *iter); - } - if (syncInFlight) { - syncInFlight = false; - cond.notify(); - } - } -} - -void Broker::appendAgents(Agent::Vector& agentlist) const -{ - for (AgentMap::const_iterator iter = agents.begin(); iter != agents.end(); iter++) { - agentlist.push_back(iter->second); - } -} - -ostream& qpid::console::operator<<(ostream& o, const Broker& k) -{ - o << "Broker: " << k.connectionSettings.host << ":" << k.connectionSettings.port; - return o; -} diff --git a/qpid/cpp/src/qpid/console/ClassKey.cpp b/qpid/cpp/src/qpid/console/ClassKey.cpp deleted file mode 100644 index d4b59fc413..0000000000 --- a/qpid/cpp/src/qpid/console/ClassKey.cpp +++ /dev/null @@ -1,106 +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 "qpid/console/ClassKey.h" -#include <string.h> -#include <iostream> -#include <cstdio> - -using namespace std; -using namespace qpid::console; - -ClassKey::ClassKey(const string& _package, const string& _name, const uint8_t* _hash) : - package(_package), name(_name) -{ - ::memcpy(hash, _hash, HASH_SIZE); -} - -string ClassKey::getHashString() const -{ - char cstr[36]; - ::sprintf(cstr, "%02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x%02x%02x", - hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], - hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]); - return string(cstr); -} - -string ClassKey::str() const -{ - string result(package + ":" + name + "(" + getHashString() + ")"); - return result; -} - -bool ClassKey::operator==(const ClassKey& other) const -{ - return ::memcmp(hash, other.hash, HASH_SIZE) == 0 && - name == other.name && - package == other.package; -} - -bool ClassKey::operator!=(const ClassKey& other) const -{ - return !(*this == other); -} - -bool ClassKey::operator<(const ClassKey& other) const -{ - int cmp = ::memcmp(hash, other.hash, HASH_SIZE); - if (cmp != 0) - return cmp < 0; - cmp = name.compare(other.name); - if (cmp != 0) - return cmp < 0; - return package < other.package; -} - -bool ClassKey::operator>(const ClassKey& other) const -{ - int cmp = ::memcmp(hash, other.hash, HASH_SIZE); - if (cmp != 0) - return cmp > 0; - cmp = name.compare(other.name); - if (cmp != 0) - return cmp > 0; - return package > other.package; -} - -bool ClassKey::operator<=(const ClassKey& other) const -{ - return !(*this > other); -} - -bool ClassKey::operator>=(const ClassKey& other) const -{ - return !(*this < other); -} - -void ClassKey::encode(qpid::framing::Buffer& buffer) const -{ - buffer.putShortString(package); - buffer.putShortString(name); - buffer.putBin128(const_cast<uint8_t*>(hash)); -} - -ostream& qpid::console::operator<<(ostream& o, const ClassKey& k) -{ - o << k.str(); - return o; -} diff --git a/qpid/cpp/src/qpid/console/Event.cpp b/qpid/cpp/src/qpid/console/Event.cpp deleted file mode 100644 index 3e14804b35..0000000000 --- a/qpid/cpp/src/qpid/console/Event.cpp +++ /dev/null @@ -1,205 +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 "qpid/console/Broker.h" -#include "qpid/console/ClassKey.h" -#include "qpid/console/Schema.h" -#include "qpid/console/Event.h" -#include "qpid/console/Value.h" -#include "qpid/sys/Time.h" -#include "qpid/framing/Buffer.h" - -using namespace qpid::console; -using namespace std; -using qpid::framing::Uuid; -using qpid::framing::FieldTable; - -Event::Event(Broker* _broker, SchemaClass* _schema, qpid::framing::Buffer& buffer) : - broker(_broker), schema(_schema) -{ - timestamp = buffer.getLongLong(); - severity = (Severity) buffer.getOctet(); - for (vector<SchemaArgument*>::const_iterator aIter = schema->arguments.begin(); - aIter != schema->arguments.end(); aIter++) { - SchemaArgument* argument = *aIter; - attributes[argument->name] = argument->decodeValue(buffer); - } -} - -const ClassKey& Event::getClassKey() const -{ - return schema->getClassKey(); -} - -string Event::getSeverityString() const -{ - switch (severity) { - case SEV_EMERGENCY : return string("EMER"); - case SEV_ALERT : return string("ALERT"); - case SEV_CRITICAL : return string("CRIT"); - case SEV_ERROR : return string("ERROR"); - case SEV_WARNING : return string("WARN"); - case SEV_NOTICE : return string("NOTIC"); - case SEV_INFO : return string("INFO"); - case SEV_DEBUG : return string("DEBUG"); - } - return string("<UNKNOWN>"); -} - -ObjectId Event::attrRef(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return ObjectId(); - Value::Ptr val = iter->second; - if (!val->isObjectId()) - return ObjectId(); - return val->asObjectId(); -} - -uint32_t Event::attrUint(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0; - Value::Ptr val = iter->second; - if (!val->isUint()) - return 0; - return val->asUint(); -} - -int32_t Event::attrInt(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0; - Value::Ptr val = iter->second; - if (!val->isInt()) - return 0; - return val->asInt(); -} - -uint64_t Event::attrUint64(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0; - Value::Ptr val = iter->second; - if (!val->isUint64()) - return 0; - return val->asUint64(); -} - -int64_t Event::attrInt64(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0; - Value::Ptr val = iter->second; - if (!val->isInt64()) - return 0; - return val->asInt64(); -} - -string Event::attrString(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return string(); - Value::Ptr val = iter->second; - if (!val->isString()) - return string(); - return val->asString(); -} - -bool Event::attrBool(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return false; - Value::Ptr val = iter->second; - if (!val->isBool()) - return false; - return val->asBool(); -} - -float Event::attrFloat(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0.0; - Value::Ptr val = iter->second; - if (!val->isFloat()) - return 0.0; - return val->asFloat(); -} - -double Event::attrDouble(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0.0; - Value::Ptr val = iter->second; - if (!val->isDouble()) - return 0.0; - return val->asDouble(); -} - -Uuid Event::attrUuid(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return Uuid(); - Value::Ptr val = iter->second; - if (!val->isUuid()) - return Uuid(); - return val->asUuid(); -} - -FieldTable Event::attrMap(const string& key) const -{ - Object::AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return FieldTable(); - Value::Ptr val = iter->second; - if (!val->isMap()) - return FieldTable(); - return val->asMap(); -} - - -std::ostream& qpid::console::operator<<(std::ostream& o, const Event& event) -{ - const ClassKey& key = event.getClassKey(); - sys::AbsTime aTime(sys::AbsTime(), sys::Duration(event.getTimestamp())); - o << aTime << " " << event.getSeverityString() << " " << - key.getPackageName() << ":" << key.getClassName() << - " broker=" << event.getBroker()->getUrl(); - - const Object::AttributeMap& attributes = event.getAttributes(); - for (Object::AttributeMap::const_iterator iter = attributes.begin(); - iter != attributes.end(); iter++) { - o << " " << iter->first << "=" << iter->second->str(); - } - return o; -} - - diff --git a/qpid/cpp/src/qpid/console/Object.cpp b/qpid/cpp/src/qpid/console/Object.cpp deleted file mode 100644 index 6570e293ab..0000000000 --- a/qpid/cpp/src/qpid/console/Object.cpp +++ /dev/null @@ -1,384 +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 "qpid/console/SessionManager.h" -#include "qpid/console/Broker.h" -#include "qpid/console/Object.h" -#include "qpid/console/Schema.h" -#include "qpid/console/ClassKey.h" -#include "qpid/console/Value.h" -#include "qpid/framing/Buffer.h" -#include "qpid/sys/Mutex.h" - -using namespace qpid::console; -using namespace qpid::sys; -using namespace qpid; -using namespace std; -using qpid::framing::Uuid; -using qpid::framing::FieldTable; - -void Object::AttributeMap::addRef(const string& key, const ObjectId& val) -{ - (*this)[key] = Value::Ptr(new RefValue(val)); -} - -void Object::AttributeMap::addUint(const string& key, uint32_t val) -{ - (*this)[key] = Value::Ptr(new UintValue(val)); -} - -void Object::AttributeMap::addInt(const string& key, int32_t val) -{ - (*this)[key] = Value::Ptr(new IntValue(val)); -} - -void Object::AttributeMap::addUint64(const string& key, uint64_t val) -{ - (*this)[key] = Value::Ptr(new Uint64Value(val)); -} - -void Object::AttributeMap::addInt64(const string& key, int64_t val) -{ - (*this)[key] = Value::Ptr(new Int64Value(val)); -} - -void Object::AttributeMap::addString(const string& key, const string& val) -{ - (*this)[key] = Value::Ptr(new StringValue(val)); -} - -void Object::AttributeMap::addBool(const string& key, bool val) -{ - (*this)[key] = Value::Ptr(new BoolValue(val)); -} - -void Object::AttributeMap::addFloat(const string& key, float val) -{ - (*this)[key] = Value::Ptr(new FloatValue(val)); -} - -void Object::AttributeMap::addDouble(const string& key, double val) -{ - (*this)[key] = Value::Ptr(new DoubleValue(val)); -} - -void Object::AttributeMap::addUuid(const string& key, const Uuid& val) -{ - (*this)[key] = Value::Ptr(new UuidValue(val)); -} - -void Object::AttributeMap::addMap(const string& key, const FieldTable& val) -{ - (*this)[key] = Value::Ptr(new MapValue(val)); -} - -Object::Object(Broker* b, SchemaClass* s, framing::Buffer& buffer, bool prop, bool stat) : - broker(b), schema(s), pendingMethod(0) -{ - currentTime = buffer.getLongLong(); - createTime = buffer.getLongLong(); - deleteTime = buffer.getLongLong(); - objectId.decode(buffer); - - if (prop) { - set<string> excludes; - parsePresenceMasks(buffer, excludes); - for (vector<SchemaProperty*>::const_iterator pIter = schema->properties.begin(); - pIter != schema->properties.end(); pIter++) { - SchemaProperty* property = *pIter; - if (excludes.count(property->name) != 0) { - attributes[property->name] = Value::Ptr(new NullValue()); - } else { - attributes[property->name] = property->decodeValue(buffer); - } - } - } - - if (stat) { - for (vector<SchemaStatistic*>::const_iterator sIter = schema->statistics.begin(); - sIter != schema->statistics.end(); sIter++) { - SchemaStatistic* statistic = *sIter; - attributes[statistic->name] = statistic->decodeValue(buffer); - } - } -} - -Object::~Object() {} - -const ClassKey& Object::getClassKey() const -{ - return schema->getClassKey(); -} - -string Object::getIndex() const -{ - string result; - - for (vector<SchemaProperty*>::const_iterator pIter = schema->properties.begin(); - pIter != schema->properties.end(); pIter++) { - SchemaProperty* property = *pIter; - if (property->isIndex) { - AttributeMap::const_iterator vIter = attributes.find(property->name); - if (vIter != attributes.end()) { - if (!result.empty()) - result += ":"; - result += vIter->second->str(); - } - } - } - return result; -} - -void Object::mergeUpdate(const Object& /*updated*/) -{ - // TODO -} - -void Object::invokeMethod(const string name, const AttributeMap& args, MethodResponse& result) -{ - for (vector<SchemaMethod*>::const_iterator iter = schema->methods.begin(); - iter != schema->methods.end(); iter++) { - if ((*iter)->name == name) { - SchemaMethod* method = *iter; - char rawbuffer[65536]; - framing::Buffer buffer(rawbuffer, 65536); - uint32_t sequence = broker->sessionManager.sequenceManager.reserve("method"); - pendingMethod = method; - broker->methodObject = this; - broker->encodeHeader(buffer, 'M', sequence); - objectId.encode(buffer); - schema->key.encode(buffer); - buffer.putShortString(name); - - for (vector<SchemaArgument*>::const_iterator aIter = method->arguments.begin(); - aIter != method->arguments.end(); aIter++) { - SchemaArgument* arg = *aIter; - if (arg->dirInput) { - AttributeMap::const_iterator attr = args.find(arg->name); - if (attr != args.end()) { - ValueFactory::encodeValue(arg->typeCode, attr->second, buffer); - } else { - // TODO Use the default value instead of throwing - throw Exception("Missing arguments in method call"); - } - } - } - - uint32_t length = buffer.getPosition(); - buffer.reset(); - stringstream routingKey; - routingKey << "agent." << objectId.getBrokerBank() << "." << objectId.getAgentBank(); - broker->connThreadBody.sendBuffer(buffer, length, "qpid.management", routingKey.str()); - - { - Mutex::ScopedLock l(broker->lock); - bool ok = true; - while (pendingMethod != 0 && ok) { - ok = broker->cond.wait(broker->lock, AbsTime(now(), broker->sessionManager.settings.methodTimeout * TIME_SEC)); - } - - if (!ok) { - result.code = 0x1001; - result.text.assign("Method call timed out"); - result.arguments.clear(); - } else { - result = methodResponse; - } - } - } - } -} - -void Object::handleMethodResp(framing::Buffer& buffer, uint32_t sequence) -{ - broker->sessionManager.sequenceManager.release(sequence); - methodResponse.code = buffer.getLong(); - buffer.getMediumString(methodResponse.text); - methodResponse.arguments.clear(); - - for (vector<SchemaArgument*>::const_iterator aIter = pendingMethod->arguments.begin(); - aIter != pendingMethod->arguments.end(); aIter++) { - SchemaArgument* arg = *aIter; - if (arg->dirOutput) { - methodResponse.arguments[arg->name] = arg->decodeValue(buffer); - } - } - - { - Mutex::ScopedLock l(broker->lock); - pendingMethod = 0; - broker->cond.notify(); - } -} - -ObjectId Object::attrRef(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return ObjectId(); - Value::Ptr val = iter->second; - if (!val->isObjectId()) - return ObjectId(); - return val->asObjectId(); -} - -uint32_t Object::attrUint(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0; - Value::Ptr val = iter->second; - if (!val->isUint()) - return 0; - return val->asUint(); -} - -int32_t Object::attrInt(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0; - Value::Ptr val = iter->second; - if (!val->isInt()) - return 0; - return val->asInt(); -} - -uint64_t Object::attrUint64(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0; - Value::Ptr val = iter->second; - if (!val->isUint64()) - return 0; - return val->asUint64(); -} - -int64_t Object::attrInt64(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0; - Value::Ptr val = iter->second; - if (!val->isInt64()) - return 0; - return val->asInt64(); -} - -string Object::attrString(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return string(); - Value::Ptr val = iter->second; - if (!val->isString()) - return string(); - return val->asString(); -} - -bool Object::attrBool(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return false; - Value::Ptr val = iter->second; - if (!val->isBool()) - return false; - return val->asBool(); -} - -float Object::attrFloat(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0.0; - Value::Ptr val = iter->second; - if (!val->isFloat()) - return 0.0; - return val->asFloat(); -} - -double Object::attrDouble(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return 0.0; - Value::Ptr val = iter->second; - if (!val->isDouble()) - return 0.0; - return val->asDouble(); -} - -Uuid Object::attrUuid(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return Uuid(); - Value::Ptr val = iter->second; - if (!val->isUuid()) - return Uuid(); - return val->asUuid(); -} - -FieldTable Object::attrMap(const string& key) const -{ - AttributeMap::const_iterator iter = attributes.find(key); - if (iter == attributes.end()) - return FieldTable(); - Value::Ptr val = iter->second; - if (!val->isMap()) - return FieldTable(); - return val->asMap(); -} - -void Object::parsePresenceMasks(framing::Buffer& buffer, set<string>& excludeList) -{ - excludeList.clear(); - uint8_t bit = 0; - uint8_t mask = 0; - - for (vector<SchemaProperty*>::const_iterator pIter = schema->properties.begin(); - pIter != schema->properties.end(); pIter++) { - SchemaProperty* property = *pIter; - if (property->isOptional) { - if (bit == 0) { - mask = buffer.getOctet(); - bit = 1; - } - if ((mask & bit) == 0) - excludeList.insert(property->name); - if (bit == 0x80) - bit = 0; - else - bit = bit << 1; - } - } -} - -ostream& qpid::console::operator<<(ostream& o, const Object& object) -{ - const ClassKey& key = object.getClassKey(); - o << key.getPackageName() << ":" << key.getClassName() << "[" << object.getObjectId() << "] " << - object.getIndex(); - return o; -} - diff --git a/qpid/cpp/src/qpid/console/ObjectId.cpp b/qpid/cpp/src/qpid/console/ObjectId.cpp deleted file mode 100644 index fbaad20d57..0000000000 --- a/qpid/cpp/src/qpid/console/ObjectId.cpp +++ /dev/null @@ -1,91 +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 "qpid/console/ObjectId.h" -#include "qpid/framing/Buffer.h" - -using namespace qpid::console; -using namespace qpid; -using namespace std; - -ObjectId::ObjectId(framing::Buffer& buffer) -{ - decode(buffer); -} - -void ObjectId::decode(framing::Buffer& buffer) -{ - first = buffer.getLongLong(); - second = buffer.getLongLong(); -} - -void ObjectId::encode(framing::Buffer& buffer) -{ - buffer.putLongLong(first); - buffer.putLongLong(second); -} - -bool ObjectId::operator==(const ObjectId& other) const -{ - return second == other.second && first == other.first; -} - -bool ObjectId::operator!=(const ObjectId& other) const -{ - return !(*this == other); -} - -bool ObjectId::operator<(const ObjectId& other) const -{ - if (first < other.first) - return true; - if (first > other.first) - return false; - return second < other.second; -} - -bool ObjectId::operator>(const ObjectId& other) const -{ - if (first > other.first) - return true; - if (first < other.first) - return false; - return second > other.second; -} - -bool ObjectId::operator<=(const ObjectId& other) const -{ - return !(*this > other); -} - -bool ObjectId::operator>=(const ObjectId& other) const -{ - return !(*this < other); -} - -ostream& qpid::console::operator<<(ostream& o, const ObjectId& id) -{ - o << (int) id.getFlags() << "-" << id.getSequence() << "-" << id.getBrokerBank() << "-" << - id.getAgentBank() << "-" << id.getObject(); - return o; -} - - diff --git a/qpid/cpp/src/qpid/console/Schema.cpp b/qpid/cpp/src/qpid/console/Schema.cpp deleted file mode 100644 index a3dbd91201..0000000000 --- a/qpid/cpp/src/qpid/console/Schema.cpp +++ /dev/null @@ -1,165 +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 "qpid/console/Schema.h" -#include "qpid/console/Value.h" -#include "qpid/framing/FieldTable.h" - -using namespace qpid::console; -using namespace qpid; -using std::string; -using std::vector; - -SchemaArgument::SchemaArgument(framing::Buffer& buffer, bool forMethod) -{ - framing::FieldTable map; - map.decode(buffer); - - name = map.getAsString("name"); - typeCode = map.getAsInt("type"); - unit = map.getAsString("unit"); - min = map.getAsInt("min"); - max = map.getAsInt("max"); - maxLen = map.getAsInt("maxlen"); - desc = map.getAsString("desc"); - - dirInput = false; - dirOutput = false; - if (forMethod) { - string dir(map.getAsString("dir")); - if (dir.find('I') != dir.npos || dir.find('i') != dir.npos) - dirInput = true; - if (dir.find('O') != dir.npos || dir.find('o') != dir.npos) - dirOutput = true; - } -} - -Value::Ptr SchemaArgument::decodeValue(framing::Buffer& buffer) -{ - return ValueFactory::newValue(typeCode, buffer); -} - -SchemaProperty::SchemaProperty(framing::Buffer& buffer) -{ - framing::FieldTable map; - map.decode(buffer); - - name = map.getAsString("name"); - typeCode = map.getAsInt("type"); - accessCode = map.getAsInt("access"); - isIndex = map.getAsInt("index") != 0; - isOptional = map.getAsInt("optional") != 0; - unit = map.getAsString("unit"); - min = map.getAsInt("min"); - max = map.getAsInt("max"); - maxLen = map.getAsInt("maxlen"); - desc = map.getAsString("desc"); -} - -Value::Ptr SchemaProperty::decodeValue(framing::Buffer& buffer) -{ - return ValueFactory::newValue(typeCode, buffer); -} - -SchemaStatistic::SchemaStatistic(framing::Buffer& buffer) -{ - framing::FieldTable map; - map.decode(buffer); - - name = map.getAsString("name"); - typeCode = map.getAsInt("type"); - unit = map.getAsString("unit"); - desc = map.getAsString("desc"); -} - -Value::Ptr SchemaStatistic::decodeValue(framing::Buffer& buffer) -{ - return ValueFactory::newValue(typeCode, buffer); -} - -SchemaMethod::SchemaMethod(framing::Buffer& buffer) -{ - framing::FieldTable map; - map.decode(buffer); - - name = map.getAsString("name"); - desc = map.getAsString("desc"); - int argCount = map.getAsInt("argCount"); - - for (int i = 0; i < argCount; i++) - arguments.push_back(new SchemaArgument(buffer, true)); -} - -SchemaMethod::~SchemaMethod() -{ - for (vector<SchemaArgument*>::iterator iter = arguments.begin(); - iter != arguments.end(); iter++) - delete *iter; -} - -SchemaClass::SchemaClass(const uint8_t _kind, const ClassKey& _key, framing::Buffer& buffer) : - kind(_kind), key(_key) -{ - if (kind == KIND_TABLE) { - uint8_t hasSupertype = 0; //buffer.getOctet(); - uint16_t propCount = buffer.getShort(); - uint16_t statCount = buffer.getShort(); - uint16_t methodCount = buffer.getShort(); - - if (hasSupertype) { - string unused; - buffer.getShortString(unused); - buffer.getShortString(unused); - buffer.getLongLong(); - buffer.getLongLong(); - } - - for (uint16_t idx = 0; idx < propCount; idx++) - properties.push_back(new SchemaProperty(buffer)); - for (uint16_t idx = 0; idx < statCount; idx++) - statistics.push_back(new SchemaStatistic(buffer)); - for (uint16_t idx = 0; idx < methodCount; idx++) - methods.push_back(new SchemaMethod(buffer)); - - } else if (kind == KIND_EVENT) { - uint16_t argCount = buffer.getShort(); - - for (uint16_t idx = 0; idx < argCount; idx++) - arguments.push_back(new SchemaArgument(buffer)); - } -} - -SchemaClass::~SchemaClass() -{ - for (vector<SchemaProperty*>::iterator iter = properties.begin(); - iter != properties.end(); iter++) - delete *iter; - for (vector<SchemaStatistic*>::iterator iter = statistics.begin(); - iter != statistics.end(); iter++) - delete *iter; - for (vector<SchemaMethod*>::iterator iter = methods.begin(); - iter != methods.end(); iter++) - delete *iter; - for (vector<SchemaArgument*>::iterator iter = arguments.begin(); - iter != arguments.end(); iter++) - delete *iter; -} - diff --git a/qpid/cpp/src/qpid/console/SessionManager.cpp b/qpid/cpp/src/qpid/console/SessionManager.cpp deleted file mode 100644 index 910ae22be8..0000000000 --- a/qpid/cpp/src/qpid/console/SessionManager.cpp +++ /dev/null @@ -1,516 +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 "qpid/console/SessionManager.h" -#include "qpid/console/Schema.h" -#include "qpid/console/Agent.h" -#include "qpid/console/ConsoleListener.h" -#include "qpid/log/Statement.h" -#include "qpid/sys/Time.h" -#include "qpid/framing/Buffer.h" -#include "qpid/framing/Uuid.h" -#include "qpid/framing/FieldTable.h" - -using namespace qpid::console; -using namespace qpid::sys; -using namespace qpid; -using namespace std; -using qpid::framing::Buffer; -using qpid::framing::FieldTable; - -SessionManager::SessionManager(ConsoleListener* _listener, Settings _settings) : - listener(_listener), settings(_settings) -{ - bindingKeys(); -} - -SessionManager::~SessionManager() -{ - for (vector<Broker*>::iterator iter = brokers.begin(); - iter != brokers.end(); iter++) - delete *iter; - - for (map<string, Package*>::iterator iter = packages.begin(); - iter != packages.end(); iter++) { - for (Package::ClassMap::iterator citer = iter->second->classes.begin(); - citer != iter->second->classes.end(); - citer++) - delete citer->second; - delete iter->second; - } -} - -Broker* SessionManager::addBroker(client::ConnectionSettings& settings) -{ - Broker* broker(new Broker(*this, settings)); - { - Mutex::ScopedLock l(brokerListLock); - brokers.push_back(broker); - } - return broker; -} - -void SessionManager::delBroker(Broker* broker) -{ - Mutex::ScopedLock l(brokerListLock); - for (vector<Broker*>::iterator iter = brokers.begin(); - iter != brokers.end(); iter++) - if (*iter == broker) { - brokers.erase(iter); - delete broker; - return; - } -} - -void SessionManager::getPackages(NameVector& packageNames) -{ - allBrokersStable(); - packageNames.clear(); - { - Mutex::ScopedLock l(lock); - for (map<string, Package*>::iterator iter = packages.begin(); - iter != packages.end(); iter++) - packageNames.push_back(iter->first); - } -} - -void SessionManager::getClasses(KeyVector& classKeys, const std::string& packageName) -{ - allBrokersStable(); - classKeys.clear(); - map<string, Package*>::iterator iter = packages.find(packageName); - if (iter == packages.end()) - return; - - Package& package = *(iter->second); - for (Package::ClassMap::const_iterator piter = package.classes.begin(); - piter != package.classes.end(); piter++) { - ClassKey key(piter->second->getClassKey()); - classKeys.push_back(key); - } -} - -SchemaClass& SessionManager::getSchema(const ClassKey& classKey) -{ - allBrokersStable(); - map<string, Package*>::iterator iter = packages.find(classKey.getPackageName()); - if (iter == packages.end()) - throw Exception("Unknown package"); - - Package& package = *(iter->second); - Package::NameHash key(classKey.getClassName(), classKey.getHash()); - Package::ClassMap::iterator cIter = package.classes.find(key); - if (cIter == package.classes.end()) - throw Exception("Unknown class"); - - return *(cIter->second); -} - -void SessionManager::bindPackage(const std::string& packageName) -{ - stringstream key; - key << "console.obj.*.*." << packageName << ".#"; - bindingKeyList.push_back(key.str()); - for (vector<Broker*>::iterator iter = brokers.begin(); iter != brokers.end(); iter++) - (*iter)->addBinding(key.str()); -} - -void SessionManager::bindClass(const ClassKey& classKey) -{ - bindClass(classKey.getPackageName(), classKey.getClassName()); -} - -void SessionManager::bindClass(const std::string& packageName, const std::string& className) -{ - stringstream key; - key << "console.obj.*.*." << packageName << "." << className << ".#"; - bindingKeyList.push_back(key.str()); - for (vector<Broker*>::iterator iter = brokers.begin(); - iter != brokers.end(); iter++) - (*iter)->addBinding(key.str()); -} - - -void SessionManager::bindEvent(const ClassKey& classKey) -{ - bindEvent(classKey.getPackageName(), classKey.getClassName()); -} - - -void SessionManager::bindEvent(const std::string& packageName, const std::string& eventName) -{ - if (!settings.userBindings) throw Exception("Session not configured for userBindings."); - if (settings.rcvEvents) throw Exception("Session already configured to receive all events."); - - stringstream key; - key << "console.event.*.*." << packageName; - if (eventName.length()) { - key << "." << eventName << ".#"; - } else { - key << ".#"; - } - - bindingKeyList.push_back(key.str()); - for (vector<Broker*>::iterator iter = brokers.begin(); - iter != brokers.end(); iter++) - (*iter)->addBinding(key.str()); -} - - -void SessionManager::getAgents(Agent::Vector& agents, Broker* broker) -{ - agents.clear(); - if (broker != 0) { - broker->appendAgents(agents); - } else { - for (vector<Broker*>::iterator iter = brokers.begin(); iter != brokers.end(); iter++) { - (*iter)->appendAgents(agents); - } - } -} - -void SessionManager::getObjects(Object::Vector& objects, const std::string& className, - Broker* _broker, Agent* _agent) -{ - Agent::Vector agentList; - - if (_agent != 0) { - agentList.push_back(_agent); - _agent->getBroker()->waitForStable(); - } else { - if (_broker != 0) { - _broker->appendAgents(agentList); - _broker->waitForStable(); - } else { - allBrokersStable(); - Mutex::ScopedLock _lock(brokerListLock); - for (vector<Broker*>::iterator iter = brokers.begin(); iter != brokers.end(); iter++) { - (*iter)->appendAgents(agentList); - } - } - } - - FieldTable ft; - uint32_t sequence; - ft.setString("_class", className); - - getResult.clear(); - syncSequenceList.clear(); - error = string(); - - if (agentList.empty()) { - objects = getResult; - return; - } - - for (Agent::Vector::iterator iter = agentList.begin(); iter != agentList.end(); iter++) { - Agent* agent = *iter; - char rawbuffer[512]; - Buffer buffer(rawbuffer, 512); - stringstream routingKey; - routingKey << "agent." << agent->getBrokerBank() << "." << agent->getAgentBank(); - { - Mutex::ScopedLock _lock(lock); - sequence = sequenceManager.reserve("multiget"); - syncSequenceList.insert(sequence); - } - agent->getBroker()->encodeHeader(buffer, 'G', sequence); - ft.encode(buffer); - uint32_t length = buffer.getPosition(); - buffer.reset(); - agent->getBroker()->connThreadBody.sendBuffer(buffer, length, "qpid.management", routingKey.str()); - } - - { - Mutex::ScopedLock _lock(lock); - sys::AbsTime startTime = sys::now(); - while (!syncSequenceList.empty() && error.empty()) { - cv.wait(lock, AbsTime(now(), settings.getTimeout * TIME_SEC)); - sys::AbsTime currTime = sys::now(); - if (sys::Duration(startTime, currTime) > settings.getTimeout * TIME_SEC) - break; - } - } - - objects = getResult; -} - -void SessionManager::bindingKeys() -{ - bindingKeyList.push_back("schema.#"); - if (settings.rcvObjects && settings.rcvEvents && settings.rcvHeartbeats && !settings.userBindings) { - bindingKeyList.push_back("console.#"); - } else { - if (settings.rcvObjects && !settings.userBindings) - bindingKeyList.push_back("console.obj.#"); - else - bindingKeyList.push_back("console.obj.*.*.org.apache.qpid.broker.agent"); - if (settings.rcvEvents) - bindingKeyList.push_back("console.event.#"); - if (settings.rcvHeartbeats) - bindingKeyList.push_back("console.heartbeat"); - } -} - -void SessionManager::allBrokersStable() -{ - Mutex::ScopedLock l(brokerListLock); - for (vector<Broker*>::iterator iter = brokers.begin(); - iter != brokers.end(); iter++) - if ((*iter)->isConnected()) - (*iter)->waitForStable(); -} - -void SessionManager::startProtocol(Broker* broker) -{ - char rawbuffer[512]; - Buffer buffer(rawbuffer, 512); - - broker->encodeHeader(buffer, 'B'); - uint32_t length = 512 - buffer.available(); - buffer.reset(); - broker->connThreadBody.sendBuffer(buffer, length); -} - - -void SessionManager::handleBrokerResp(Broker* broker, Buffer& inBuffer, uint32_t) -{ - framing::Uuid brokerId; - - brokerId.decode(inBuffer); - broker->setBrokerId(brokerId); - - char rawbuffer[512]; - Buffer buffer(rawbuffer, 512); - - uint32_t sequence = sequenceManager.reserve("startup"); - broker->encodeHeader(buffer, 'P', sequence); - uint32_t length = 512 - buffer.available(); - buffer.reset(); - broker->connThreadBody.sendBuffer(buffer, length); - - if (listener != 0) { - listener->brokerInfo(*broker); - } -} - -void SessionManager::handlePackageInd(Broker* broker, Buffer& inBuffer, uint32_t) -{ - string packageName; - inBuffer.getShortString(packageName); - - { - Mutex::ScopedLock l(lock); - map<string, Package*>::iterator iter = packages.find(packageName); - if (iter == packages.end()) { - packages[packageName] = new Package(packageName); - if (listener != 0) - listener->newPackage(packageName); - } - } - - broker->incOutstanding(); - char rawbuffer[512]; - Buffer buffer(rawbuffer, 512); - - uint32_t sequence = sequenceManager.reserve("startup"); - broker->encodeHeader(buffer, 'Q', sequence); - buffer.putShortString(packageName); - uint32_t length = 512 - buffer.available(); - buffer.reset(); - broker->connThreadBody.sendBuffer(buffer, length); -} - -void SessionManager::handleCommandComplete(Broker* broker, Buffer& inBuffer, uint32_t sequence) -{ - Mutex::ScopedLock l(lock); - uint32_t resultCode = inBuffer.getLong(); - string resultText; - inBuffer.getShortString(resultText); - string context = sequenceManager.release(sequence); - if (resultCode != 0) - QPID_LOG(debug, "Received error in completion: " << resultCode << " " << resultText); - if (context == "startup") { - broker->decOutstanding(); - } else if (context == "multiget") { - if (syncSequenceList.count(sequence) == 1) { - syncSequenceList.erase(sequence); - if (syncSequenceList.empty()) { - cv.notify(); - } - } - } - // TODO: Other context cases -} - -void SessionManager::handleClassInd(Broker* broker, Buffer& inBuffer, uint32_t) -{ - string packageName; - string className; - uint8_t hash[16]; - - /*kind*/ (void) inBuffer.getOctet(); - inBuffer.getShortString(packageName); - inBuffer.getShortString(className); - inBuffer.getBin128(hash); - - { - Mutex::ScopedLock l(lock); - map<string, Package*>::iterator pIter = packages.find(packageName); - if (pIter == packages.end() || pIter->second->getClass(className, hash)) - return; - } - - broker->incOutstanding(); - char rawbuffer[512]; - Buffer buffer(rawbuffer, 512); - - uint32_t sequence = sequenceManager.reserve("startup"); - broker->encodeHeader(buffer, 'S', sequence); - buffer.putShortString(packageName); - buffer.putShortString(className); - buffer.putBin128(hash); - uint32_t length = 512 - buffer.available(); - buffer.reset(); - broker->connThreadBody.sendBuffer(buffer, length); -} - -void SessionManager::handleMethodResp(Broker* broker, Buffer& buffer, uint32_t sequence) -{ - if (broker->methodObject) { - broker->methodObject->handleMethodResp(buffer, sequence); - } -} - -void SessionManager::handleHeartbeatInd(Broker* /*broker*/, Buffer& /*inBuffer*/, uint32_t /*sequence*/) -{ -} - -void SessionManager::handleEventInd(Broker* broker, Buffer& buffer, uint32_t /*sequence*/) -{ - string packageName; - string className; - uint8_t hash[16]; - SchemaClass* schemaClass; - - buffer.getShortString(packageName); - buffer.getShortString(className); - buffer.getBin128(hash); - - { - Mutex::ScopedLock l(lock); - map<string, Package*>::iterator pIter = packages.find(packageName); - if (pIter == packages.end()) - return; - schemaClass = pIter->second->getClass(className, hash); - if (schemaClass == 0) - return; - } - - Event event(broker, schemaClass, buffer); - - if (listener) - listener->event(event); -} - -void SessionManager::handleSchemaResp(Broker* broker, Buffer& inBuffer, uint32_t sequence) -{ - uint8_t kind; - string packageName; - string className; - uint8_t hash[16]; - - kind = inBuffer.getOctet(); - inBuffer.getShortString(packageName); - inBuffer.getShortString(className); - inBuffer.getBin128(hash); - - { - Mutex::ScopedLock l(lock); - map<string, Package*>::iterator pIter = packages.find(packageName); - if (pIter != packages.end() && !pIter->second->getClass(className, hash)) { - ClassKey key(packageName, className, hash); - SchemaClass* schemaClass(new SchemaClass(kind, key, inBuffer)); - pIter->second->addClass(className, hash, schemaClass); - if (listener != 0) { - listener->newClass(schemaClass->getClassKey()); - } - } - } - - sequenceManager.release(sequence); - broker->decOutstanding(); -} - -void SessionManager::handleContentInd(Broker* broker, Buffer& buffer, uint32_t sequence, bool prop, bool stat) -{ - string packageName; - string className; - uint8_t hash[16]; - SchemaClass* schemaClass; - - buffer.getShortString(packageName); - buffer.getShortString(className); - buffer.getBin128(hash); - - { - Mutex::ScopedLock l(lock); - map<string, Package*>::iterator pIter = packages.find(packageName); - if (pIter == packages.end()) - return; - schemaClass = pIter->second->getClass(className, hash); - if (schemaClass == 0) - return; - } - - Object object(broker, schemaClass, buffer, prop, stat); - - if (prop && className == "agent" && packageName == "org.apache.qpid.broker") - broker->updateAgent(object); - - { - Mutex::ScopedLock l(lock); - if (syncSequenceList.count(sequence) == 1) { - if (!object.isDeleted()) - getResult.push_back(object); - return; - } - } - - if (listener) { - if (prop) - listener->objectProps(*broker, object); - if (stat) - listener->objectStats(*broker, object); - } -} - -void SessionManager::handleBrokerConnect(Broker* broker) -{ - if (listener != 0) - listener->brokerConnected(*broker); -} - -void SessionManager::handleBrokerDisconnect(Broker* broker) -{ - if (listener != 0) - listener->brokerDisconnected(*broker); -} - diff --git a/qpid/cpp/src/qpid/console/Value.cpp b/qpid/cpp/src/qpid/console/Value.cpp deleted file mode 100644 index 47c6a4ce57..0000000000 --- a/qpid/cpp/src/qpid/console/Value.cpp +++ /dev/null @@ -1,171 +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 "qpid/console/Value.h" -#include "qpid/framing/Buffer.h" - -#include <sstream> - -using namespace qpid; -using namespace qpid::console; -using namespace std; - -string NullValue::str() const -{ - return "<Null>"; -} - -RefValue::RefValue(framing::Buffer& buffer) -{ - uint64_t first = buffer.getLongLong(); - uint64_t second = buffer.getLongLong(); - value.setValue(first, second); -} - -string RefValue::str() const -{ - stringstream s; - s << value; - return s.str(); -} - -string UintValue::str() const -{ - stringstream s; - s << value; - return s.str(); -} - -string IntValue::str() const -{ - stringstream s; - s << value; - return s.str(); -} - -string Uint64Value::str() const -{ - stringstream s; - s << value; - return s.str(); -} - -string Int64Value::str() const -{ - stringstream s; - s << value; - return s.str(); -} - -StringValue::StringValue(framing::Buffer& buffer, int tc) -{ - if (tc == 6) - buffer.getShortString(value); - else - buffer.getMediumString(value); -} - -string BoolValue::str() const -{ - return value ? "T" : "F"; -} - -string FloatValue::str() const -{ - stringstream s; - s << value; - return s.str(); -} - -string DoubleValue::str() const -{ - stringstream s; - s << value; - return s.str(); -} - -UuidValue::UuidValue(framing::Buffer& buffer) -{ - value.decode(buffer); -} - -string MapValue::str() const -{ - stringstream s; - s << value; - return s.str(); -} - -MapValue::MapValue(framing::Buffer& buffer) -{ - value.decode(buffer); -} - - -Value::Ptr ValueFactory::newValue(int typeCode, framing::Buffer& buffer) -{ - switch (typeCode) { - case 1: return Value::Ptr(new UintValue(buffer.getOctet())); // U8 - case 2: return Value::Ptr(new UintValue(buffer.getShort())); // U16 - case 3: return Value::Ptr(new UintValue(buffer.getLong())); // U32 - case 4: return Value::Ptr(new Uint64Value(buffer.getLongLong())); // U64 - case 6: return Value::Ptr(new StringValue(buffer, 6)); // SSTR - case 7: return Value::Ptr(new StringValue(buffer, 7)); // LSTR - case 8: return Value::Ptr(new Int64Value(buffer.getLongLong())); // ABSTIME - case 9: return Value::Ptr(new Uint64Value(buffer.getLongLong())); // DELTATIME - case 10: return Value::Ptr(new RefValue(buffer)); // REF - case 11: return Value::Ptr(new BoolValue(buffer.getOctet())); // BOOL - case 12: return Value::Ptr(new FloatValue(buffer.getFloat())); // FLOAT - case 13: return Value::Ptr(new DoubleValue(buffer.getDouble())); // DOUBLE - case 14: return Value::Ptr(new UuidValue(buffer)); // UUID - case 15: return Value::Ptr(new MapValue(buffer)); // MAP - case 16: return Value::Ptr(new IntValue(buffer.getOctet())); // S8 - case 17: return Value::Ptr(new IntValue(buffer.getShort())); // S16 - case 18: return Value::Ptr(new IntValue(buffer.getLong())); // S32 - case 19: return Value::Ptr(new Int64Value(buffer.getLongLong())); // S64 - } - - return Value::Ptr(); -} - -void ValueFactory::encodeValue(int typeCode, Value::Ptr value, framing::Buffer& buffer) -{ - switch (typeCode) { - case 1: buffer.putOctet(value->asUint()); return; // U8 - case 2: buffer.putShort(value->asUint()); return; // U16 - case 3: buffer.putLong(value->asUint()); return; // U32 - case 4: buffer.putLongLong(value->asUint64()); return; // U64 - case 6: buffer.putShortString(value->asString()); return; // SSTR - case 7: buffer.putMediumString(value->asString()); return; // LSTR - case 8: buffer.putLongLong(value->asInt64()); return; // ABSTIME - case 9: buffer.putLongLong(value->asUint64()); return; // DELTATIME - case 10: value->asObjectId().encode(buffer); return; // REF - case 11: buffer.putOctet(value->asBool() ? 1 : 0); return; // BOOL - case 12: buffer.putFloat(value->asFloat()); return; // FLOAT - case 13: buffer.putDouble(value->asDouble()); return; // DOUBLE - case 14: value->asUuid().encode(buffer); return; // UUID - case 15: value->asMap().encode(buffer); return; // MAP - case 16: buffer.putOctet(value->asInt()); return; // S8 - case 17: buffer.putShort(value->asInt()); return; // S16 - case 18: buffer.putLong(value->asInt()); return; // S32 - case 19: buffer.putLongLong(value->asInt64()); return; // S64 - } -} diff --git a/qpid/cpp/src/qpid/framing/Array.h b/qpid/cpp/src/qpid/framing/Array.h new file mode 100644 index 0000000000..6254f6271a --- /dev/null +++ b/qpid/cpp/src/qpid/framing/Array.h @@ -0,0 +1,99 @@ +#ifndef QPID_FRAMING_ARRAY_H +#define QPID_FRAMING_ARRAY_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/framing/amqp_types.h" +#include "qpid/framing/TypeCode.h" + +#include <boost/shared_ptr.hpp> + +#include <iostream> +#include <vector> + +#include "qpid/CommonImportExport.h" + +namespace qpid { +namespace framing { + +class Buffer; +class FieldValue; + +class QPID_COMMON_CLASS_EXTERN Array +{ + public: + typedef boost::shared_ptr<FieldValue> ValuePtr; + typedef std::vector<ValuePtr> ValueVector; + typedef ValueVector::const_iterator const_iterator; + typedef ValueVector::iterator iterator; + + QPID_COMMON_EXTERN uint32_t encodedSize() const; + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN void decode(Buffer& buffer); + + QPID_COMMON_EXTERN int count() const; + QPID_COMMON_EXTERN bool operator==(const Array& other) const; + + QPID_COMMON_EXTERN Array(); + QPID_COMMON_EXTERN Array(TypeCode type); + QPID_COMMON_EXTERN Array(uint8_t type); + //creates a longstr array + QPID_COMMON_EXTERN Array(const std::vector<std::string>& in); + + QPID_COMMON_INLINE_EXTERN TypeCode getType() const { return type; } + + // std collection interface. + QPID_COMMON_INLINE_EXTERN const_iterator begin() const { return values.begin(); } + QPID_COMMON_INLINE_EXTERN const_iterator end() const { return values.end(); } + QPID_COMMON_INLINE_EXTERN iterator begin() { return values.begin(); } + QPID_COMMON_INLINE_EXTERN iterator end(){ return values.end(); } + + QPID_COMMON_INLINE_EXTERN ValuePtr front() const { return values.front(); } + QPID_COMMON_INLINE_EXTERN ValuePtr back() const { return values.back(); } + QPID_COMMON_INLINE_EXTERN size_t size() const { return values.size(); } + + QPID_COMMON_EXTERN void insert(iterator i, ValuePtr value); + QPID_COMMON_INLINE_EXTERN void erase(iterator i) { values.erase(i); } + QPID_COMMON_INLINE_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); } + QPID_COMMON_INLINE_EXTERN void pop_back() { values.pop_back(); } + + // Non-std interface + QPID_COMMON_INLINE_EXTERN void add(ValuePtr value) { push_back(value); } + + // For use in standard algorithms + template <typename R, typename V> + static R get(const V& v) { + return v->template get<R>(); + } + + private: + TypeCode type; + ValueVector values; + + friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& out, const Array& body); +}; + +} +} + + +#endif diff --git a/qpid/cpp/src/qpid/framing/Buffer.cpp b/qpid/cpp/src/qpid/framing/Buffer.cpp index ef977cc8a3..1c4caef046 100644 --- a/qpid/cpp/src/qpid/framing/Buffer.cpp +++ b/qpid/cpp/src/qpid/framing/Buffer.cpp @@ -182,27 +182,27 @@ double Buffer::getDouble(){ } template <> -uint64_t Buffer::getUInt<1>() { +QPID_COMMON_EXTERN uint64_t Buffer::getUInt<1>() { return getOctet(); } template <> -uint64_t Buffer::getUInt<2>() { +QPID_COMMON_EXTERN uint64_t Buffer::getUInt<2>() { return getShort(); } template <> -uint64_t Buffer::getUInt<4>() { +QPID_COMMON_EXTERN uint64_t Buffer::getUInt<4>() { return getLong(); } template <> -uint64_t Buffer::getUInt<8>() { +QPID_COMMON_EXTERN uint64_t Buffer::getUInt<8>() { return getLongLong(); } template <> -void Buffer::putUInt<1>(uint64_t i) { +QPID_COMMON_EXTERN void Buffer::putUInt<1>(uint64_t i) { if (std::numeric_limits<uint8_t>::min() <= i && i <= std::numeric_limits<uint8_t>::max()) { putOctet(i); return; @@ -211,7 +211,7 @@ void Buffer::putUInt<1>(uint64_t i) { } template <> -void Buffer::putUInt<2>(uint64_t i) { +QPID_COMMON_EXTERN void Buffer::putUInt<2>(uint64_t i) { if (std::numeric_limits<uint16_t>::min() <= i && i <= std::numeric_limits<uint16_t>::max()) { putShort(i); return; @@ -220,7 +220,7 @@ void Buffer::putUInt<2>(uint64_t i) { } template <> -void Buffer::putUInt<4>(uint64_t i) { +QPID_COMMON_EXTERN void Buffer::putUInt<4>(uint64_t i) { if (std::numeric_limits<uint32_t>::min() <= i && i <= std::numeric_limits<uint32_t>::max()) { putLong(i); return; @@ -229,7 +229,7 @@ void Buffer::putUInt<4>(uint64_t i) { } template <> -void Buffer::putUInt<8>(uint64_t i) { +QPID_COMMON_EXTERN void Buffer::putUInt<8>(uint64_t i) { putLongLong(i); } diff --git a/qpid/cpp/src/qpid/framing/Buffer.h b/qpid/cpp/src/qpid/framing/Buffer.h new file mode 100644 index 0000000000..166b524e3c --- /dev/null +++ b/qpid/cpp/src/qpid/framing/Buffer.h @@ -0,0 +1,115 @@ +#ifndef QPID_FRAMING_BUFFER_H +#define QPID_FRAMING_BUFFER_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/Exception.h" +#include "qpid/CommonImportExport.h" +#include "qpid/sys/IntegerTypes.h" + +#include <string> + +namespace qpid { +namespace framing { + +struct QPID_COMMON_CLASS_EXTERN OutOfBounds : qpid::Exception { + OutOfBounds() : qpid::Exception(std::string("Out of Bounds")) {} +}; + +class Content; +class FieldTable; + +class QPID_COMMON_CLASS_EXTERN Buffer +{ + uint32_t size; + char* data; + uint32_t position; + + public: + void checkAvailable(size_t count) { if (count > size - position) throw OutOfBounds(); } + + QPID_COMMON_EXTERN Buffer(char* data=0, uint32_t size=0); + + QPID_COMMON_EXTERN void reset(); + + QPID_COMMON_INLINE_EXTERN uint32_t available() const{ return size - position; } + QPID_COMMON_INLINE_EXTERN uint32_t getSize() const { return size; } + QPID_COMMON_INLINE_EXTERN uint32_t getPosition() const { return position; } + QPID_COMMON_INLINE_EXTERN void setPosition(uint32_t p) { position = p; } + QPID_COMMON_INLINE_EXTERN const char * getPointer() const { return data; } + QPID_COMMON_INLINE_EXTERN char* getPointer() { return data; } + + QPID_COMMON_EXTERN void putOctet(uint8_t i); + QPID_COMMON_EXTERN void putShort(uint16_t i); + QPID_COMMON_EXTERN void putLong(uint32_t i); + QPID_COMMON_EXTERN void putLongLong(uint64_t i); + QPID_COMMON_EXTERN void putInt8(int8_t i); + QPID_COMMON_EXTERN void putInt16(int16_t i); + QPID_COMMON_EXTERN void putInt32(int32_t i); + QPID_COMMON_EXTERN void putInt64(int64_t i); + QPID_COMMON_EXTERN void putFloat(float f); + QPID_COMMON_EXTERN void putDouble(double f); + QPID_COMMON_EXTERN void putBin128(const uint8_t* b); + + QPID_COMMON_EXTERN uint8_t getOctet(); + QPID_COMMON_EXTERN uint16_t getShort(); + QPID_COMMON_EXTERN uint32_t getLong(); + QPID_COMMON_EXTERN uint64_t getLongLong(); + QPID_COMMON_EXTERN int8_t getInt8(); + QPID_COMMON_EXTERN int16_t getInt16(); + QPID_COMMON_EXTERN int32_t getInt32(); + QPID_COMMON_EXTERN int64_t getInt64(); + QPID_COMMON_EXTERN float getFloat(); + QPID_COMMON_EXTERN double getDouble(); + + template <int n> + QPID_COMMON_EXTERN uint64_t getUInt(); + + template <int n> + QPID_COMMON_EXTERN void putUInt(uint64_t); + + QPID_COMMON_EXTERN void putShortString(const std::string& s); + QPID_COMMON_EXTERN void putMediumString(const std::string& s); + QPID_COMMON_EXTERN void putLongString(const std::string& s); + QPID_COMMON_EXTERN void getShortString(std::string& s); + QPID_COMMON_EXTERN void getMediumString(std::string& s); + QPID_COMMON_EXTERN void getLongString(std::string& s); + QPID_COMMON_EXTERN void getBin128(uint8_t* b); + + QPID_COMMON_EXTERN void putRawData(const std::string& s); + QPID_COMMON_EXTERN void getRawData(std::string& s, uint32_t size); + + QPID_COMMON_EXTERN void putRawData(const uint8_t* data, size_t size); + QPID_COMMON_EXTERN void getRawData(uint8_t* data, size_t size); + + template <class T> void put(const T& data) { data.encode(*this); } + template <class T> void get(T& data) { data.decode(*this); } + + QPID_COMMON_EXTERN void dump(std::ostream&) const; +}; + +std::ostream& operator<<(std::ostream&, const Buffer&); + +}} // namespace qpid::framing + + +#endif diff --git a/qpid/cpp/src/qpid/framing/FieldTable.h b/qpid/cpp/src/qpid/framing/FieldTable.h new file mode 100644 index 0000000000..1986a72d10 --- /dev/null +++ b/qpid/cpp/src/qpid/framing/FieldTable.h @@ -0,0 +1,139 @@ +#ifndef _FieldTable_ +#define _FieldTable_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/framing/amqp_types.h" +#include "qpid/sys/Mutex.h" + +#include <boost/shared_ptr.hpp> +#include <boost/shared_array.hpp> + +#include <iosfwd> +#include <map> + +#include "qpid/CommonImportExport.h" + +namespace qpid { + /** + * The framing namespace contains classes that are used to create, + * send and receive the basic packets from which AMQP is built. + */ +namespace framing { + +class Array; +class FieldValue; +class Buffer; + +/** + * A set of name-value pairs. (See the AMQP spec for more details on + * AMQP field tables). + * + * \ingroup clientapi + */ +class FieldTable +{ + public: + typedef boost::shared_ptr<FieldValue> ValuePtr; + typedef std::map<std::string, ValuePtr> ValueMap; + typedef ValueMap::iterator iterator; + typedef ValueMap::const_iterator const_iterator; + typedef ValueMap::const_reference const_reference; + typedef ValueMap::reference reference; + typedef ValueMap::value_type value_type; + + QPID_COMMON_EXTERN FieldTable(); + QPID_COMMON_EXTERN FieldTable(const FieldTable&); + QPID_COMMON_EXTERN FieldTable& operator=(const FieldTable&); + // Compiler default destructor fine + QPID_COMMON_EXTERN uint32_t encodedSize() const; + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN void decode(Buffer& buffer); + + QPID_COMMON_EXTERN int count() const; + QPID_COMMON_INLINE_EXTERN size_t size() const { return values.size(); } + QPID_COMMON_INLINE_EXTERN bool empty() { return size() == 0; } + QPID_COMMON_EXTERN void set(const std::string& name, const ValuePtr& value); + QPID_COMMON_EXTERN ValuePtr get(const std::string& name) const; + QPID_COMMON_INLINE_EXTERN bool isSet(const std::string& name) const { return get(name).get() != 0; } + + QPID_COMMON_EXTERN void setString(const std::string& name, const std::string& value); + QPID_COMMON_EXTERN void setInt(const std::string& name, const int value); + QPID_COMMON_EXTERN void setInt64(const std::string& name, const int64_t value); + QPID_COMMON_EXTERN void setTimestamp(const std::string& name, const uint64_t value); + QPID_COMMON_EXTERN void setUInt64(const std::string& name, const uint64_t value); + QPID_COMMON_EXTERN void setTable(const std::string& name, const FieldTable& value); + QPID_COMMON_EXTERN void setArray(const std::string& name, const Array& value); + QPID_COMMON_EXTERN void setFloat(const std::string& name, const float value); + QPID_COMMON_EXTERN void setDouble(const std::string& name, const double value); + //void setDecimal(string& name, xxx& value); + + QPID_COMMON_EXTERN int getAsInt(const std::string& name) const; + QPID_COMMON_EXTERN uint64_t getAsUInt64(const std::string& name) const; + QPID_COMMON_EXTERN int64_t getAsInt64(const std::string& name) const; + QPID_COMMON_EXTERN std::string getAsString(const std::string& name) const; + + QPID_COMMON_EXTERN bool getTable(const std::string& name, FieldTable& value) const; + QPID_COMMON_EXTERN bool getArray(const std::string& name, Array& value) const; + QPID_COMMON_EXTERN bool getFloat(const std::string& name, float& value) const; + QPID_COMMON_EXTERN bool getDouble(const std::string& name, double& value) const; + //QPID_COMMON_EXTERN bool getTimestamp(const std::string& name, uint64_t& value) const; + //QPID_COMMON_EXTERN bool getDecimal(string& name, xxx& value); + QPID_COMMON_EXTERN void erase(const std::string& name); + + + QPID_COMMON_EXTERN bool operator==(const FieldTable& other) const; + + // Map-like interface. + QPID_COMMON_EXTERN ValueMap::const_iterator begin() const; + QPID_COMMON_EXTERN ValueMap::const_iterator end() const; + QPID_COMMON_EXTERN ValueMap::const_iterator find(const std::string& s) const; + + QPID_COMMON_EXTERN ValueMap::iterator begin(); + QPID_COMMON_EXTERN ValueMap::iterator end(); + QPID_COMMON_EXTERN ValueMap::iterator find(const std::string& s); + + QPID_COMMON_EXTERN std::pair <ValueMap::iterator, bool> insert(const ValueMap::value_type&); + QPID_COMMON_EXTERN ValueMap::iterator insert(ValueMap::iterator, const ValueMap::value_type&); + QPID_COMMON_EXTERN void clear(); + + private: + void realDecode() const; + void flushRawCache(); + + mutable qpid::sys::Mutex lock; + mutable ValueMap values; + mutable boost::shared_array<uint8_t> cachedBytes; + mutable uint32_t cachedSize; // if = 0 then non cached size as 0 is not a legal size + mutable bool newBytes; + + QPID_COMMON_EXTERN friend std::ostream& operator<<(std::ostream& out, const FieldTable& body); +}; + +//class FieldNotFoundException{}; +//class UnknownFieldName : public FieldNotFoundException{}; +//class IncorrectFieldType : public FieldNotFoundException{}; +} +} + + +#endif diff --git a/qpid/cpp/src/qpid/framing/FieldValue.h b/qpid/cpp/src/qpid/framing/FieldValue.h new file mode 100644 index 0000000000..1adcb2fa07 --- /dev/null +++ b/qpid/cpp/src/qpid/framing/FieldValue.h @@ -0,0 +1,484 @@ +#ifndef _framing_FieldValue_h +#define _framing_FieldValue_h +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/Exception.h" +#include "qpid/framing/amqp_types.h" +#include "qpid/framing/Buffer.h" +#include "qpid/framing/FieldTable.h" +#include "qpid/CommonImportExport.h" + +#include <iostream> +#include <memory> +#include <vector> + +#include <assert.h> + +namespace qpid { +namespace framing { + +/** + * Exception that is the base exception for all field table errors. + * + * \ingroup clientapi + */ +class QPID_COMMON_CLASS_EXTERN FieldValueException : public qpid::Exception {}; + +/** + * Exception thrown when we can't perform requested conversion + * + * \ingroup clientapi + */ +struct QPID_COMMON_CLASS_EXTERN InvalidConversionException : public FieldValueException { + InvalidConversionException() {} +}; + +class List; + +/** + * Value that can appear in an AMQP field table + * + * \ingroup clientapi + */ +class QPID_COMMON_CLASS_EXTERN FieldValue { + public: + /* + * Abstract type for content of different types + */ + class Data { + public: + virtual ~Data() {}; + virtual uint32_t encodedSize() const = 0; + virtual void encode(Buffer& buffer) = 0; + virtual void decode(Buffer& buffer) = 0; + virtual bool operator==(const Data&) const = 0; + + virtual bool convertsToInt() const { return false; } + virtual bool convertsToString() const { return false; } + virtual int64_t getInt() const { throw InvalidConversionException();} + virtual std::string getString() const { throw InvalidConversionException(); } + + virtual void print(std::ostream& out) const = 0; + }; + + FieldValue(): data(0) {}; + // Default assignment operator is fine + void setType(uint8_t type); + QPID_COMMON_EXTERN uint8_t getType() const; + Data& getData() { return *data; } + uint32_t encodedSize() const { return 1 + data->encodedSize(); }; + bool empty() const { return data.get() == 0; } + void encode(Buffer& buffer); + void decode(Buffer& buffer); + QPID_COMMON_EXTERN bool operator==(const FieldValue&) const; + QPID_COMMON_INLINE_EXTERN bool operator!=(const FieldValue& v) const { return !(*this == v); } + + QPID_COMMON_EXTERN void print(std::ostream& out) const; + + template <typename T> bool convertsTo() const { return false; } + template <typename T> T get() const { throw InvalidConversionException(); } + + template <class T, int W> T getIntegerValue() const; + template <class T> T getIntegerValue() const; + template <class T, int W> T getFloatingPointValue() const; + template <int W> void getFixedWidthValue(unsigned char*) const; + template <class T> bool get(T&) const; + + protected: + FieldValue(uint8_t t, Data* d): typeOctet(t), data(d) {} + + QPID_COMMON_EXTERN static uint8_t* convertIfRequired(uint8_t* const octets, int width); + + private: + uint8_t typeOctet; + std::auto_ptr<Data> data; + +}; + +template <> +inline bool FieldValue::convertsTo<int>() const { return data->convertsToInt(); } + +template <> +inline bool FieldValue::convertsTo<int64_t>() const { return data->convertsToInt(); } + +template <> +inline bool FieldValue::convertsTo<std::string>() const { return data->convertsToString(); } + +template <> +inline int FieldValue::get<int>() const { return static_cast<int>(data->getInt()); } + +template <> +inline int64_t FieldValue::get<int64_t>() const { return data->getInt(); } + +template <> +inline std::string FieldValue::get<std::string>() const { return data->getString(); } + +inline std::ostream& operator<<(std::ostream& out, const FieldValue& v) { + v.print(out); + return out; +} + +template <int width> +class FixedWidthValue : public FieldValue::Data { + uint8_t octets[width]; + + public: + FixedWidthValue() {} + FixedWidthValue(const uint8_t (&data)[width]) : octets(data) {} + FixedWidthValue(const uint8_t* const data) + { + for (int i = 0; i < width; i++) octets[i] = data[i]; + } + FixedWidthValue(uint64_t v) + { + for (int i = width; i > 1; --i) { + octets[i-1] = (uint8_t) (0xFF & v); v >>= 8; + } + octets[0] = (uint8_t) (0xFF & v); + } + uint32_t encodedSize() const { return width; } + void encode(Buffer& buffer) { buffer.putRawData(octets, width); } + void decode(Buffer& buffer) { buffer.getRawData(octets, width); } + bool operator==(const Data& d) const { + const FixedWidthValue<width>* rhs = dynamic_cast< const FixedWidthValue<width>* >(&d); + if (rhs == 0) return false; + else return std::equal(&octets[0], &octets[width], &rhs->octets[0]); + } + + bool convertsToInt() const { return true; } + int64_t getInt() const + { + int64_t v = 0; + for (int i = 0; i < width-1; ++i) { + v |= octets[i]; v <<= 8; + } + v |= octets[width-1]; + return v; + } + uint8_t* rawOctets() { return octets; } + const uint8_t* rawOctets() const { return octets; } + + void print(std::ostream& o) const { o << "F" << width << ":"; }; +}; + +class UuidData : public FixedWidthValue<16> { + public: + UuidData(); + UuidData(const unsigned char* bytes); + bool convertsToString() const; + std::string getString() const; +}; + +template <class T, int W> +inline T FieldValue::getIntegerValue() const +{ + FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get()); + if (fwv) { + uint8_t* octets = fwv->rawOctets(); + T v = 0; + for (int i = 0; i < W-1; ++i) { + v |= octets[i]; v <<= 8; + } + v |= octets[W-1]; + return v; + } else { + throw InvalidConversionException(); + } +} + +template <class T> +inline T FieldValue::getIntegerValue() const +{ + FixedWidthValue<1>* const fwv = dynamic_cast< FixedWidthValue<1>* const>(data.get()); + if (fwv) { + uint8_t* octets = fwv->rawOctets(); + return octets[0]; + } else { + throw InvalidConversionException(); + } +} + +template <class T, int W> +inline T FieldValue::getFloatingPointValue() const { + FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get()); + if (fwv) { + T value; + uint8_t* const octets = convertIfRequired(fwv->rawOctets(), W); + uint8_t* const target = reinterpret_cast<uint8_t*>(&value); + for (size_t i = 0; i < W; ++i) target[i] = octets[i]; + return value; + } else { + throw InvalidConversionException(); + } +} + +template <int W> void FieldValue::getFixedWidthValue(unsigned char* value) const +{ + FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get()); + if (fwv) { + for (size_t i = 0; i < W; ++i) value[i] = fwv->rawOctets()[i]; + } else { + throw InvalidConversionException(); + } +} + +template <> +inline float FieldValue::get<float>() const { + return getFloatingPointValue<float, 4>(); +} + +template <> +inline double FieldValue::get<double>() const { + return getFloatingPointValue<double, 8>(); +} + +template <> +class FixedWidthValue<0> : public FieldValue::Data { + public: + // Implicit default constructor is fine + uint32_t encodedSize() const { return 0; } + void encode(Buffer&) {}; + void decode(Buffer&) {}; + bool operator==(const Data& d) const { + const FixedWidthValue<0>* rhs = dynamic_cast< const FixedWidthValue<0>* >(&d); + return rhs != 0; + } + void print(std::ostream& o) const { o << "F0"; }; +}; + +template <int lenwidth> +class VariableWidthValue : public FieldValue::Data { + std::vector<uint8_t> octets; + + public: + VariableWidthValue() {} + VariableWidthValue(const std::vector<uint8_t>& data) : octets(data) {} + VariableWidthValue(const uint8_t* start, const uint8_t* end) : octets(start, end) {} + uint32_t encodedSize() const { return lenwidth + octets.size(); } + void encode(Buffer& buffer) { + buffer.putUInt<lenwidth>(octets.size()); + if (octets.size() > 0) + buffer.putRawData(&octets[0], octets.size()); + }; + void decode(Buffer& buffer) { + uint32_t len = buffer.getUInt<lenwidth>(); + buffer.checkAvailable(len); + octets.resize(len); + if (len > 0) + buffer.getRawData(&octets[0], len); + } + bool operator==(const Data& d) const { + const VariableWidthValue<lenwidth>* rhs = dynamic_cast< const VariableWidthValue<lenwidth>* >(&d); + if (rhs == 0) return false; + else return octets==rhs->octets; + } + + bool convertsToString() const { return true; } + std::string getString() const { return std::string(octets.begin(), octets.end()); } + + void print(std::ostream& o) const { o << "V" << lenwidth << ":" << octets.size() << ":"; }; +}; + +template <class T> +class EncodedValue : public FieldValue::Data { + T value; + public: + + EncodedValue() {} + EncodedValue(const T& v) : value(v) {} + + T& getValue() { return value; } + const T& getValue() const { return value; } + + uint32_t encodedSize() const { return value.encodedSize(); } + + void encode(Buffer& buffer) { + value.encode(buffer); + }; + void decode(Buffer& buffer) { + value.decode(buffer); + } + bool operator==(const Data& d) const { + const EncodedValue<T>* rhs = dynamic_cast< const EncodedValue<T>* >(&d); + if (rhs == 0) return false; + else return value==rhs->value; + } + + void print(std::ostream& o) const { o << "[" << value << "]"; }; +}; + +/** + * Accessor that can be used to get values of type FieldTable, Array + * and List. + */ +template <class T> +inline bool FieldValue::get(T& t) const +{ + const EncodedValue<T>* v = dynamic_cast< EncodedValue<T>* >(data.get()); + if (v != 0) { + t = v->getValue(); + return true; + } else { + try { + t = get<T>(); + return true; + } catch (const InvalidConversionException&) { + return false; + } + } +} + +class Str8Value : public FieldValue { + public: + QPID_COMMON_EXTERN Str8Value(const std::string& v); +}; + +class Str16Value : public FieldValue { + public: + QPID_COMMON_EXTERN Str16Value(const std::string& v); +}; + +class Var16Value : public FieldValue { + public: + QPID_COMMON_EXTERN Var16Value(const std::string& v, uint8_t code); +}; + +class Var32Value : public FieldValue { + public: + QPID_COMMON_EXTERN Var32Value(const std::string& v, uint8_t code); + }; + +class Struct32Value : public FieldValue { + public: + QPID_COMMON_EXTERN Struct32Value(const std::string& v); +}; + +class FloatValue : public FieldValue +{ + public: + QPID_COMMON_EXTERN FloatValue(float f); +}; +class DoubleValue : public FieldValue +{ + public: + QPID_COMMON_EXTERN DoubleValue(double f); +}; + +/* + * Basic integer value encodes as signed 32 bit + */ +class IntegerValue : public FieldValue { + public: + QPID_COMMON_EXTERN IntegerValue(int v); +}; + +class TimeValue : public FieldValue { + public: + QPID_COMMON_EXTERN TimeValue(uint64_t v); +}; + +class Integer64Value : public FieldValue { + public: + QPID_COMMON_EXTERN Integer64Value(int64_t v); +}; + +class Unsigned64Value : public FieldValue { + public: + QPID_COMMON_EXTERN Unsigned64Value(uint64_t v); +}; + +class FieldTableValue : public FieldValue { + public: + typedef FieldTable ValueType; + QPID_COMMON_EXTERN FieldTableValue(const FieldTable&); +}; + +class ArrayValue : public FieldValue { + public: + QPID_COMMON_EXTERN ArrayValue(const Array&); +}; + +class VoidValue : public FieldValue { + public: + QPID_COMMON_EXTERN VoidValue(); +}; + +class BoolValue : public FieldValue { + public: + QPID_COMMON_EXTERN BoolValue(bool); +}; + +class Unsigned8Value : public FieldValue { + public: + QPID_COMMON_EXTERN Unsigned8Value(uint8_t); +}; + +class Unsigned16Value : public FieldValue { + public: + QPID_COMMON_EXTERN Unsigned16Value(uint16_t); +}; + +class Unsigned32Value : public FieldValue { + public: + QPID_COMMON_EXTERN Unsigned32Value(uint32_t); +}; + +class Integer8Value : public FieldValue { + public: + QPID_COMMON_EXTERN Integer8Value(int8_t); +}; + +class Integer16Value : public FieldValue { + public: + QPID_COMMON_EXTERN Integer16Value(int16_t); +}; + +typedef IntegerValue Integer32Value; + +class ListValue : public FieldValue { + public: + typedef List ValueType; + QPID_COMMON_EXTERN ListValue(const List&); +}; + +class UuidValue : public FieldValue { + public: + QPID_COMMON_EXTERN UuidValue(); + QPID_COMMON_EXTERN UuidValue(const unsigned char*); +}; + +template <class T> +bool getEncodedValue(FieldTable::ValuePtr vptr, T& value) +{ + if (vptr) { + const EncodedValue<T>* ev = dynamic_cast< EncodedValue<T>* >(&(vptr->getData())); + if (ev != 0) { + value = ev->getValue(); + return true; + } + } + return false; +} + +}} // qpid::framing + +#endif diff --git a/qpid/cpp/src/qpid/framing/FrameSet.h b/qpid/cpp/src/qpid/framing/FrameSet.h index 9640abb7ac..4188fd9b8c 100644 --- a/qpid/cpp/src/qpid/framing/FrameSet.h +++ b/qpid/cpp/src/qpid/framing/FrameSet.h @@ -9,9 +9,9 @@ * 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 @@ -44,6 +44,8 @@ class FrameSet public: typedef boost::shared_ptr<FrameSet> shared_ptr; + typedef Frames::iterator iterator; + typedef Frames::const_iterator const_iterator; QPID_COMMON_EXTERN FrameSet(const SequenceNumber& id); QPID_COMMON_EXTERN FrameSet(const FrameSet&); @@ -62,7 +64,7 @@ public: QPID_COMMON_EXTERN AMQMethodBody* getMethod(); QPID_COMMON_EXTERN const AMQHeaderBody* getHeaders() const; QPID_COMMON_EXTERN AMQHeaderBody* getHeaders(); - + template <class T> bool isA() const { const AMQMethodBody* method = getMethod(); return method && method->isA<T>(); @@ -71,12 +73,12 @@ public: template <class T> const T* as() const { const AMQMethodBody* method = getMethod(); return (method && method->isA<T>()) ? dynamic_cast<const T*>(method) : 0; - } + } template <class T> T* as() { AMQMethodBody* method = getMethod(); return (method && method->isA<T>()) ? dynamic_cast<T*>(method) : 0; - } + } template <class T> const T* getHeaderProperties() const { const AMQHeaderBody* header = getHeaders(); @@ -85,7 +87,7 @@ public: Frames::const_iterator begin() const { return parts.begin(); } Frames::const_iterator end() const { return parts.end(); } - + const SequenceNumber& getId() const { return id; } template <class P> void remove(P predicate) { diff --git a/qpid/cpp/src/qpid/framing/List.h b/qpid/cpp/src/qpid/framing/List.h new file mode 100644 index 0000000000..681445947c --- /dev/null +++ b/qpid/cpp/src/qpid/framing/List.h @@ -0,0 +1,78 @@ +#ifndef QPID_FRAMING_LIST_H +#define QPID_FRAMING_LIST_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "qpid/CommonImportExport.h" +#include "qpid/framing/amqp_types.h" +#include <iostream> +#include <list> +#include <boost/shared_ptr.hpp> + +namespace qpid { +namespace framing { + +class Buffer; +class FieldValue; + +/** + * Representation of an AMQP 0-10 list + */ +class QPID_COMMON_CLASS_EXTERN List +{ + public: + typedef boost::shared_ptr<FieldValue> ValuePtr; + typedef ValuePtr value_type; + typedef std::list<ValuePtr> Values; + typedef Values::const_iterator const_iterator; + typedef Values::iterator iterator; + typedef Values::const_reference const_reference; + typedef Values::reference reference; + + QPID_COMMON_EXTERN uint32_t encodedSize() const; + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN void decode(Buffer& buffer); + + QPID_COMMON_EXTERN bool operator==(const List& other) const; + + // std collection interface. + QPID_COMMON_INLINE_EXTERN const_iterator begin() const { return values.begin(); } + QPID_COMMON_INLINE_EXTERN const_iterator end() const { return values.end(); } + QPID_COMMON_INLINE_EXTERN iterator begin() { return values.begin(); } + QPID_COMMON_INLINE_EXTERN iterator end(){ return values.end(); } + + QPID_COMMON_INLINE_EXTERN ValuePtr front() const { return values.front(); } + QPID_COMMON_INLINE_EXTERN ValuePtr back() const { return values.back(); } + QPID_COMMON_INLINE_EXTERN size_t size() const { return values.size(); } + + QPID_COMMON_INLINE_EXTERN iterator insert(iterator i, ValuePtr value) { return values.insert(i, value); } + QPID_COMMON_INLINE_EXTERN void erase(iterator i) { values.erase(i); } + QPID_COMMON_INLINE_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); } + QPID_COMMON_INLINE_EXTERN void pop_back() { values.pop_back(); } + + private: + Values values; + + friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& out, const List& list); +}; +}} // namespace qpid::framing + +#endif /*!QPID_FRAMING_LIST_H*/ diff --git a/qpid/cpp/src/qpid/framing/ProtocolVersion.h b/qpid/cpp/src/qpid/framing/ProtocolVersion.h new file mode 100644 index 0000000000..309e543516 --- /dev/null +++ b/qpid/cpp/src/qpid/framing/ProtocolVersion.h @@ -0,0 +1,67 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _ProtocolVersion_ +#define _ProtocolVersion_ + +#include "qpid/framing/amqp_types.h" +#include "qpid/CommonImportExport.h" + +#include <string> + +namespace qpid +{ +namespace framing +{ + +class QPID_COMMON_CLASS_EXTERN ProtocolVersion +{ +private: + uint8_t major_; + uint8_t minor_; + uint8_t protocol_; + +public: + explicit ProtocolVersion(uint8_t _major=0, uint8_t _minor=0, uint8_t _protocol=0) + : major_(_major), minor_(_minor), protocol_(_protocol) {} + + QPID_COMMON_INLINE_EXTERN uint8_t getMajor() const { return major_; } + QPID_COMMON_INLINE_EXTERN void setMajor(uint8_t major) { major_ = major; } + QPID_COMMON_INLINE_EXTERN uint8_t getMinor() const { return minor_; } + QPID_COMMON_INLINE_EXTERN void setMinor(uint8_t minor) { minor_ = minor; } + QPID_COMMON_INLINE_EXTERN uint8_t getProtocol() const { return protocol_; } + QPID_COMMON_INLINE_EXTERN void setProtocol(uint8_t protocol) { protocol_ = protocol; } + QPID_COMMON_EXTERN const std::string toString() const; + + QPID_COMMON_EXTERN ProtocolVersion& operator=(ProtocolVersion p); + + QPID_COMMON_EXTERN bool operator==(ProtocolVersion p) const; + QPID_COMMON_INLINE_EXTERN bool operator!=(ProtocolVersion p) const { return ! (*this == p); } + QPID_COMMON_EXTERN static uint8_t AMQP; + QPID_COMMON_EXTERN static uint8_t LEGACY_AMQP; + QPID_COMMON_EXTERN static uint8_t TLS; + QPID_COMMON_EXTERN static uint8_t SASL; +}; + +} // namespace framing +} // namespace qpid + + +#endif // ifndef _ProtocolVersion_ diff --git a/qpid/cpp/src/qpid/framing/SequenceNumber.h b/qpid/cpp/src/qpid/framing/SequenceNumber.h new file mode 100644 index 0000000000..00fa2469c8 --- /dev/null +++ b/qpid/cpp/src/qpid/framing/SequenceNumber.h @@ -0,0 +1,85 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#ifndef _framing_SequenceNumber_h +#define _framing_SequenceNumber_h + +#include "qpid/framing/amqp_types.h" +#include <boost/operators.hpp> +#include <iosfwd> +#include "qpid/CommonImportExport.h" + +namespace qpid { +namespace framing { + +class Buffer; + +/** + * 4-byte sequence number that 'wraps around'. + */ +class QPID_COMMON_CLASS_EXTERN SequenceNumber : public +boost::equality_comparable< + SequenceNumber, boost::less_than_comparable< + SequenceNumber, boost::incrementable< + SequenceNumber, boost::decrementable<SequenceNumber> > > > +{ + int32_t value; + + public: + SequenceNumber(uint32_t v=0) : value(v) {} + + SequenceNumber& operator++() { ++value; return *this; } + SequenceNumber& operator--() { --value; return *this; } + bool operator==(const SequenceNumber& other) const { return value == other.value; } + bool operator<(const SequenceNumber& other) const { return (value - other.value) < 0; } + uint32_t getValue() const { return uint32_t(value); } + operator uint32_t() const { return uint32_t(value); } + + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN void decode(Buffer& buffer); + QPID_COMMON_EXTERN uint32_t encodedSize() const; + + template <class S> void serialize(S& s) { s(value); } +}; + +inline int32_t operator-(const SequenceNumber& a, const SequenceNumber& b) { + return int32_t(a.getValue() - b.getValue()); +} + +inline SequenceNumber operator+(const SequenceNumber& a, int32_t n) { + return SequenceNumber(a.getValue() + n); +} + +inline SequenceNumber operator-(const SequenceNumber& a, int32_t n) { + return SequenceNumber(a.getValue() - n); +} + +struct Window +{ + SequenceNumber hwm; + SequenceNumber lwm; +}; + +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& o, const SequenceNumber& n); + +}} // namespace qpid::framing + + +#endif diff --git a/qpid/cpp/src/qpid/framing/SequenceSet.h b/qpid/cpp/src/qpid/framing/SequenceSet.h new file mode 100644 index 0000000000..827c8999b3 --- /dev/null +++ b/qpid/cpp/src/qpid/framing/SequenceSet.h @@ -0,0 +1,69 @@ +/* + * + * 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. + * + */ +#ifndef _framing_SequenceSet_h +#define _framing_SequenceSet_h + +#include "qpid/framing/SequenceNumber.h" +#include "qpid/RangeSet.h" +#include "qpid/CommonImportExport.h" + +namespace qpid { +namespace framing { +class Buffer; + +class QPID_COMMON_CLASS_EXTERN SequenceSet : public RangeSet<SequenceNumber> { + public: + SequenceSet() {} + SequenceSet(const RangeSet<SequenceNumber>& r) + : RangeSet<SequenceNumber>(r) {} + SequenceSet(const SequenceNumber& s) { add(s); } + SequenceSet(const SequenceNumber& start, const SequenceNumber finish) { add(start,finish); } + + + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN void decode(Buffer& buffer); + QPID_COMMON_EXTERN uint32_t encodedSize() const; + + QPID_COMMON_EXTERN bool contains(const SequenceNumber& s) const; + QPID_COMMON_EXTERN void add(const SequenceNumber& s); + QPID_COMMON_EXTERN void add(const SequenceNumber& start, const SequenceNumber& finish); // Closed range + QPID_COMMON_EXTERN void add(const SequenceSet& set); + QPID_COMMON_EXTERN void remove(const SequenceNumber& s); + QPID_COMMON_EXTERN void remove(const SequenceNumber& start, const SequenceNumber& finish); // Closed range + QPID_COMMON_EXTERN void remove(const SequenceSet& set); + + template <class T> void for_each(T& t) const { + for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++) + t(i->first(), i->last()); + } + + template <class T> void for_each(const T& t) const { + for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++) + t(i->first(), i->last()); + } + + friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SequenceSet&); +}; + +}} // namespace qpid::framing + + +#endif diff --git a/qpid/cpp/src/qpid/framing/StructHelper.h b/qpid/cpp/src/qpid/framing/StructHelper.h new file mode 100644 index 0000000000..fe2fa64ce7 --- /dev/null +++ b/qpid/cpp/src/qpid/framing/StructHelper.h @@ -0,0 +1,57 @@ +/* + * + * 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. + * + */ +#ifndef _StructHelper_ +#define _StructHelper_ + +#include "qpid/Exception.h" +#include "qpid/CommonImportExport.h" +#include "qpid/framing/Buffer.h" + +#include <stdlib.h> // For alloca + +namespace qpid { +namespace framing { + +class QPID_COMMON_CLASS_EXTERN StructHelper +{ +public: + + template <class T> void encode(const T& t, std::string& data) { + uint32_t size = t.bodySize() + 2/*type*/; + data.resize(size); + Buffer wbuffer(const_cast<char*>(data.data()), size); + wbuffer.putShort(T::TYPE); + t.encodeStructBody(wbuffer); + } + + template <class T> void decode(T& t, const std::string& data) { + Buffer rbuffer(const_cast<char*>(data.data()), data.length()); + uint16_t type = rbuffer.getShort(); + if (type == T::TYPE) { + t.decodeStructBody(rbuffer); + } else { + throw Exception("Type code does not match"); + } + } +}; + +}} +#endif diff --git a/qpid/cpp/src/qpid/framing/Uuid.h b/qpid/cpp/src/qpid/framing/Uuid.h new file mode 100644 index 0000000000..e9e56ed7c9 --- /dev/null +++ b/qpid/cpp/src/qpid/framing/Uuid.h @@ -0,0 +1,94 @@ +#ifndef QPID_FRAMING_UUID_H +#define QPID_FRAMING_UUID_H + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "qpid/CommonImportExport.h" +#include "qpid/sys/IntegerTypes.h" + +#include <boost/array.hpp> + +#include <ostream> +#include <istream> + +namespace qpid { +namespace framing { + +class Buffer; + +/** + * A UUID is represented as a boost::array of 16 bytes. + * + * Full value semantics, operators ==, < etc. are provided by + * boost::array so Uuid can be the key type in a map etc. + * + * TODO: change this implementation as it leaks boost into the + * client API + */ +struct Uuid : public boost::array<uint8_t, 16> { + /** If unique is true, generate a unique ID else a null ID. */ + QPID_COMMON_EXTERN Uuid(bool unique=false); + + /** Copy from 16 bytes of data. */ + QPID_COMMON_EXTERN Uuid(const uint8_t* data); + + /** Parse format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */ + QPID_COMMON_EXTERN Uuid(const std::string&); + + // Default op= and copy ctor are fine. + // boost::array gives us ==, < etc. + + /** Copy from 16 bytes of data. */ + QPID_COMMON_EXTERN void assign(const uint8_t* data); + + /** Set to a new unique identifier. */ + QPID_COMMON_EXTERN void generate(); + + /** Set to all zeros. */ + QPID_COMMON_EXTERN void clear(); + + /** Test for null (all zeros). */ + QPID_COMMON_EXTERN bool isNull() const; + QPID_COMMON_INLINE_EXTERN operator bool() const { return !isNull(); } + QPID_COMMON_INLINE_EXTERN bool operator!() const { return isNull(); } + + QPID_COMMON_EXTERN void encode(framing::Buffer& buf) const; + QPID_COMMON_EXTERN void decode(framing::Buffer& buf); + QPID_COMMON_INLINE_EXTERN uint32_t encodedSize() const + { return static_cast<uint32_t>(size()); } + + /** String value in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */ + QPID_COMMON_EXTERN std::string str() const; + + template <class S> void serialize(S& s) { + s.raw(begin(), size()); + } +}; + +/** Print in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */ +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, Uuid); + +/** Read from format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */ +QPID_COMMON_EXTERN std::istream& operator>>(std::istream&, Uuid&); + +}} // namespace qpid::framing + + + +#endif /*!QPID_FRAMING_UUID_H*/ diff --git a/qpid/cpp/src/qpid/framing/amqp_types.h b/qpid/cpp/src/qpid/framing/amqp_types.h new file mode 100644 index 0000000000..2072a83904 --- /dev/null +++ b/qpid/cpp/src/qpid/framing/amqp_types.h @@ -0,0 +1,64 @@ +#ifndef AMQP_TYPES_H +#define AMQP_TYPES_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. + * + */ + +/** \file + * Definitions and forward declarations of all types used + * in AMQP messages. + */ + +#include "qpid/sys/IntegerTypes.h" + +namespace qpid { +namespace framing { + +typedef uint8_t FrameType; +typedef uint16_t ChannelId; +typedef uint32_t BatchOffset; +typedef uint8_t ClassId; +typedef uint8_t MethodId; +typedef uint16_t ReplyCode; + +// Types represented by classes. +class Content; +class FieldTable; +class SequenceNumberSet; +struct Uuid; + +// Useful constants + +/** Maximum channel ID used by broker. Reserve high bit for internal use.*/ +const ChannelId CHANNEL_MAX=(ChannelId(~1))>>1; +const ChannelId CHANNEL_HIGH_BIT= ChannelId(~CHANNEL_MAX); + +// Forward declare class types +class FramingContent; +class FieldTable; +class SequenceNumberSet; +class SequenceSet; +struct Uuid; + +// Enum types +enum DeliveryMode { TRANSIENT = 1, PERSISTENT = 2}; + +}} // namespace qpid::framing +#endif diff --git a/qpid/cpp/src/qpid/framing/amqp_types_full.h b/qpid/cpp/src/qpid/framing/amqp_types_full.h new file mode 100644 index 0000000000..c5d84dedea --- /dev/null +++ b/qpid/cpp/src/qpid/framing/amqp_types_full.h @@ -0,0 +1,38 @@ +#ifndef _framing_amqp_types_decl_h +#define _framing_amqp_types_decl_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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. + * + */ + +/** \file + * Definitions and full declarations of all types used + * in AMQP messages. + * + * It's better to include amqp_types.h in another header instead of this file + * unless the header actually needs the full declarations. Including + * full declarations when forward declarations would increase compile + * times. + */ + +#include "qpid/framing/amqp_types.h" +#include "qpid/framing/Array.h" +#include "qpid/framing/FieldTable.h" +#include "qpid/framing/SequenceSet.h" +#include "qpid/framing/Uuid.h" + +#endif /*!_framing_amqp_types_decl_h*/ diff --git a/qpid/cpp/src/qpid/ha/AlternateExchangeSetter.h b/qpid/cpp/src/qpid/ha/AlternateExchangeSetter.h index 2386a01084..fbf4755e7d 100644 --- a/qpid/cpp/src/qpid/ha/AlternateExchangeSetter.h +++ b/qpid/cpp/src/qpid/ha/AlternateExchangeSetter.h @@ -25,7 +25,6 @@ #include "qpid/log/Statement.h" #include "qpid/broker/Exchange.h" #include "qpid/broker/ExchangeRegistry.h" -#include "boost/function.hpp" #include <map> namespace qpid { diff --git a/qpid/cpp/src/qpid/ha/Backup.cpp b/qpid/cpp/src/qpid/ha/Backup.cpp index e28ca1fa6a..503de3e351 100644 --- a/qpid/cpp/src/qpid/ha/Backup.cpp +++ b/qpid/cpp/src/qpid/ha/Backup.cpp @@ -52,9 +52,7 @@ using sys::Mutex; Backup::Backup(HaBroker& hb, const Settings& s) : logPrefix("Backup: "), membership(hb.getMembership()), stopped(false), haBroker(hb), broker(hb.getBroker()), settings(s), - statusCheck( - new StatusCheck( - logPrefix, broker.getOptions().linkHeartbeatInterval, hb.getBrokerInfo())) + statusCheck(new StatusCheck(hb)) {} void Backup::setBrokerUrl(const Url& brokers) { diff --git a/qpid/cpp/src/qpid/ha/Backup.h b/qpid/cpp/src/qpid/ha/Backup.h index 4943ca5e2e..88194158ce 100644 --- a/qpid/cpp/src/qpid/ha/Backup.h +++ b/qpid/cpp/src/qpid/ha/Backup.h @@ -59,6 +59,8 @@ class Backup : public Role Role* promote(); + boost::shared_ptr<BrokerReplicator> getBrokerReplicator() { return replicator; } + private: void stop(sys::Mutex::ScopedLock&); Role* recover(sys::Mutex::ScopedLock&); diff --git a/qpid/cpp/src/qpid/ha/BrokerInfo.h b/qpid/cpp/src/qpid/ha/BrokerInfo.h index bd1ad86392..87d51f5113 100644 --- a/qpid/cpp/src/qpid/ha/BrokerInfo.h +++ b/qpid/cpp/src/qpid/ha/BrokerInfo.h @@ -23,6 +23,7 @@ */ #include "types.h" +#include "hash.h" #include "qpid/Url.h" #include "qpid/framing/FieldTable.h" #include "qpid/types/Uuid.h" @@ -42,7 +43,7 @@ class BrokerInfo { public: typedef std::set<BrokerInfo> Set; - typedef qpid::sys::unordered_map<types::Uuid, BrokerInfo, types::Uuid::Hasher> Map; + typedef qpid::sys::unordered_map<types::Uuid, BrokerInfo, Hasher<types::Uuid> > Map; BrokerInfo(); BrokerInfo(const types::Uuid& id, BrokerStatus, const Address& = Address()); diff --git a/qpid/cpp/src/qpid/ha/BrokerReplicator.cpp b/qpid/cpp/src/qpid/ha/BrokerReplicator.cpp index 17b00185ef..eb1206437a 100644 --- a/qpid/cpp/src/qpid/ha/BrokerReplicator.cpp +++ b/qpid/cpp/src/qpid/ha/BrokerReplicator.cpp @@ -21,6 +21,7 @@ #include "BrokerReplicator.h" #include "HaBroker.h" #include "QueueReplicator.h" +#include "TxReplicator.h" #include "qpid/broker/Broker.h" #include "qpid/broker/amqp_0_10/Connection.h" #include "qpid/broker/ConnectionObserver.h" @@ -129,7 +130,6 @@ const string COLON(":"); void sendQuery(const string& packageName, const string& className, const string& queueName, SessionHandler& sessionHandler) { - framing::AMQP_ServerProxy peer(sessionHandler.out); Variant::Map request; request[WHAT] = OBJECT; Variant::Map schema; @@ -229,8 +229,8 @@ class BrokerReplicator::UpdateTracker { typedef boost::function<void (const std::string&)> CleanFn; UpdateTracker(const std::string& type_, // "queue" or "exchange" - CleanFn f, const ReplicationTest& rt) - : type(type_), cleanFn(f), repTest(rt) {} + CleanFn f) + : type(type_), cleanFn(f) {} /** Destructor cleans up remaining initial queues. */ ~UpdateTracker() { @@ -245,16 +245,10 @@ class BrokerReplicator::UpdateTracker { } /** Add an exchange name */ - void addExchange(Exchange::shared_ptr ex) { - if (repTest.getLevel(*ex)) - initial.insert(ex->getName()); - } + void addExchange(Exchange::shared_ptr ex) { initial.insert(ex->getName()); } /** Add a queue name. */ - void addQueue(Queue::shared_ptr q) { - if (repTest.getLevel(*q)) - initial.insert(q->getName()); - } + void addQueue(Queue::shared_ptr q) { initial.insert(q->getName()); } /** Received an event for name */ void event(const std::string& name) { @@ -275,13 +269,13 @@ class BrokerReplicator::UpdateTracker { void clean(const std::string& name) { QPID_LOG(info, "Backup: Deleted " << type << " " << name << ": no longer exists on primary"); - cleanFn(name); + try { cleanFn(name); } + catch (const framing::NotFoundException&) {} } std::string type; Names initial, events; CleanFn cleanFn; - ReplicationTest repTest; }; namespace { @@ -349,7 +343,8 @@ BrokerReplicator::~BrokerReplicator() { shutdown(); } namespace { void collectQueueReplicators( - const boost::shared_ptr<Exchange> ex, set<boost::shared_ptr<QueueReplicator> >& collect) + const boost::shared_ptr<Exchange>& ex, + set<boost::shared_ptr<QueueReplicator> >& collect) { boost::shared_ptr<QueueReplicator> qr(boost::dynamic_pointer_cast<QueueReplicator>(ex)); if (qr) collect.insert(qr); @@ -390,16 +385,13 @@ void BrokerReplicator::connected(Bridge& bridge, SessionHandler& sessionHandler) exchangeTracker.reset( new UpdateTracker("exchange", - boost::bind(&BrokerReplicator::deleteExchange, this, _1), - replicationTest)); - exchanges.eachExchange( - boost::bind(&UpdateTracker::addExchange, exchangeTracker.get(), _1)); + boost::bind(&BrokerReplicator::deleteExchange, this, _1))); + exchanges.eachExchange(boost::bind(&BrokerReplicator::existingExchange, this, _1)); queueTracker.reset( new UpdateTracker("queue", - boost::bind(&BrokerReplicator::deleteQueue, this, _1, true), - replicationTest)); - queues.eachQueue(boost::bind(&UpdateTracker::addQueue, queueTracker.get(), _1)); + boost::bind(&BrokerReplicator::deleteQueue, this, _1, true))); + queues.eachQueue(boost::bind(&BrokerReplicator::existingQueue, this, _1)); framing::AMQP_ServerProxy peer(sessionHandler.out); const qmf::org::apache::qpid::broker::ArgsLinkBridge& args(bridge.getArgs()); @@ -428,6 +420,21 @@ void BrokerReplicator::connected(Bridge& bridge, SessionHandler& sessionHandler) sendQuery(ORG_APACHE_QPID_BROKER, BINDING, queueName, sessionHandler); } +// Called for each queue in existence when the backup connects to a primary. +void BrokerReplicator::existingQueue(const boost::shared_ptr<Queue>& q) { + if (replicationTest.getLevel(*q)) { + QPID_LOG(debug, "Existing queue: " << q->getName()); + queueTracker->addQueue(q); + } +} + +void BrokerReplicator::existingExchange(const boost::shared_ptr<Exchange>& ex) { + if (replicationTest.getLevel(*ex)) { + QPID_LOG(debug, "Existing exchange: " << ex->getName()); + exchangeTracker->addExchange(ex); + } +} + void BrokerReplicator::route(Deliverable& msg) { // We transition from JOINING->CATCHUP on the first message received from the primary. // Until now we couldn't be sure if we had a good connection to the primary. @@ -554,11 +561,7 @@ void BrokerReplicator::doEventExchangeDeclare(Variant::Map& values) { void BrokerReplicator::doEventExchangeDelete(Variant::Map& values) { string name = values[EXNAME].asString(); boost::shared_ptr<Exchange> exchange = exchanges.find(name); - if (!exchange) { - QPID_LOG(warning, logPrefix << "Exchange delete event, not found: " << name); - } else if (!replicationTest.getLevel(*exchange)) { - QPID_LOG(warning, logPrefix << "Exchange delete event, not replicated: " << name); - } else { + if (exchange && replicationTest.getLevel(*exchange)) { QPID_LOG(debug, logPrefix << "Exchange delete event:" << name); if (exchangeTracker.get()) exchangeTracker->event(name); deleteExchange(name); @@ -651,8 +654,10 @@ void BrokerReplicator::doResponseQueue(Variant::Map& values) { if (!queueTracker.get()) throw Exception(QPID_MSG("Unexpected queue response: " << values)); if (!queueTracker->response(name)) return; // Response is out-of-date + QPID_LOG(debug, logPrefix << "Queue response: " << name); boost::shared_ptr<Queue> queue = queues.find(name); + if (queue) { // Already exists bool uuidOk = (getHaUuid(queue->getSettings().original) == getHaUuid(argsMap)); if (!uuidOk) QPID_LOG(debug, logPrefix << "UUID mismatch for queue: " << name); @@ -660,6 +665,7 @@ void BrokerReplicator::doResponseQueue(Variant::Map& values) { QPID_LOG(debug, logPrefix << "Queue response replacing queue: " << name); deleteQueue(name); } + framing::FieldTable args; qpid::amqp_0_10::translate(argsMap, args); boost::shared_ptr<QueueReplicator> qr = replicateQueue( @@ -770,8 +776,13 @@ boost::shared_ptr<QueueReplicator> BrokerReplicator::startQueueReplicator( const boost::shared_ptr<Queue>& queue) { if (replicationTest.getLevel(*queue) == ALL) { - boost::shared_ptr<QueueReplicator> qr( - new QueueReplicator(haBroker, queue, link)); + boost::shared_ptr<QueueReplicator> qr; + if (TxReplicator::isTxQueue(queue->getName())){ + qr.reset(new TxReplicator(haBroker, queue, link)); + } + else { + qr.reset(new QueueReplicator(haBroker, queue, link)); + } qr->activate(); return qr; } @@ -785,7 +796,7 @@ void BrokerReplicator::deleteQueue(const std::string& name, bool purge) { // messages. Any reroutes will be done at the primary and // replicated as normal. if (purge) queue->purge(0, boost::shared_ptr<Exchange>()); - broker.deleteQueue(name, userId, remoteHost); + haBroker.getBroker().deleteQueue(name, userId, remoteHost); QPID_LOG(debug, logPrefix << "Queue deleted: " << name); } } @@ -864,28 +875,35 @@ bool BrokerReplicator::isBound(boost::shared_ptr<Queue>, const string* const, co string BrokerReplicator::getType() const { return QPID_CONFIGURATION_REPLICATOR; } -void BrokerReplicator::autoDeleteCheck(boost::shared_ptr<Exchange> ex) { +void BrokerReplicator::disconnectedExchange(boost::shared_ptr<Exchange> ex) { boost::shared_ptr<QueueReplicator> qr(boost::dynamic_pointer_cast<QueueReplicator>(ex)); - if (!qr) return; - assert(qr); - if (qr->getQueue()->isAutoDelete() && qr->isSubscribed()) { - if (qr->getQueue()->getSettings().autoDeleteDelay) { - // Start the auto-delete timer - qr->getQueue()->releaseFromUse(); - qr->getQueue()->scheduleAutoDelete(); + if (qr) { + qr->disconnect(); + if (TxReplicator::isTxQueue(qr->getQueue()->getName())) { + // Transactions are aborted on failover so clean up tx-queues + deleteQueue(qr->getQueue()->getName()); } - else { - // Delete immediately. Don't purge, the primary is gone so we need - // to reroute the deleted messages. - deleteQueue(qr->getQueue()->getName(), false); + else if (qr->getQueue()->isAutoDelete() && qr->isSubscribed()) { + if (qr->getQueue()->getSettings().autoDeleteDelay) { + // Start the auto-delete timer + qr->getQueue()->releaseFromUse(); + qr->getQueue()->scheduleAutoDelete(); + } + else { + // Delete immediately. Don't purge, the primary is gone so we need + // to reroute the deleted messages. + deleteQueue(qr->getQueue()->getName(), false); + } } } } +typedef vector<boost::shared_ptr<Exchange> > ExchangeVector; + // Callback function for accumulating exchange candidates namespace { - void exchangeAccumulatorCallback(vector<boost::shared_ptr<Exchange> >& c, const Exchange::shared_ptr& i) { - c.push_back(i); + void exchangeAccumulatorCallback(ExchangeVector& ev, const Exchange::shared_ptr& i) { + ev.push_back(i); } } @@ -893,13 +911,12 @@ namespace { void BrokerReplicator::disconnected() { QPID_LOG(info, logPrefix << "Disconnected from primary " << primary); connection = 0; - // Clean up auto-delete queues - vector<boost::shared_ptr<Exchange> > collect; - // Make a copy so we can work outside the ExchangeRegistry lock - exchanges.eachExchange( - boost::bind(&exchangeAccumulatorCallback, boost::ref(collect), _1)); - for_each(collect.begin(), collect.end(), - boost::bind(&BrokerReplicator::autoDeleteCheck, this, _1)); + + // Make copy of exchanges so we can work outside the registry lock. + ExchangeVector exs; + exchanges.eachExchange(boost::bind(&exchangeAccumulatorCallback, boost::ref(exs), _1)); + for_each(exs.begin(), exs.end(), + boost::bind(&BrokerReplicator::disconnectedExchange, this, _1)); } void BrokerReplicator::setMembership(const Variant::List& brokers) { diff --git a/qpid/cpp/src/qpid/ha/BrokerReplicator.h b/qpid/cpp/src/qpid/ha/BrokerReplicator.h index f93e25cb81..395f0706d9 100644 --- a/qpid/cpp/src/qpid/ha/BrokerReplicator.h +++ b/qpid/cpp/src/qpid/ha/BrokerReplicator.h @@ -71,6 +71,8 @@ class BrokerReplicator : public broker::Exchange, public boost::enable_shared_from_this<BrokerReplicator> { public: + typedef boost::shared_ptr<QueueReplicator> QueueReplicatorPtr; + BrokerReplicator(HaBroker&, const boost::shared_ptr<broker::Link>&); ~BrokerReplicator(); @@ -84,8 +86,9 @@ class BrokerReplicator : public broker::Exchange, bool isBound(boost::shared_ptr<broker::Queue>, const std::string* const, const framing::FieldTable* const); void shutdown(); + QueueReplicatorPtr findQueueReplicator(const std::string& qname); + private: - typedef boost::shared_ptr<QueueReplicator> QueueReplicatorPtr; typedef std::pair<boost::shared_ptr<broker::Queue>, bool> CreateQueueResult; typedef std::pair<boost::shared_ptr<broker::Exchange>, bool> CreateExchangeResult; @@ -99,6 +102,8 @@ class BrokerReplicator : public broker::Exchange, class ConnectionObserver; void connected(broker::Bridge&, broker::SessionHandler&); + void existingQueue(const boost::shared_ptr<broker::Queue>&); + void existingExchange(const boost::shared_ptr<broker::Exchange>&); void doEventQueueDeclare(types::Variant::Map& values); void doEventQueueDelete(types::Variant::Map& values); @@ -114,7 +119,6 @@ class BrokerReplicator : public broker::Exchange, void doResponseBind(types::Variant::Map& values); void doResponseHaBroker(types::Variant::Map& values); - QueueReplicatorPtr findQueueReplicator(const std::string& qname); QueueReplicatorPtr startQueueReplicator(const boost::shared_ptr<broker::Queue>&); QueueReplicatorPtr replicateQueue( @@ -135,8 +139,7 @@ class BrokerReplicator : public broker::Exchange, void deleteQueue(const std::string& name, bool purge=true); void deleteExchange(const std::string& name); - void autoDeleteCheck(boost::shared_ptr<broker::Exchange>); - + void disconnectedExchange(boost::shared_ptr<broker::Exchange>); void disconnected(); void setMembership(const types::Variant::List&); // Set membership from list. diff --git a/qpid/cpp/src/qpid/ha/makeMessage.cpp b/qpid/cpp/src/qpid/ha/Event.cpp index 5b063a23e7..8265a6edd3 100644 --- a/qpid/cpp/src/qpid/ha/makeMessage.cpp +++ b/qpid/cpp/src/qpid/ha/Event.cpp @@ -18,45 +18,69 @@ * under the License. * */ -#include "makeMessage.h" +#include "Event.h" #include "qpid/broker/amqp_0_10/MessageTransfer.h" #include "qpid/framing/AMQFrame.h" +#include "qpid/framing/DeliveryProperties.h" #include "qpid/framing/MessageTransferBody.h" +#include "qpid/log/Statement.h" namespace qpid { namespace ha { -broker::Message makeMessage(const framing::Buffer& buffer, - const std::string& destination) -{ - using namespace framing; - using broker::amqp_0_10::MessageTransfer; +using namespace std; +using namespace framing; +using namespace broker::amqp_0_10; + +namespace { +const string QPID_HA(QPID_HA_PREFIX); +} + +bool isEventKey(const std::string& key) { + const std::string& prefix = QPID_HA; + bool ret = key.size() > prefix.size() && key.compare(0, prefix.size(), prefix) == 0; + return ret; +} + +const string DequeueEvent::KEY(QPID_HA+"de"); +const string IdEvent::KEY(QPID_HA+"id"); +const string TxEnqueueEvent::KEY(QPID_HA+"txenq"); +const string TxDequeueEvent::KEY(QPID_HA+"txdeq"); +const string TxPrepareEvent::KEY(QPID_HA+"txpre"); +const string TxCommitEvent::KEY(QPID_HA+"txcom"); +const string TxRollbackEvent::KEY(QPID_HA+"txrb"); +const string TxPrepareOkEvent::KEY(QPID_HA+"txok"); +const string TxPrepareFailEvent::KEY(QPID_HA+"txno"); +const string TxMembersEvent::KEY(QPID_HA+"txmem"); - boost::intrusive_ptr<MessageTransfer> transfer( - new qpid::broker::amqp_0_10::MessageTransfer()); +broker::Message makeMessage( + const string& data, const string& destination, const string& routingKey) +{ + boost::intrusive_ptr<MessageTransfer> transfer(new MessageTransfer()); AMQFrame method((MessageTransferBody(ProtocolVersion(), destination, 0, 0))); + method.setBof(true); + method.setEof(false); + method.setBos(true); + method.setEos(true); AMQFrame header((AMQHeaderBody())); - AMQFrame content((AMQContentBody())); - // AMQContentBody::decode is missing a const declaration, so cast it here. - content.castBody<AMQContentBody>()->decode( - const_cast<Buffer&>(buffer), buffer.getSize()); header.setBof(false); header.setEof(false); header.setBos(true); header.setEos(true); + AMQFrame content((AMQContentBody())); content.setBof(false); content.setEof(true); content.setBos(true); content.setEos(true); + Buffer buffer(const_cast<char*>(&data[0]), data.size()); + content.castBody<AMQContentBody>()->decode( + const_cast<Buffer&>(buffer), buffer.getSize()); transfer->getFrames().append(method); transfer->getFrames().append(header); transfer->getFrames().append(content); + transfer->getFrames().getHeaders()-> + get<DeliveryProperties>(true)->setRoutingKey(routingKey); return broker::Message(transfer, 0); } -broker::Message makeMessage(const std::string& content, const std::string& destination) { - framing::Buffer buffer(const_cast<char*>(&content[0]), content.size()); - return makeMessage(buffer, destination); -} - }} // namespace qpid::ha diff --git a/qpid/cpp/src/qpid/ha/Event.h b/qpid/cpp/src/qpid/ha/Event.h new file mode 100644 index 0000000000..f292499e7b --- /dev/null +++ b/qpid/cpp/src/qpid/ha/Event.h @@ -0,0 +1,193 @@ +#ifndef QPID_HA_EVENT_H +#define QPID_HA_EVENT_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 "types.h" +#include "qpid/broker/Message.h" +#include "qpid/framing/BufferTypes.h" + +/**@file Defines event messages used to pass transaction information from + * primary observers to backup replicators. + */ + +namespace qpid { +namespace ha { + +broker::Message makeMessage( + const std::string& content, + const std::string& destination, + const std::string& routingKey); + + +/** Test if a string is an event key */ +bool isEventKey(const std::string& key); + +/** Base class for encodable events */ +class Event { + public: + virtual ~Event() {} + virtual void encode(framing::Buffer& buffer) const = 0; + virtual void decode(framing::Buffer& buffer) = 0; + virtual size_t encodedSize() const = 0; + virtual std::string key() const = 0; // Routing key + virtual void print(std::ostream& o) const = 0; + broker::Message message(const std::string& destination=std::string()) const { + return makeMessage(framing::encodeStr(*this), destination, key()); } +}; + + +inline std::ostream& operator<<(std::ostream& o, const Event& e) { + o << "<" << e.key() << ":"; + e.print(o); + return o << ">"; +} + +/** Event base template */ +template <class Derived> class EventBase : public Event { + public: + std::string key() const { return Derived::KEY; } +}; + +//////////////// Specific event type + +//// QueueReplicator events + +struct DequeueEvent : public EventBase<DequeueEvent> { + static const std::string KEY; + ReplicationIdSet ids; + + DequeueEvent(ReplicationIdSet ids_=ReplicationIdSet()) : ids(ids_) {} + void encode(framing::Buffer& b) const { b.put(ids); } + void decode(framing::Buffer& b) { b.get(ids); } + virtual size_t encodedSize() const { return ids.encodedSize(); } + void print(std::ostream& o) const { o << ids; } +}; + +struct IdEvent : public EventBase<IdEvent> { + static const std::string KEY; + ReplicationId id; + + IdEvent(ReplicationId id_=0) : id(id_) {} + void encode(framing::Buffer& b) const { b.put(id); } + void decode(framing::Buffer& b) { b.get(id); } + virtual size_t encodedSize() const { return id.encodedSize(); } + void print(std::ostream& o) const { o << id; } +}; + +//// Transaction events + +struct TxEnqueueEvent : public EventBase<TxEnqueueEvent> { + static const std::string KEY; + framing::LongString queue; + ReplicationId id; + + TxEnqueueEvent(std::string q=std::string(), ReplicationId i=ReplicationId()) + : queue(q), id(i) {} + void encode(framing::Buffer& b) const { b.put(queue); b.put(id); } + void decode(framing::Buffer& b) { b.get(queue); b.get(id); } + virtual size_t encodedSize() const { return queue.encodedSize()+id.encodedSize(); } + void print(std::ostream& o) const { o << queue.value << " " << id; } +}; + +struct TxDequeueEvent : public EventBase<TxDequeueEvent> { + static const std::string KEY; + framing::LongString queue; + ReplicationId id; + + TxDequeueEvent(std::string q=std::string(), ReplicationId r=0) : + queue(q), id(r) {} + void encode(framing::Buffer& b) const { b.put(queue);b.put(id); } + void decode(framing::Buffer& b) { b.get(queue);b.get(id); } + virtual size_t encodedSize() const { return queue.encodedSize()+id.encodedSize(); } + void print(std::ostream& o) const { o << queue.value << " " << id; } +}; + +struct TxPrepareEvent : public EventBase<TxPrepareEvent> { + static const std::string KEY; + void encode(framing::Buffer&) const {} + void decode(framing::Buffer&) {} + virtual size_t encodedSize() const { return 0; } + void print(std::ostream&) const {} +}; + +struct TxCommitEvent : public EventBase<TxCommitEvent> { + static const std::string KEY; + void encode(framing::Buffer&) const {} + void decode(framing::Buffer&) {} + virtual size_t encodedSize() const { return 0; } + void print(std::ostream&) const {} +}; + +struct TxRollbackEvent : public EventBase<TxRollbackEvent> { + static const std::string KEY; + void encode(framing::Buffer&) const {} + void decode(framing::Buffer&) {} + virtual size_t encodedSize() const { return 0; } + void print(std::ostream&) const {} +}; + +struct TxPrepareOkEvent : public EventBase<TxPrepareOkEvent> { + static const std::string KEY; + types::Uuid broker; + TxPrepareOkEvent(const types::Uuid& b=types::Uuid()) : broker(b) {} + + void encode(framing::Buffer& b) const { + b.putRawData(broker.data(), broker.size()); + } + + void decode(framing::Buffer& b) { + std::string s; + b.getRawData(s, broker.size()); + broker = types::Uuid(&s[0]); + } + virtual size_t encodedSize() const { return broker.size(); } + void print(std::ostream& o) const { o << broker; } +}; + +struct TxPrepareFailEvent : public EventBase<TxPrepareFailEvent> { + static const std::string KEY; + types::Uuid broker; + TxPrepareFailEvent(const types::Uuid& b=types::Uuid()) : broker(b) {} + void encode(framing::Buffer& b) const { b.putRawData(broker.data(), broker.size()); } + void decode(framing::Buffer& b) { + std::string s; + b.getRawData(s, broker.size()); + broker = types::Uuid(&s[0]); + } + virtual size_t encodedSize() const { return broker.size(); } + void print(std::ostream& o) const { o << broker; } +}; + +struct TxMembersEvent : public EventBase<TxMembersEvent> { + static const std::string KEY; + UuidSet members; + TxMembersEvent(const UuidSet& s=UuidSet()) : members(s) {} + void encode(framing::Buffer& b) const { b.put(members); } + void decode(framing::Buffer& b) { b.get(members); } + size_t encodedSize() const { return members.encodedSize(); } + void print(std::ostream& o) const { o << members; } +}; + +}} // namespace qpid::ha + +#endif /*!QPID_HA_EVENT_H*/ diff --git a/qpid/cpp/src/qpid/ha/FailoverExchange.cpp b/qpid/cpp/src/qpid/ha/FailoverExchange.cpp index 556c7458b6..9c7b986bf8 100644 --- a/qpid/cpp/src/qpid/ha/FailoverExchange.cpp +++ b/qpid/cpp/src/qpid/ha/FailoverExchange.cpp @@ -19,7 +19,7 @@ * */ #include "FailoverExchange.h" -#include "makeMessage.h" +#include "Event.h" #include "qpid/broker/amqp_0_10/MessageTransfer.h" #include "qpid/broker/Message.h" #include "qpid/broker/DeliverableMessage.h" @@ -117,7 +117,7 @@ void FailoverExchange::sendUpdate(const Queue::shared_ptr& queue, sys::Mutex::Sc if (urls.empty()) return; framing::Array array = vectorToUrlArray(urls); const ProtocolVersion v; - broker::Message message(makeMessage(Buffer(), typeName)); + broker::Message message(makeMessage(std::string(), typeName, typeName)); MessageTransfer& transfer = MessageTransfer::get(message); MessageProperties* props = transfer.getFrames().getHeaders()->get<framing::MessageProperties>(true); diff --git a/qpid/cpp/src/qpid/ha/HaBroker.cpp b/qpid/cpp/src/qpid/ha/HaBroker.cpp index 7efeaad5b2..61561b3af6 100644 --- a/qpid/cpp/src/qpid/ha/HaBroker.cpp +++ b/qpid/cpp/src/qpid/ha/HaBroker.cpp @@ -64,6 +64,7 @@ using boost::dynamic_pointer_cast; HaBroker::HaBroker(broker::Broker& b, const Settings& s) : systemId(b.getSystem()->getSystemId().data()), settings(s), + userId(s.username+"@"+b.getOptions().realm), broker(b), observer(new ConnectionObserver(*this, systemId)), role(new StandAlone), @@ -75,14 +76,14 @@ HaBroker::HaBroker(broker::Broker& b, const Settings& s) // otherwise there's a window for a client to connect before we get to // initialize() if (settings.cluster) { - QPID_LOG(debug, "Broker startup, rejecting client connections."); + QPID_LOG(debug, "Backup starting, rejecting client connections."); shared_ptr<broker::ConnectionObserver> excluder(new BackupConnectionExcluder); observer->setObserver(excluder, "Backup: "); broker.getConnectionObservers().add(observer); broker.getExchanges().registerExchange(failoverExchange); } // QueueSnapshots are needed for standalone replication as well as cluster. - broker.getConfigurationObservers().add(queueSnapshots); + broker.getBrokerObservers().add(queueSnapshots); } namespace { @@ -94,7 +95,7 @@ bool isNone(const std::string& x) { return x.empty() || x == NONE; } void HaBroker::initialize() { if (settings.cluster) { membership.setStatus(JOINING); - QPID_LOG(notice, "Initializing HA broker: " << membership.getInfo()); + QPID_LOG(notice, "Initializing HA broker: " << membership.getSelf()); } // Set up the management object. @@ -202,7 +203,7 @@ std::vector<Url> HaBroker::getKnownBrokers() const { } void HaBroker::shutdown(const std::string& message) { - QPID_LOG(critical, message); + QPID_LOG(critical, "Shutting down: " << message); broker.shutdown(); throw Exception(message); } @@ -213,7 +214,7 @@ BrokerStatus HaBroker::getStatus() const { void HaBroker::setAddress(const Address& a) { QPID_LOG(info, role->getLogPrefix() << "Set self address to: " << a); - membership.setAddress(a); + membership.setSelfAddress(a); } boost::shared_ptr<QueueReplicator> HaBroker::findQueueReplicator(const std::string& queueName) { diff --git a/qpid/cpp/src/qpid/ha/HaBroker.h b/qpid/cpp/src/qpid/ha/HaBroker.h index 8e5d30acfb..d10014846c 100644 --- a/qpid/cpp/src/qpid/ha/HaBroker.h +++ b/qpid/cpp/src/qpid/ha/HaBroker.h @@ -84,6 +84,7 @@ class HaBroker : public management::Manageable broker::Broker& getBroker() { return broker; } const Settings& getSettings() const { return settings; } + boost::shared_ptr<Role> getRole() const {return role; } /** Shut down the broker because of a critical error. */ void shutdown(const std::string& message); @@ -91,7 +92,7 @@ class HaBroker : public management::Manageable BrokerStatus getStatus() const; boost::shared_ptr<ConnectionObserver> getObserver() { return observer; } - BrokerInfo getBrokerInfo() const { return membership.getInfo(); } + BrokerInfo getBrokerInfo() const { return membership.getSelf(); } Membership& getMembership() { return membership; } types::Uuid getSystemId() const { return systemId; } @@ -101,6 +102,9 @@ class HaBroker : public management::Manageable boost::shared_ptr<QueueReplicator> findQueueReplicator(const std::string& queueName); + /** Authenticated user ID for queue create/delete */ + std::string getUserId() const { return userId; } + private: void setPublicUrl(const Url&); void setBrokerUrl(const Url&); @@ -111,6 +115,7 @@ class HaBroker : public management::Manageable // Immutable members const types::Uuid systemId; const Settings settings; + const std::string userId; // Member variables protected by lock mutable sys::Mutex lock; diff --git a/qpid/cpp/src/qpid/ha/Membership.cpp b/qpid/cpp/src/qpid/ha/Membership.cpp index 411bad3841..2f8ef1da97 100644 --- a/qpid/cpp/src/qpid/ha/Membership.cpp +++ b/qpid/cpp/src/qpid/ha/Membership.cpp @@ -107,6 +107,14 @@ BrokerInfo::Set Membership::otherBackups() const { return result; } +BrokerInfo::Set Membership::getBrokers() const { + Mutex::ScopedLock l(lock); + BrokerInfo::Set result; + transform(brokers.begin(), brokers.end(), inserter(result, result.begin()), + boost::bind(&BrokerInfo::Map::value_type::second, _1)); + return result; +} + bool Membership::get(const types::Uuid& id, BrokerInfo& result) const { Mutex::ScopedLock l(lock); BrokerInfo::Map::const_iterator i = brokers.find(id); @@ -136,10 +144,9 @@ bool checkTransition(BrokerStatus from, BrokerStatus to) { } } // namespace - void Membership::update(Mutex::ScopedLock& l) { QPID_LOG(info, "Membership: " << brokers); - // Update managment and send update event. +// Update managment and send update event. BrokerStatus newStatus = getStatus(l); Variant::List brokerList = asList(l); if (mgmtObject) { @@ -198,14 +205,14 @@ BrokerStatus Membership::getStatus(sys::Mutex::ScopedLock&) const { return i->second.getStatus(); } -BrokerInfo Membership::getInfo() const { +BrokerInfo Membership::getSelf() const { Mutex::ScopedLock l(lock); BrokerInfo::Map::const_iterator i = brokers.find(self); assert(i != brokers.end()); return i->second; } -void Membership::setAddress(const Address& a) { +void Membership::setSelfAddress(const Address& a) { Mutex::ScopedLock l(lock); brokers[self].setAddress(a); update(l); diff --git a/qpid/cpp/src/qpid/ha/Membership.h b/qpid/cpp/src/qpid/ha/Membership.h index f442586a71..5b2b72e2fc 100644 --- a/qpid/cpp/src/qpid/ha/Membership.h +++ b/qpid/cpp/src/qpid/ha/Membership.h @@ -26,6 +26,7 @@ #include "types.h" #include "qpid/log/Statement.h" #include "qpid/sys/Mutex.h" +#include "qpid/sys/Time.h" #include "qpid/types/Variant.h" #include <boost/function.hpp> #include <set> @@ -69,16 +70,19 @@ class Membership /** Return IDs of all READY backups other than self */ BrokerInfo::Set otherBackups() const; + /** Return IDs of all brokers */ + BrokerInfo::Set getBrokers() const; + void assign(const types::Variant::List&); types::Variant::List asList() const; bool get(const types::Uuid& id, BrokerInfo& result) const; - types::Uuid getSelf() const { return self; } - BrokerInfo getInfo() const; + BrokerInfo getSelf() const; BrokerStatus getStatus() const; void setStatus(BrokerStatus s); - void setAddress(const Address&); + + void setSelfAddress(const Address&); private: void update(sys::Mutex::ScopedLock&); diff --git a/qpid/cpp/src/qpid/ha/Primary.cpp b/qpid/cpp/src/qpid/ha/Primary.cpp index beabab4e32..e7fdc5035f 100644 --- a/qpid/cpp/src/qpid/ha/Primary.cpp +++ b/qpid/cpp/src/qpid/ha/Primary.cpp @@ -27,17 +27,19 @@ #include "RemoteBackup.h" #include "ConnectionObserver.h" #include "QueueReplicator.h" +#include "PrimaryTxObserver.h" #include "qpid/assert.h" #include "qpid/broker/Broker.h" -#include "qpid/broker/ConfigurationObserver.h" +#include "qpid/broker/BrokerObserver.h" #include "qpid/broker/Connection.h" #include "qpid/broker/Queue.h" #include "qpid/framing/FieldTable.h" #include "qpid/framing/FieldValue.h" -#include "qpid/framing/Uuid.h" #include "qpid/log/Statement.h" +#include "qpid/types/Uuid.h" #include "qpid/sys/Timer.h" #include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> namespace qpid { namespace ha { @@ -59,15 +61,18 @@ class PrimaryConnectionObserver : public broker::ConnectionObserver Primary& primary; }; -class PrimaryConfigurationObserver : public broker::ConfigurationObserver +class PrimaryBrokerObserver : public broker::BrokerObserver { public: - PrimaryConfigurationObserver(Primary& p) : primary(p) {} + PrimaryBrokerObserver(Primary& p) : primary(p) {} void queueCreate(const Primary::QueuePtr& q) { primary.queueCreate(q); } void queueDestroy(const Primary::QueuePtr& q) { primary.queueDestroy(q); } void exchangeCreate(const Primary::ExchangePtr& q) { primary.exchangeCreate(q); } void exchangeDestroy(const Primary::ExchangePtr& q) { primary.exchangeDestroy(q); } - private: + void startTx(const shared_ptr<broker::TxBuffer>& tx) { primary.startTx(tx); } + void startDtx(const shared_ptr<broker::DtxBuffer>& dtx) { primary.startDtx(dtx); } + + private: Primary& primary; }; @@ -82,8 +87,6 @@ class ExpectedBackupTimerTask : public sys::TimerTask { } // namespace -Primary* Primary::instance = 0; - Primary::Primary(HaBroker& hb, const BrokerInfo::Set& expect) : haBroker(hb), membership(hb.getMembership()), logPrefix("Primary: "), active(false), @@ -92,13 +95,11 @@ Primary::Primary(HaBroker& hb, const BrokerInfo::Set& expect) : hb.getMembership().setStatus(RECOVERING); broker::QueueRegistry& queues = hb.getBroker().getQueues(); queues.eachQueue(boost::bind(&Primary::initializeQueue, this, _1)); - assert(instance == 0); - instance = this; // Let queue replicators find us. if (expect.empty()) { QPID_LOG(notice, logPrefix << "Promoted to primary. No expected backups."); } else { - // NOTE: RemoteBackups must be created before we set the ConfigurationObserver + // NOTE: RemoteBackups must be created before we set the BrokerObserver // or ConnectionObserver so that there is no client activity while // the QueueGuards are created. QPID_LOG(notice, logPrefix << "Promoted to primary. Expected backups: " << expect); @@ -113,8 +114,8 @@ Primary::Primary(HaBroker& hb, const BrokerInfo::Set& expect) : timerTask = new ExpectedBackupTimerTask(*this, deadline); hb.getBroker().getTimer().add(timerTask); } - configurationObserver.reset(new PrimaryConfigurationObserver(*this)); - haBroker.getBroker().getConfigurationObservers().add(configurationObserver); + brokerObserver.reset(new PrimaryBrokerObserver(*this)); + haBroker.getBroker().getBrokerObservers().add(brokerObserver); checkReady(); // Outside lock // Allow client connections @@ -124,7 +125,7 @@ Primary::Primary(HaBroker& hb, const BrokerInfo::Set& expect) : Primary::~Primary() { if (timerTask) timerTask->cancel(); - haBroker.getBroker().getConfigurationObservers().remove(configurationObserver); + haBroker.getBroker().getBrokerObservers().remove(brokerObserver); haBroker.getObserver()->reset(); } @@ -212,14 +213,42 @@ void Primary::readyReplica(const ReplicatingSubscription& rs) { if (backup) checkReady(backup); } +void Primary::addReplica(ReplicatingSubscription& rs) { + // Note this is called before the ReplicatingSubscription has been activated + // on the queue. + sys::Mutex::ScopedLock l(lock); + replicas[make_pair(rs.getBrokerInfo().getSystemId(), rs.getQueue())] = &rs; +} + +void Primary::skip( + const types::Uuid& backup, + const boost::shared_ptr<broker::Queue>& queue, + const ReplicationIdSet& ids) +{ + sys::Mutex::ScopedLock l(lock); + ReplicaMap::const_iterator i = replicas.find(make_pair(backup, queue)); + if (i != replicas.end()) i->second->addSkip(ids); +} + +void Primary::removeReplica(const ReplicatingSubscription& rs) { + sys::Mutex::ScopedLock l(lock); + replicas.erase(make_pair(rs.getBrokerInfo().getSystemId(), rs.getQueue())); + + TxMap::const_iterator i = txMap.find(rs.getQueue()->getName()); + if (i != txMap.end()) { + boost::shared_ptr<PrimaryTxObserver> tx = i->second.lock(); + if (tx) tx->cancel(rs); + } +} + // NOTE: Called with queue registry lock held. void Primary::queueCreate(const QueuePtr& q) { // Set replication argument. ReplicateLevel level = replicationTest.useLevel(*q); - QPID_LOG(debug, logPrefix << "Created queue " << q->getName() - << " replication: " << printable(level)); q->addArgument(QPID_REPLICATE, printable(level).str()); if (level) { + QPID_LOG(debug, logPrefix << "Created queue " << q->getName() + << " replication: " << printable(level)); initializeQueue(q); // Give each queue a unique id. Used by backups to avoid confusion of // same-named queues. @@ -235,24 +264,26 @@ void Primary::queueCreate(const QueuePtr& q) { // NOTE: Called with queue registry lock held. void Primary::queueDestroy(const QueuePtr& q) { - QPID_LOG(debug, logPrefix << "Destroyed queue " << q->getName()); - { - Mutex::ScopedLock l(lock); - for (BackupMap::iterator i = backups.begin(); i != backups.end(); ++i) - i->second->queueDestroy(q); + if (replicationTest.useLevel(*q)) { + QPID_LOG(debug, logPrefix << "Destroyed queue " << q->getName()); + { + Mutex::ScopedLock l(lock); + for (BackupMap::iterator i = backups.begin(); i != backups.end(); ++i) + i->second->queueDestroy(q); + } + checkReady(); // Outside lock } - checkReady(); // Outside lock } // NOTE: Called with exchange registry lock held. void Primary::exchangeCreate(const ExchangePtr& ex) { ReplicateLevel level = replicationTest.useLevel(*ex); - QPID_LOG(debug, logPrefix << "Created exchange " << ex->getName() - << " replication: " << printable(level)); FieldTable args = ex->getArgs(); args.setString(QPID_REPLICATE, printable(level).str()); // Set replication arg. if (level) { - // Give each exchange a unique id to avoid confusion of same-named exchanges. + QPID_LOG(debug, logPrefix << "Created exchange " << ex->getName() + << " replication: " << printable(level)); + // Give each exchange a unique id to avoid confusion of same-named exchanges. args.set(QPID_HA_UUID, FieldTable::ValuePtr(new UuidValue(&Uuid(true)[0]))); } ex->setArgs(args); @@ -260,8 +291,10 @@ void Primary::exchangeCreate(const ExchangePtr& ex) { // NOTE: Called with exchange registry lock held. void Primary::exchangeDestroy(const ExchangePtr& ex) { - QPID_LOG(debug, logPrefix << "Destroyed exchange " << ex->getName()); - // Do nothing + if (replicationTest.useLevel(*ex)) { + QPID_LOG(debug, logPrefix << "Destroyed exchange " << ex->getName()); + // Do nothing + } } // New backup connected @@ -280,6 +313,7 @@ void Primary::backupDisconnect(shared_ptr<RemoteBackup> backup, Mutex::ScopedLoc backup->cancel(); expectedBackups.erase(backup); backups.erase(id); + membership.remove(id); } @@ -365,4 +399,19 @@ void Primary::setCatchupQueues(const RemoteBackupPtr& backup, bool createGuards) backup->startCatchup(); } +shared_ptr<PrimaryTxObserver> Primary::makeTxObserver() { + shared_ptr<PrimaryTxObserver> observer(new PrimaryTxObserver(haBroker)); + observer->initialize(); + txMap[observer->getTxQueue()->getName()] = observer; + return observer; +} + +void Primary::startTx(const boost::shared_ptr<broker::TxBuffer>& tx) { + tx->setObserver(makeTxObserver()); +} + +void Primary::startDtx(const boost::shared_ptr<broker::DtxBuffer>& dtx) { + dtx->setObserver(makeTxObserver()); +} + }} // namespace qpid::ha diff --git a/qpid/cpp/src/qpid/ha/Primary.h b/qpid/cpp/src/qpid/ha/Primary.h index 3e1ec48ce6..d1350ab261 100644 --- a/qpid/cpp/src/qpid/ha/Primary.h +++ b/qpid/cpp/src/qpid/ha/Primary.h @@ -23,12 +23,14 @@ */ #include "types.h" +#include "hash.h" #include "BrokerInfo.h" #include "ReplicationTest.h" #include "Role.h" #include "qpid/sys/Mutex.h" #include "qpid/sys/unordered_map.h" #include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> #include <boost/intrusive_ptr.hpp> #include <string> @@ -38,7 +40,9 @@ namespace broker { class Queue; class Connection; class ConnectionObserver; -class ConfigurationObserver; +class BrokerObserver; +class TxBuffer; +class DtxBuffer; } namespace sys { @@ -51,6 +55,7 @@ class ReplicatingSubscription; class RemoteBackup; class QueueGuard; class Membership; +class PrimaryTxObserver; /** * State associated with a primary broker: @@ -66,8 +71,6 @@ class Primary : public Role typedef boost::shared_ptr<broker::Exchange> ExchangePtr; typedef boost::shared_ptr<RemoteBackup> RemoteBackupPtr; - static Primary* get() { return instance; } - Primary(HaBroker& hb, const BrokerInfo::Set& expectedBackups); ~Primary(); @@ -77,13 +80,21 @@ class Primary : public Role void setBrokerUrl(const Url&) {} void readyReplica(const ReplicatingSubscription&); - void removeReplica(const std::string& q); + void addReplica(ReplicatingSubscription&); + void removeReplica(const ReplicatingSubscription&); + + /** Skip replication of ids to queue on backup. */ + void skip(const types::Uuid& backup, + const boost::shared_ptr<broker::Queue>& queue, + const ReplicationIdSet& ids); - // Called via ConfigurationObserver + // Called via BrokerObserver void queueCreate(const QueuePtr&); void queueDestroy(const QueuePtr&); void exchangeCreate(const ExchangePtr&); void exchangeDestroy(const ExchangePtr&); + void startTx(const boost::shared_ptr<broker::TxBuffer>&); + void startDtx(const boost::shared_ptr<broker::DtxBuffer>&); // Called via ConnectionObserver void opened(broker::Connection& connection); @@ -95,11 +106,18 @@ class Primary : public Role void timeoutExpectedBackups(); private: - typedef qpid::sys::unordered_map< - types::Uuid, RemoteBackupPtr, types::Uuid::Hasher > BackupMap; + typedef sys::unordered_map< + types::Uuid, RemoteBackupPtr, Hasher<types::Uuid> > BackupMap; typedef std::set<RemoteBackupPtr > BackupSet; + typedef std::pair<types::Uuid, boost::shared_ptr<broker::Queue> > UuidQueue; + typedef sys::unordered_map<UuidQueue, ReplicatingSubscription*, + Hasher<UuidQueue> > ReplicaMap; + + // Map of PrimaryTxObservers by tx-queue name + typedef sys::unordered_map<std::string, boost::weak_ptr<PrimaryTxObserver> > TxMap; + RemoteBackupPtr backupConnect(const BrokerInfo&, broker::Connection&, sys::Mutex::ScopedLock&); void backupDisconnect(RemoteBackupPtr, sys::Mutex::ScopedLock&); @@ -107,8 +125,10 @@ class Primary : public Role void checkReady(); void checkReady(RemoteBackupPtr); void setCatchupQueues(const RemoteBackupPtr&, bool createGuards); + void deduplicate(); + boost::shared_ptr<PrimaryTxObserver> makeTxObserver(); - sys::Mutex lock; + mutable sys::Mutex lock; HaBroker& haBroker; Membership& membership; std::string logPrefix; @@ -126,9 +146,10 @@ class Primary : public Role */ BackupMap backups; boost::shared_ptr<broker::ConnectionObserver> connectionObserver; - boost::shared_ptr<broker::ConfigurationObserver> configurationObserver; + boost::shared_ptr<broker::BrokerObserver> brokerObserver; boost::intrusive_ptr<sys::TimerTask> timerTask; - static Primary* instance; + ReplicaMap replicas; + TxMap txMap; }; }} // namespace qpid::ha diff --git a/qpid/cpp/src/qpid/ha/PrimaryTxObserver.cpp b/qpid/cpp/src/qpid/ha/PrimaryTxObserver.cpp new file mode 100644 index 0000000000..41494694de --- /dev/null +++ b/qpid/cpp/src/qpid/ha/PrimaryTxObserver.cpp @@ -0,0 +1,227 @@ +/* + * + * 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 "Event.h" +#include "HaBroker.h" +#include "Primary.h" +#include "PrimaryTxObserver.h" +#include "QueueGuard.h" +#include "RemoteBackup.h" +#include "ReplicatingSubscription.h" +#include "QueueReplicator.h" + +#include "qpid/broker/Broker.h" +#include "qpid/broker/Queue.h" +#include <boost/lexical_cast.hpp> +#include <algorithm> + +namespace qpid { +namespace framing { +class FieldTable; +} +namespace ha { + +using namespace std; +using namespace qpid::broker; +using namespace qpid::framing; + +// Exchange to receive prepare OK events. +class PrimaryTxObserver::Exchange : public broker::Exchange { + public: + Exchange(const boost::shared_ptr<PrimaryTxObserver>& tx_) : + broker::Exchange(tx_->getExchangeName()), + tx(tx_) + { + dispatch[TxPrepareOkEvent::KEY] = + boost::bind(&PrimaryTxObserver::txPrepareOkEvent, tx, _1); + dispatch[TxPrepareFailEvent::KEY] = + boost::bind(&PrimaryTxObserver::txPrepareFailEvent, tx, _1); + } + + void route(Deliverable& deliverable) { + const broker::Message& message(deliverable.getMessage()); + DispatchMap::iterator i = dispatch.find(message.getRoutingKey()); + if (i != dispatch.end()) i->second(message.getContent()); + } + + bool bind(boost::shared_ptr<Queue>, const string&, const FieldTable*) { return false; } + bool unbind(boost::shared_ptr<Queue>, const string&, const FieldTable*) { return false; } + bool isBound(boost::shared_ptr<Queue>, const string* const, const FieldTable* const) { return false; } + string getType() const { return TYPE_NAME; } + + private: + static const string TYPE_NAME; + typedef boost::function<void(const std::string&)> DispatchFn; + typedef qpid::sys::unordered_map<std::string, DispatchFn> DispatchMap; + + DispatchMap dispatch; + boost::shared_ptr<PrimaryTxObserver> tx; +}; + +const string PrimaryTxObserver::Exchange::TYPE_NAME(string(QPID_HA_PREFIX)+"primary-tx-observer"); + +PrimaryTxObserver::PrimaryTxObserver(HaBroker& hb) : + haBroker(hb), broker(hb.getBroker()), + replicationTest(hb.getSettings().replicateDefault.get()), + id(true), + exchangeName(TRANSACTION_REPLICATOR_PREFIX+id.str()), + failed(false), ended(false), complete(false) +{ + logPrefix = "Primary transaction "+shortStr(id)+": "; + + // The brokers known at this point are the ones that will be included + // in the transaction. Brokers that join later are not included. + // + BrokerInfo::Set backups(haBroker.getMembership().otherBackups()); + std::transform(backups.begin(), backups.end(), inserter(members, members.begin()), + boost::bind(&BrokerInfo::getSystemId, _1)); + + QPID_LOG(debug, logPrefix << "Started TX " << id); + QPID_LOG(debug, logPrefix << "Members: " << members); + unprepared = unfinished = members; + + pair<QueuePtr, bool> result = + broker.getQueues().declare( + exchangeName, QueueSettings(/*durable*/false, /*autodelete*/true)); + assert(result.second); + txQueue = result.first; + txQueue->deliver(TxMembersEvent(members).message()); +} + +PrimaryTxObserver::~PrimaryTxObserver() {} + + +void PrimaryTxObserver::initialize() { + boost::shared_ptr<Exchange> ex(new Exchange(shared_from_this())); + FieldTable args = ex->getArgs(); + args.setString(QPID_REPLICATE, printable(NONE).str()); // Set replication arg. + broker.getExchanges().registerExchange(ex); +} + +void PrimaryTxObserver::enqueue(const QueuePtr& q, const broker::Message& m) +{ + sys::Mutex::ScopedLock l(lock); + if (replicationTest.useLevel(*q) == ALL) { // Ignore unreplicated queues. + QPID_LOG(trace, logPrefix << "Enqueue: " << LogMessageId(*q, m)); + enqueues[q] += m.getReplicationId(); + txQueue->deliver(TxEnqueueEvent(q->getName(), m.getReplicationId()).message()); + txQueue->deliver(m); + } +} + +void PrimaryTxObserver::dequeue( + const QueuePtr& q, QueuePosition pos, ReplicationId id) +{ + sys::Mutex::ScopedLock l(lock); + if (replicationTest.useLevel(*q) == ALL) { // Ignore unreplicated queues. + QPID_LOG(trace, logPrefix << "Dequeue: " << LogMessageId(*q, pos, id)); + txQueue->deliver(TxDequeueEvent(q->getName(), id).message()); + } + else { + QPID_LOG(warning, logPrefix << "Dequeue skipped, queue not replicated: " + << LogMessageId(*q, pos, id)); + } +} + +void PrimaryTxObserver::deduplicate(sys::Mutex::ScopedLock&) { + boost::shared_ptr<Primary> primary(boost::dynamic_pointer_cast<Primary>(haBroker.getRole())); + assert(primary); + // Tell replicating subscriptions to skip IDs in the transaction. + for (UuidSet::iterator b = members.begin(); b != members.end(); ++b) + for (QueueIdsMap::iterator q = enqueues.begin(); q != enqueues.end(); ++q) + primary->skip(*b, q->first, q->second); +} + +bool PrimaryTxObserver::prepare() { + sys::Mutex::ScopedLock l(lock); + QPID_LOG(debug, logPrefix << "Prepare"); + deduplicate(l); + txQueue->deliver(TxPrepareEvent().message()); + // TODO aconway 2013-09-04: Blocks the current thread till backups respond. + // Need a non-blocking approach (e.g. async completion or borrowing a thread) + while (!unprepared.empty() && !failed) lock.wait(); + return !failed; +} + +void PrimaryTxObserver::commit() { + sys::Mutex::ScopedLock l(lock); + QPID_LOG(debug, logPrefix << "Commit"); + txQueue->deliver(TxCommitEvent().message()); + complete = true; + end(l); +} + +void PrimaryTxObserver::rollback() { + sys::Mutex::ScopedLock l(lock); + QPID_LOG(debug, logPrefix << "Rollback"); + txQueue->deliver(TxRollbackEvent().message()); + complete = true; + end(l); +} + +void PrimaryTxObserver::end(sys::Mutex::ScopedLock&) { + // Don't destroy the tx-queue until the transaction is complete and there + // are no connected subscriptions. + if (!ended && complete && unfinished.empty()) { + ended = true; + try { + haBroker.getBroker().deleteQueue(txQueue->getName(), haBroker.getUserId(), string()); + } catch (const std::exception& e) { + QPID_LOG(error, logPrefix << "Deleting transaction queue: " << e.what()); + } + try { + broker.getExchanges().destroy(getExchangeName()); + } catch (const std::exception& e) { + QPID_LOG(error, logPrefix << "Deleting transaction exchange: " << e.what()); + } + } +} + +void PrimaryTxObserver::txPrepareOkEvent(const string& data) { + sys::Mutex::ScopedLock l(lock); + types::Uuid backup = decodeStr<TxPrepareOkEvent>(data).broker; + QPID_LOG(debug, logPrefix << "Backup prepared ok: " << backup); + unprepared.erase(backup); + lock.notify(); +} + +void PrimaryTxObserver::txPrepareFailEvent(const string& data) { + sys::Mutex::ScopedLock l(lock); + types::Uuid backup = decodeStr<TxPrepareFailEvent>(data).broker; + QPID_LOG(error, logPrefix << "Backup prepare failed: " << backup); + unprepared.erase(backup); + failed = true; + lock.notify(); +} + +void PrimaryTxObserver::cancel(const ReplicatingSubscription& rs) { + sys::Mutex::ScopedLock l(lock); + types::Uuid backup = rs.getBrokerInfo().getSystemId(); + if (unprepared.find(backup) != unprepared.end()) { + complete = failed = true; // Canceled before prepared. + unprepared.erase(backup); // Consider it prepared-fail + } + unfinished.erase(backup); + lock.notify(); + end(l); +} + +}} // namespace qpid::ha diff --git a/qpid/cpp/src/qpid/ha/PrimaryTxObserver.h b/qpid/cpp/src/qpid/ha/PrimaryTxObserver.h new file mode 100644 index 0000000000..fb9db25e85 --- /dev/null +++ b/qpid/cpp/src/qpid/ha/PrimaryTxObserver.h @@ -0,0 +1,115 @@ +#ifndef QPID_HA_PRIMARYTXOBSERVER_H +#define QPID_HA_PRIMARYTXOBSERVER_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 "types.h" +#include "ReplicationTest.h" +#include "qpid/broker/TransactionObserver.h" +#include "qpid/log/Statement.h" +#include "qpid/types/Uuid.h" +#include "qpid/sys/unordered_map.h" +#include "qpid/sys/Monitor.h" +#include <boost/enable_shared_from_this.hpp> + +namespace qpid { + +namespace broker { +class Broker; +class Message; +class Consumer; +} + +namespace ha { +class HaBroker; +class ReplicatingSubscription; + +/** + * Observe events in the lifecycle of a transaction. + * + * The observer is called by TxBuffer for each transactional event. + * It puts the events on a special tx-queue. + * A TxReplicator on the backup replicates the tx-queue and creates + * a TxBuffer on the backup equivalent to the one on the primary. + * + * Also observes the tx-queue for prepare-complete messages and + * subscription cancellations. + * + * THREAD SAFE: called in user connection thread for TX events, + * and in backup connection threads for prepare-completed events + * and unsubscriptions. + */ +class PrimaryTxObserver : public broker::TransactionObserver, + public boost::enable_shared_from_this<PrimaryTxObserver> +{ + public: + PrimaryTxObserver(HaBroker&); + ~PrimaryTxObserver(); + + /** Call immediately after constructor, uses shared_from_this. */ + void initialize(); + + void enqueue(const QueuePtr&, const broker::Message&); + void dequeue(const QueuePtr& queue, QueuePosition, ReplicationId); + bool prepare(); + void commit(); + void rollback(); + + types::Uuid getId() const { return id; } + QueuePtr getTxQueue() const { return txQueue; } + std::string getExchangeName() const { return exchangeName; } + + // Notify that a backup subscription has been cancelled. + void cancel(const ReplicatingSubscription&); + + private: + class Exchange; + typedef qpid::sys::unordered_map< + QueuePtr, ReplicationIdSet, Hasher<QueuePtr> > QueueIdsMap; + + void membership(const BrokerInfo::Map&); + void deduplicate(sys::Mutex::ScopedLock&); + void end(sys::Mutex::ScopedLock&); + void txPrepareOkEvent(const std::string& data); + void txPrepareFailEvent(const std::string& data); + + + sys::Monitor lock; + std::string logPrefix; + HaBroker& haBroker; + broker::Broker& broker; + ReplicationTest replicationTest; + + types::Uuid id; + std::string exchangeName; + QueuePtr txQueue; + QueueIdsMap enqueues; + bool failed, ended, complete; + + UuidSet members; // All members of transaction. + UuidSet unprepared; // Members that have not yet responded to prepare. + UuidSet unfinished; // Members that have not yet disconnected. +}; + +}} // namespace qpid::ha + +#endif /*!QPID_HA_PRIMARYTXOBSERVER_H*/ diff --git a/qpid/cpp/src/qpid/ha/QueueGuard.h b/qpid/cpp/src/qpid/ha/QueueGuard.h index e41a92c74f..33967970eb 100644 --- a/qpid/cpp/src/qpid/ha/QueueGuard.h +++ b/qpid/cpp/src/qpid/ha/QueueGuard.h @@ -89,7 +89,7 @@ class QueueGuard { class QueueObserver; typedef qpid::sys::unordered_map<ReplicationId, boost::intrusive_ptr<broker::AsyncCompletion>, - TrivialHasher<ReplicationId> > Delayed; + Hasher<ReplicationId> > Delayed; bool complete(ReplicationId, sys::Mutex::ScopedLock &); void complete(Delayed::iterator, sys::Mutex::ScopedLock &); diff --git a/qpid/cpp/src/qpid/ha/QueueReplicator.cpp b/qpid/cpp/src/qpid/ha/QueueReplicator.cpp index d99602fdda..22af7284a8 100644 --- a/qpid/cpp/src/qpid/ha/QueueReplicator.cpp +++ b/qpid/cpp/src/qpid/ha/QueueReplicator.cpp @@ -19,12 +19,13 @@ * */ -#include "makeMessage.h" +#include "Event.h" #include "HaBroker.h" #include "QueueReplicator.h" #include "QueueSnapshots.h" #include "ReplicatingSubscription.h" #include "Settings.h" +#include "types.h" #include "qpid/broker/Bridge.h" #include "qpid/broker/Broker.h" #include "qpid/broker/Link.h" @@ -38,36 +39,31 @@ #include "qpid/Msg.h" #include "qpid/assert.h" #include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> -namespace { -const std::string QPID_REPLICATOR_("qpid.replicator-"); -const std::string TYPE_NAME("qpid.queue-replicator"); -const std::string QPID_HA("qpid.ha-"); -} namespace qpid { namespace ha { using namespace broker; using namespace framing; using namespace std; +using std::exception; using sys::Mutex; -const std::string QueueReplicator::DEQUEUE_EVENT_KEY(QPID_HA+"dequeue"); -const std::string QueueReplicator::ID_EVENT_KEY(QPID_HA+"id"); const std::string QueueReplicator::QPID_SYNC_FREQUENCY("qpid.sync_frequency"); -std::string QueueReplicator::replicatorName(const std::string& queueName) { - return QPID_REPLICATOR_ + queueName; +namespace { +const string QPID_HA(QPID_HA_PREFIX); +const std::string TYPE_NAME(QPID_HA+"queue-replicator"); } -bool QueueReplicator::isReplicatorName(const std::string& name) { - return name.compare(0, QPID_REPLICATOR_.size(), QPID_REPLICATOR_) == 0; + +std::string QueueReplicator::replicatorName(const std::string& queueName) { + return QUEUE_REPLICATOR_PREFIX + queueName; } -bool QueueReplicator::isEventKey(const std::string key) { - const std::string& prefix = QPID_HA; - bool ret = key.size() > prefix.size() && key.compare(0, prefix.size(), prefix) == 0; - return ret; +bool QueueReplicator::isReplicatorName(const std::string& name) { + return startsWith(name, QUEUE_REPLICATOR_PREFIX); } class QueueReplicator::ErrorListener : public SessionHandler::ErrorListener { @@ -109,12 +105,15 @@ QueueReplicator::QueueReplicator(HaBroker& hb, boost::shared_ptr<Link> l) : Exchange(replicatorName(q->getName()), 0, q->getBroker()), haBroker(hb), + brokerInfo(hb.getBrokerInfo()), + link(l), + queue(q), + sessionHandler(0), logPrefix("Backup of "+q->getName()+": "), - queue(q), link(l), brokerInfo(hb.getBrokerInfo()), subscribed(false), - settings(hb.getSettings()), destroyed(false), + subscribed(false), + settings(hb.getSettings()), nextId(0), maxId(0) { - QPID_LOG(debug, logPrefix << "Created"); args.setString(QPID_REPLICATE, printable(NONE).str()); Uuid uuid(true); bridgeName = replicatorName(q->getName()) + std::string(".") + uuid.str(); @@ -122,12 +121,18 @@ QueueReplicator::QueueReplicator(HaBroker& hb, args.setString(QPID_REPLICATE, printable(NONE).str()); setArgs(args); if (q->isAutoDelete()) q->markInUse(); + + dispatch[DequeueEvent::KEY] = + boost::bind(&QueueReplicator::dequeueEvent, this, _1, _2); + dispatch[IdEvent::KEY] = + boost::bind(&QueueReplicator::idEvent, this, _1, _2); } // This must be called immediately after the constructor. // It has to be separate so we can call shared_from_this(). void QueueReplicator::activate() { Mutex::ScopedLock l(lock); + QPID_LOG(debug, logPrefix << "Created"); if (!queue) return; // Already destroyed // Enable callback to route() @@ -163,6 +168,11 @@ void QueueReplicator::activate() { boost::shared_ptr<QueueObserver>(new QueueObserver(shared_from_this()))); } +void QueueReplicator::disconnect() { + Mutex::ScopedLock l(lock); + sessionHandler = 0; +} + QueueReplicator::~QueueReplicator() {} // Called from Queue::destroyed() @@ -170,25 +180,24 @@ void QueueReplicator::destroy() { boost::shared_ptr<Bridge> bridge2; // To call outside of lock { Mutex::ScopedLock l(lock); - if (destroyed) return; - destroyed = true; + if (!queue) return; // Already destroyed QPID_LOG(debug, logPrefix << "Destroyed"); + bridge2 = bridge; // call close outside the lock. // Need to drop shared pointers to avoid pointer cycles keeping this in memory. queue.reset(); - link.reset(); bridge.reset(); getBroker()->getExchanges().destroy(getName()); - bridge2 = bridge; } if (bridge2) bridge2->close(); // Outside of lock, avoid deadlock. } // Called in a broker connection thread when the bridge is created. // Note: called with the Link lock held. -void QueueReplicator::initializeBridge(Bridge& bridge, SessionHandler& sessionHandler) { +void QueueReplicator::initializeBridge(Bridge& bridge, SessionHandler& sessionHandler_) { Mutex::ScopedLock l(lock); - if (destroyed) return; // Already destroyed - AMQP_ServerProxy peer(sessionHandler.out); + if (!queue) return; // Already destroyed + sessionHandler = &sessionHandler_; + AMQP_ServerProxy peer(sessionHandler->out); const qmf::org::apache::qpid::broker::ArgsLinkBridge& args(bridge.getArgs()); FieldTable arguments; arguments.setInt(ReplicatingSubscription::QPID_REPLICATING_SUBSCRIPTION, 1); @@ -224,44 +233,57 @@ template <class T> T decodeContent(Message& m) { } } -void QueueReplicator::dequeue(const ReplicationIdSet& dequeues, Mutex::ScopedLock&) { - QPID_LOG(trace, logPrefix << "Dequeue " << dequeues); +void QueueReplicator::dequeueEvent(const string& data, Mutex::ScopedLock&) { + DequeueEvent e; + decodeStr(data, e); + QPID_LOG(trace, logPrefix << "Dequeue " << e.ids); //TODO: should be able to optimise the following - for (ReplicationIdSet::iterator i = dequeues.begin(); i != dequeues.end(); ++i) { + for (ReplicationIdSet::iterator i = e.ids.begin(); i != e.ids.end(); ++i) { PositionMap::iterator j = positions.find(*i); if (j != positions.end()) queue->dequeueMessageAt(j->second); } } // Called in connection thread of the queues bridge to primary. -void QueueReplicator::route(Deliverable& msg) +void QueueReplicator::route(Deliverable& deliverable) { try { Mutex::ScopedLock l(lock); - if (destroyed) return; - const std::string& key = msg.getMessage().getRoutingKey(); - if (!isEventKey(key)) { // Replicated message + if (!queue) return; // Already destroyed + broker::Message& message(deliverable.getMessage()); + string key(message.getRoutingKey()); + if (!isEventKey(message.getRoutingKey())) { ReplicationId id = nextId++; maxId = std::max(maxId, id); - msg.getMessage().setReplicationId(id); - msg.deliverTo(queue); + message.setReplicationId(id); + deliver(message); QueuePosition position = queue->getPosition(); positions[id] = position; QPID_LOG(trace, logPrefix << "Enqueued " << LogMessageId(*queue,position,id)); } - else if (key == DEQUEUE_EVENT_KEY) { - dequeue(decodeContent<ReplicationIdSet>(msg.getMessage()), l); - } - else if (key == ID_EVENT_KEY) { - nextId = decodeContent<ReplicationId>(msg.getMessage()); + else { + DispatchMap::iterator i = dispatch.find(key); + if (i == dispatch.end()) { + QPID_LOG(info, logPrefix << "Ignoring unknown event: " << key); + } + else { + (i->second)(message.getContent(), l); + } } - // Ignore unknown event keys, may be introduced in later versions. } catch (const std::exception& e) { haBroker.shutdown(QPID_MSG(logPrefix << "Replication failed: " << e.what())); } } +void QueueReplicator::deliver(const broker::Message& m) { + queue->deliver(m); +} + +void QueueReplicator::idEvent(const string& data, Mutex::ScopedLock&) { + nextId = decodeStr<IdEvent>(data).id; +} + ReplicationId QueueReplicator::getMaxId() { Mutex::ScopedLock l(lock); return maxId; @@ -273,4 +295,5 @@ bool QueueReplicator::unbind(boost::shared_ptr<Queue>, const std::string&, const bool QueueReplicator::isBound(boost::shared_ptr<Queue>, const std::string* const, const FieldTable* const) { return false; } std::string QueueReplicator::getType() const { return TYPE_NAME; } + }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/ha/QueueReplicator.h b/qpid/cpp/src/qpid/ha/QueueReplicator.h index 811ddba256..01abc88843 100644 --- a/qpid/cpp/src/qpid/ha/QueueReplicator.h +++ b/qpid/cpp/src/qpid/ha/QueueReplicator.h @@ -26,6 +26,7 @@ #include "hash.h" #include "qpid/broker/Exchange.h" #include <boost/enable_shared_from_this.hpp> +#include <boost/function.hpp> #include <iosfwd> namespace qpid { @@ -56,30 +57,24 @@ class QueueReplicator : public broker::Exchange, public boost::enable_shared_from_this<QueueReplicator> { public: - static const std::string DEQUEUE_EVENT_KEY; - static const std::string ID_EVENT_KEY; static const std::string QPID_SYNC_FREQUENCY; + static const std::string REPLICATOR_PREFIX; static std::string replicatorName(const std::string& queueName); static bool isReplicatorName(const std::string&); - /** Test if a string is an event key */ - static bool isEventKey(const std::string key); - QueueReplicator(HaBroker&, boost::shared_ptr<broker::Queue> q, boost::shared_ptr<broker::Link> l); ~QueueReplicator(); - void activate(); // Must be called immediately after constructor. + void activate(); // Must be called immediately after constructor. + void disconnect(); // Called when we are disconnected from the primary. std::string getType() const; - bool bind(boost::shared_ptr<broker::Queue - >, const std::string&, const framing::FieldTable*); - bool unbind(boost::shared_ptr<broker::Queue>, const std::string&, const framing::FieldTable*); + void route(broker::Deliverable&); - bool isBound(boost::shared_ptr<broker::Queue>, const std::string* const, const framing::FieldTable* const); // Set if the queue has ever been subscribed to, used for auto-delete cleanup. void setSubscribed() { subscribed = true; } @@ -89,27 +84,44 @@ class QueueReplicator : public broker::Exchange, ReplicationId getMaxId(); - private: - typedef qpid::sys::unordered_map<ReplicationId, QueuePosition, TrivialHasher<int32_t> > PositionMap; + // No-op unused Exchange virtual functions. + bool bind(boost::shared_ptr<broker::Queue>, const std::string&, const framing::FieldTable*); + bool unbind(boost::shared_ptr<broker::Queue>, const std::string&, const framing::FieldTable*); + bool isBound(boost::shared_ptr<broker::Queue>, const std::string* const, const framing::FieldTable* const); + + protected: + typedef boost::function<void(const std::string&, sys::Mutex::ScopedLock&)> DispatchFn; + typedef qpid::sys::unordered_map<std::string, DispatchFn> DispatchMap; + + virtual void deliver(const broker::Message&); + virtual void destroy(); // Called when the queue is destroyed. + sys::Mutex lock; + HaBroker& haBroker; + const BrokerInfo brokerInfo; + DispatchMap dispatch; + boost::shared_ptr<broker::Link> link; + boost::shared_ptr<broker::Bridge> bridge; + boost::shared_ptr<broker::Queue> queue; + broker::SessionHandler* sessionHandler; + + private: + typedef qpid::sys::unordered_map< + ReplicationId, QueuePosition, Hasher<ReplicationId> > PositionMap; class ErrorListener; class QueueObserver; void initializeBridge(broker::Bridge& bridge, broker::SessionHandler& sessionHandler); - void destroy(); // Called when the queue is destroyed. - void dequeue(const ReplicationIdSet&, sys::Mutex::ScopedLock&); - HaBroker& haBroker; + // Dispatch functions + void dequeueEvent(const std::string& data, sys::Mutex::ScopedLock&); + void idEvent(const std::string& data, sys::Mutex::ScopedLock&); + std::string logPrefix; std::string bridgeName; - sys::Mutex lock; - boost::shared_ptr<broker::Queue> queue; - boost::shared_ptr<broker::Link> link; - boost::shared_ptr<broker::Bridge> bridge; - BrokerInfo brokerInfo; + bool subscribed; const Settings& settings; - bool destroyed; PositionMap positions; ReplicationIdSet idSet; // Set of replicationIds on the queue. ReplicationId nextId; // ID for next message to arrive. diff --git a/qpid/cpp/src/qpid/ha/QueueSnapshots.h b/qpid/cpp/src/qpid/ha/QueueSnapshots.h index 258c406954..d067b983d1 100644 --- a/qpid/cpp/src/qpid/ha/QueueSnapshots.h +++ b/qpid/cpp/src/qpid/ha/QueueSnapshots.h @@ -27,7 +27,7 @@ #include "hash.h" #include "qpid/assert.h" -#include "qpid/broker/ConfigurationObserver.h" +#include "qpid/broker/BrokerObserver.h" #include "qpid/broker/Queue.h" #include "qpid/sys/Mutex.h" @@ -37,10 +37,10 @@ namespace qpid { namespace ha { /** - * ConfigurationObserver that maintains a map of the QueueSnapshot for each queue. + * BrokerObserver that maintains a map of the QueueSnapshot for each queue. * THREAD SAFE. */ -class QueueSnapshots : public broker::ConfigurationObserver +class QueueSnapshots : public broker::BrokerObserver { public: boost::shared_ptr<QueueSnapshot> get(const boost::shared_ptr<broker::Queue>& q) const { @@ -49,7 +49,7 @@ class QueueSnapshots : public broker::ConfigurationObserver return i != snapshots.end() ? i->second : boost::shared_ptr<QueueSnapshot>(); } - // ConfigurationObserver overrides. + // BrokerObserver overrides. void queueCreate(const boost::shared_ptr<broker::Queue>& q) { sys::Mutex::ScopedLock l(lock); boost::shared_ptr<QueueSnapshot> observer(new QueueSnapshot); @@ -69,7 +69,7 @@ class QueueSnapshots : public broker::ConfigurationObserver private: typedef qpid::sys::unordered_map<boost::shared_ptr<broker::Queue>, boost::shared_ptr<QueueSnapshot>, - SharedPtrHasher<broker::Queue> + Hasher<boost::shared_ptr<broker::Queue> > > SnapshotMap; SnapshotMap snapshots; mutable sys::Mutex lock; diff --git a/qpid/cpp/src/qpid/ha/RemoteBackup.cpp b/qpid/cpp/src/qpid/ha/RemoteBackup.cpp index c37d44fa08..0993c6ea39 100644 --- a/qpid/cpp/src/qpid/ha/RemoteBackup.cpp +++ b/qpid/cpp/src/qpid/ha/RemoteBackup.cpp @@ -20,6 +20,7 @@ */ #include "RemoteBackup.h" #include "QueueGuard.h" +#include "TxReplicator.h" #include "qpid/broker/Broker.h" #include "qpid/broker/Connection.h" #include "qpid/broker/Queue.h" @@ -108,13 +109,13 @@ void RemoteBackup::ready(const QueuePtr& q) { QPID_LOG(debug, logPrefix << "Caught up on queue: " << q->getName() ); } -// Called via ConfigurationObserver::queueCreate and from catchupQueue +// Called via BrokerObserver::queueCreate and from catchupQueue void RemoteBackup::queueCreate(const QueuePtr& q) { if (replicationTest.getLevel(*q) == ALL) guards[q].reset(new QueueGuard(*q, brokerInfo)); } -// Called via ConfigurationObserver +// Called via BrokerObserver void RemoteBackup::queueDestroy(const QueuePtr& q) { catchupQueues.erase(q); GuardMap::iterator i = guards.find(q); diff --git a/qpid/cpp/src/qpid/ha/RemoteBackup.h b/qpid/cpp/src/qpid/ha/RemoteBackup.h index e2c5032820..b9e2e1a496 100644 --- a/qpid/cpp/src/qpid/ha/RemoteBackup.h +++ b/qpid/cpp/src/qpid/ha/RemoteBackup.h @@ -71,10 +71,10 @@ class RemoteBackup */ void ready(const QueuePtr& queue); - /** Called via ConfigurationObserver */ + /** Called via BrokerObserver */ void queueCreate(const QueuePtr&); - /** Called via ConfigurationObserver. Note: may set isReady() */ + /** Called via BrokerObserver. Note: may set isReady() */ void queueDestroy(const QueuePtr&); /**@return true when all catch-up queues for this backup are ready. */ @@ -96,8 +96,10 @@ class RemoteBackup void startCatchup() { started = true; } private: - typedef qpid::sys::unordered_map<QueuePtr, GuardPtr, - SharedPtrHasher<broker::Queue> > GuardMap; + typedef qpid::sys::unordered_map< + QueuePtr, GuardPtr, Hasher<boost::shared_ptr<broker::Queue> > + > GuardMap; + typedef std::set<QueuePtr> QueueSet; std::string logPrefix; diff --git a/qpid/cpp/src/qpid/ha/ReplicatingSubscription.cpp b/qpid/cpp/src/qpid/ha/ReplicatingSubscription.cpp index 1ede47ed60..cdfe9dd888 100644 --- a/qpid/cpp/src/qpid/ha/ReplicatingSubscription.cpp +++ b/qpid/cpp/src/qpid/ha/ReplicatingSubscription.cpp @@ -19,7 +19,7 @@ * */ -#include "makeMessage.h" +#include "Event.h" #include "IdSetter.h" #include "QueueGuard.h" #include "QueueReplicator.h" @@ -111,7 +111,8 @@ ReplicatingSubscription::ReplicatingSubscription( ) : ConsumerImpl(parent, name, queue, ack, REPLICATOR, exclusive, tag, resumeId, resumeTtl, arguments), position(0), ready(false), cancelled(false), - haBroker(hb) + haBroker(hb), + primary(boost::dynamic_pointer_cast<Primary>(haBroker.getRole())) { try { FieldTable ft; @@ -137,7 +138,7 @@ ReplicatingSubscription::ReplicatingSubscription( } // If there's already a guard (we are in failover) use it, else create one. - if (Primary::get()) guard = Primary::get()->getGuard(queue, info); + if (primary) guard = primary->getGuard(queue, info); if (!guard) guard.reset(new QueueGuard(*queue, info)); // NOTE: Once the observer is attached we can have concurrent @@ -148,20 +149,19 @@ ReplicatingSubscription::ReplicatingSubscription( // between the snapshot and attaching the observer. observer.reset(new QueueObserver(*this)); queue->addObserver(observer); - ReplicationIdSet primary = haBroker.getQueueSnapshots()->get(queue)->snapshot(); + ReplicationIdSet primaryIds = haBroker.getQueueSnapshots()->get(queue)->snapshot(); std::string backupStr = arguments.getAsString(ReplicatingSubscription::QPID_ID_SET); - ReplicationIdSet backup; - if (!backupStr.empty()) backup = decodeStr<ReplicationIdSet>(backupStr); + ReplicationIdSet backupIds; + if (!backupStr.empty()) backupIds = decodeStr<ReplicationIdSet>(backupStr); // Initial dequeues are messages on backup but not on primary. - ReplicationIdSet initDequeues = backup - primary; + ReplicationIdSet initDequeues = backupIds - primaryIds; QueuePosition front,back; queue->getRange(front, back, broker::REPLICATOR); // Outside lock, getRange locks queue { sys::Mutex::ScopedLock l(lock); // Concurrent calls to dequeued() dequeues += initDequeues; // Messages on backup that are not on primary. - skip = backup - initDequeues; // Messages already on the backup. - + skip = backupIds - initDequeues; // Messages already on the backup. // Queue front is moving but we know this subscriptions will start at a // position >= front so if front is safe then position must be. position = front; @@ -189,6 +189,7 @@ ReplicatingSubscription::~ReplicatingSubscription() {} // void ReplicatingSubscription::initialize() { try { + if (primary) primary->addReplica(*this); Mutex::ScopedLock l(lock); // Note dequeued() can be called concurrently. // Send initial dequeues to the backup. // There must be a shared_ptr(this) when sending. @@ -216,9 +217,8 @@ bool ReplicatingSubscription::deliver( try { bool result = false; if (skip.contains(id)) { + QPID_LOG(trace, logPrefix << "Skip " << LogMessageId(*getQueue(), m)); skip -= id; - QPID_LOG(trace, logPrefix << "On backup, skip " << - LogMessageId(*getQueue(), m)); guard->complete(id); // This will never be acknowledged. notify(); result = true; @@ -238,16 +238,13 @@ bool ReplicatingSubscription::deliver( } } -/** - *@param position: must be <= last position seen by subscription. - */ void ReplicatingSubscription::checkReady(sys::Mutex::ScopedLock& l) { if (!ready && isGuarded(l) && unready.empty()) { ready = true; sys::Mutex::ScopedUnlock u(lock); // Notify Primary that a subscription is ready. QPID_LOG(debug, logPrefix << "Caught up"); - if (Primary::get()) Primary::get()->readyReplica(*this); + if (primary) primary->readyReplica(*this); } } @@ -260,6 +257,7 @@ void ReplicatingSubscription::cancel() cancelled = true; } QPID_LOG(debug, logPrefix << "Cancelled"); + if (primary) primary->removeReplica(*this); getQueue()->removeObserver(observer); guard->cancel(); ConsumerImpl::cancel(); @@ -285,9 +283,7 @@ void ReplicatingSubscription::sendDequeueEvent(Mutex::ScopedLock& l) { if (dequeues.empty()) return; QPID_LOG(trace, logPrefix << "Sending dequeues " << dequeues); - string buffer = encodeStr(dequeues); - dequeues.clear(); - sendEvent(QueueReplicator::DEQUEUE_EVENT_KEY, buffer, l); + sendEvent(DequeueEvent(dequeues), l); } // Called after the message has been removed @@ -307,23 +303,16 @@ void ReplicatingSubscription::dequeued(ReplicationId id) // Called with lock held. Called in subscription's connection thread. void ReplicatingSubscription::sendIdEvent(ReplicationId pos, Mutex::ScopedLock& l) { - sendEvent(QueueReplicator::ID_EVENT_KEY, encodeStr(pos), l); + sendEvent(IdEvent(pos), l); } -void ReplicatingSubscription::sendEvent(const std::string& key, - const std::string& buffer, - Mutex::ScopedLock&) +void ReplicatingSubscription::sendEvent(const Event& event, Mutex::ScopedLock&) { Mutex::ScopedUnlock u(lock); - broker::Message message = makeMessage(buffer); - MessageTransfer& transfer = MessageTransfer::get(message); - DeliveryProperties* props = - transfer.getFrames().getHeaders()->get<DeliveryProperties>(true); - props->setRoutingKey(key); // Send the event directly to the base consumer implementation. The dummy // consumer prevents acknowledgements being handled, which is what we want // for events - ConsumerImpl::deliver(QueueCursor(), message, boost::shared_ptr<Consumer>()); + ConsumerImpl::deliver(QueueCursor(), event.message(), boost::shared_ptr<Consumer>()); } // Called in subscription's connection thread. @@ -342,4 +331,9 @@ bool ReplicatingSubscription::doDispatch() } } +void ReplicatingSubscription::addSkip(const ReplicationIdSet& ids) { + Mutex::ScopedLock l(lock); + skip += ids; +} + }} // namespace qpid::ha diff --git a/qpid/cpp/src/qpid/ha/ReplicatingSubscription.h b/qpid/cpp/src/qpid/ha/ReplicatingSubscription.h index c202089e91..71993bcb12 100644 --- a/qpid/cpp/src/qpid/ha/ReplicatingSubscription.h +++ b/qpid/cpp/src/qpid/ha/ReplicatingSubscription.h @@ -25,7 +25,6 @@ #include "BrokerInfo.h" #include "qpid/broker/SemanticState.h" #include "qpid/broker/ConsumerFactory.h" -#include "qpid/types/Uuid.h" #include <iosfwd> namespace qpid { @@ -44,6 +43,8 @@ class Buffer; namespace ha { class QueueGuard; class HaBroker; +class Event; +class Primary; /** * A susbcription that replicates to a remote backup. @@ -118,6 +119,9 @@ class ReplicatingSubscription : public broker::SemanticState::ConsumerImpl BrokerInfo getBrokerInfo() const { return info; } + /** Skip replicating enqueue of of ids. */ + void addSkip(const ReplicationIdSet& ids); + protected: bool doDispatch(); @@ -128,7 +132,7 @@ class ReplicatingSubscription : public broker::SemanticState::ConsumerImpl std::string logPrefix; QueuePosition position; ReplicationIdSet dequeues; // Dequeues to be sent in next dequeue event. - ReplicationIdSet skip; // Messages already on backup will be skipped. + ReplicationIdSet skip; // Skip enqueues: messages already on backup and tx enqueues. ReplicationIdSet unready; // Unguarded, replicated and un-acknowledged. bool ready; bool cancelled; @@ -136,12 +140,13 @@ class ReplicatingSubscription : public broker::SemanticState::ConsumerImpl boost::shared_ptr<QueueGuard> guard; HaBroker& haBroker; boost::shared_ptr<QueueObserver> observer; + boost::shared_ptr<Primary> primary; bool isGuarded(sys::Mutex::ScopedLock&); void dequeued(ReplicationId); void sendDequeueEvent(sys::Mutex::ScopedLock&); void sendIdEvent(ReplicationId, sys::Mutex::ScopedLock&); - void sendEvent(const std::string& key, const std::string& data, sys::Mutex::ScopedLock&); + void sendEvent(const Event&, sys::Mutex::ScopedLock&); void checkReady(sys::Mutex::ScopedLock&); friend class Factory; }; diff --git a/qpid/cpp/src/qpid/ha/ReplicationTest.h b/qpid/cpp/src/qpid/ha/ReplicationTest.h index 7d44d82a21..c157385ce6 100644 --- a/qpid/cpp/src/qpid/ha/ReplicationTest.h +++ b/qpid/cpp/src/qpid/ha/ReplicationTest.h @@ -41,6 +41,13 @@ namespace ha { /** * Test whether something is replicated, taking into account the * default replication level. + * + * The primary uses a ReplicationTest with default based on configuration + * settings, and marks objects to be replicated with an explict replication + * argument. + * + * The backup uses a default of NONE, so it always accepts what the primary has + * marked on the object. */ class ReplicationTest { diff --git a/qpid/cpp/src/qpid/ha/StatusCheck.cpp b/qpid/cpp/src/qpid/ha/StatusCheck.cpp index d73f2cf8b5..fdc256d5a2 100644 --- a/qpid/cpp/src/qpid/ha/StatusCheck.cpp +++ b/qpid/cpp/src/qpid/ha/StatusCheck.cpp @@ -20,6 +20,8 @@ */ #include "StatusCheck.h" #include "ConnectionObserver.h" +#include "HaBroker.h" +#include "qpid/broker/Broker.h" #include "qpid/log/Statement.h" #include "qpid/messaging/Address.h" #include "qpid/messaging/Connection.h" @@ -41,27 +43,32 @@ const string HA_BROKER = "org.apache.qpid.ha:habroker:ha-broker"; class StatusCheckThread : public sys::Runnable { public: - StatusCheckThread(StatusCheck& sc, const qpid::Address& addr, const BrokerInfo& self) - : url(addr), statusCheck(sc), brokerInfo(self) {} + StatusCheckThread(StatusCheck& sc, const qpid::Address& addr) + : url(addr), statusCheck(sc) {} void run(); private: Url url; StatusCheck& statusCheck; - BrokerInfo brokerInfo; }; void StatusCheckThread::run() { - QPID_LOG(debug, statusCheck.logPrefix << "Checking status of " << url); + string logPrefix("Status check " + url.str() + ": "); Connection c; try { + // Check for self connections Variant::Map options, clientProperties; - clientProperties = brokerInfo.asMap(); // Detect self connections. clientProperties[ConnectionObserver::ADMIN_TAG] = 1; // Allow connection to backups. clientProperties[ConnectionObserver::ADDRESS_TAG] = url.str(); - clientProperties[ConnectionObserver::BACKUP_TAG] = brokerInfo.asMap(); + clientProperties[ConnectionObserver::BACKUP_TAG] = statusCheck.haBroker.getBrokerInfo().asMap(); + // Set connection options + Settings settings(statusCheck.haBroker.getSettings()); + if (settings.username.size()) options["username"] = settings.username; + if (settings.password.size()) options["password"] = settings.password; + if (settings.mechanism.size()) options["sasl_mechanisms"] = settings.mechanism; options["client-properties"] = clientProperties; - options["heartbeat"] = statusCheck.linkHeartbeatInterval/sys::TIME_SEC; + sys::Duration heartbeat(statusCheck.haBroker.getBroker().getOptions().linkHeartbeatInterval); + options["heartbeat"] = heartbeat/sys::TIME_SEC; c = Connection(url.str(), options); c.open(); @@ -81,7 +88,7 @@ void StatusCheckThread::run() { content["_object_id"] = oid; encode(content, request); s.send(request); - messaging::Duration timeout(statusCheck.linkHeartbeatInterval/sys::TIME_MSEC); + messaging::Duration timeout(heartbeat/sys::TIME_MSEC); Message response = r.fetch(timeout); session.acknowledge(); Variant::List contentIn; @@ -89,29 +96,24 @@ void StatusCheckThread::run() { if (contentIn.size() == 1) { Variant::Map details = contentIn.front().asMap()["_values"].asMap(); string status = details["status"].getString(); + QPID_LOG(debug, logPrefix << status); if (status != "joining") { statusCheck.setPromote(false); - QPID_LOG(info, statusCheck.logPrefix << "Status of " << url << " is " - << status << ", this broker will refuse promotion."); + QPID_LOG(info, logPrefix << "Joining established cluster"); } - QPID_LOG(debug, statusCheck.logPrefix << "Status of " << url << ": " << status); } + else + QPID_LOG(error, logPrefix << "Invalid response " << response.getContent()) } catch(const exception& error) { - QPID_LOG(info, statusCheck.logPrefix << "Checking status of " << url << ": " << error.what()); - } - try { c.close(); } - catch(const exception&) { - QPID_LOG(warning, statusCheck.logPrefix << "Error closing status check connection to " << url); - } - try { c.close(); } - catch(const exception&) { - QPID_LOG(warning, "Error closing status check connection to " << url); + // Its not an error to fail to connect to self. + if (statusCheck.haBroker.getBrokerInfo().getAddress() != url[0]) + QPID_LOG(warning, logPrefix << error.what()); } + try { c.close(); } catch(...) {} delete this; } -StatusCheck::StatusCheck(const string& lp, sys::Duration lh, const BrokerInfo& self) - : logPrefix(lp), promote(true), linkHeartbeatInterval(lh), brokerInfo(self) +StatusCheck::StatusCheck(HaBroker& hb) : promote(true), haBroker(hb) {} StatusCheck::~StatusCheck() { @@ -122,7 +124,7 @@ StatusCheck::~StatusCheck() { void StatusCheck::setUrl(const Url& url) { Mutex::ScopedLock l(lock); for (size_t i = 0; i < url.size(); ++i) - threads.push_back(Thread(new StatusCheckThread(*this, url[i], brokerInfo))); + threads.push_back(Thread(new StatusCheckThread(*this, url[i]))); } bool StatusCheck::canPromote() { diff --git a/qpid/cpp/src/qpid/ha/StatusCheck.h b/qpid/cpp/src/qpid/ha/StatusCheck.h index 65ad3cefcf..8896969f55 100644 --- a/qpid/cpp/src/qpid/ha/StatusCheck.h +++ b/qpid/cpp/src/qpid/ha/StatusCheck.h @@ -23,6 +23,7 @@ */ #include "BrokerInfo.h" +#include "Settings.h" #include "qpid/Url.h" #include "qpid/sys/Thread.h" #include "qpid/sys/Mutex.h" @@ -33,6 +34,8 @@ namespace qpid { namespace ha { +class HaBroker; + // TODO aconway 2012-12-21: This solution is incomplete. It will only protect // against bad promotion if there are READY brokers when this broker starts. // It will not help the situation where brokers became READY after this one starts. @@ -51,7 +54,7 @@ namespace ha { class StatusCheck { public: - StatusCheck(const std::string& logPrefix, sys::Duration linkHeartbeatInterval, const BrokerInfo& self); + StatusCheck(HaBroker&); ~StatusCheck(); void setUrl(const Url&); bool canPromote(); @@ -59,12 +62,11 @@ class StatusCheck private: void setPromote(bool p); - std::string logPrefix; sys::Mutex lock; std::vector<sys::Thread> threads; bool promote; - sys::Duration linkHeartbeatInterval; - BrokerInfo brokerInfo; + HaBroker& haBroker; + friend class StatusCheckThread; }; }} // namespace qpid::ha diff --git a/qpid/cpp/src/qpid/ha/TxReplicator.cpp b/qpid/cpp/src/qpid/ha/TxReplicator.cpp new file mode 100644 index 0000000000..63301a92f5 --- /dev/null +++ b/qpid/cpp/src/qpid/ha/TxReplicator.cpp @@ -0,0 +1,247 @@ +/* + * + * 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 "TxReplicator.h" +#include "Role.h" +#include "Backup.h" +#include "BrokerReplicator.h" +#include "Event.h" +#include "HaBroker.h" +#include "types.h" +#include "qpid/broker/Broker.h" +#include "qpid/broker/Link.h" +#include "qpid/broker/QueueRegistry.h" +#include "qpid/broker/Queue.h" +#include "qpid/broker/SessionHandler.h" +#include "qpid/broker/TxBuffer.h" +#include "qpid/broker/TxAccept.h" +#include "qpid/broker/amqp_0_10/Connection.h" +#include "qpid/broker/DeliverableMessage.h" +#include "qpid/framing/BufferTypes.h" +#include "qpid/log/Statement.h" +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> +#include "qpid/broker/amqp_0_10/MessageTransfer.h" +#include "qpid/framing/MessageTransferBody.h" + +namespace qpid { +namespace ha { + +using namespace std; +using namespace qpid::broker; +using namespace qpid::framing; +using qpid::broker::amqp_0_10::MessageTransfer; +using qpid::types::Uuid; + +namespace { +const string QPID_HA(QPID_HA_PREFIX); +const string TYPE_NAME(QPID_HA+"tx-replicator"); +const string PREFIX(TRANSACTION_REPLICATOR_PREFIX); + +} // namespace + + + +bool TxReplicator::isTxQueue(const string& q) { + return startsWith(q, PREFIX); +} + +string TxReplicator::getTxId(const string& q) { + assert(isTxQueue(q)); + return q.substr(PREFIX.size()); +} + +string TxReplicator::getType() const { return TYPE_NAME; } + +TxReplicator::TxReplicator( + HaBroker& hb, + const boost::shared_ptr<broker::Queue>& txQueue, + const boost::shared_ptr<broker::Link>& link) : + QueueReplicator(hb, txQueue, link), + txBuffer(new broker::TxBuffer), + store(hb.getBroker().hasStore() ? &hb.getBroker().getStore() : 0), + channel(link->nextChannel()), + complete(false), ignore(false), + dequeueState(hb.getBroker().getQueues()) +{ + string id(getTxId(txQueue->getName())); + string shortId = id.substr(0, 8); + logPrefix = "Backup of transaction "+shortId+": "; + QPID_LOG(debug, logPrefix << "Started TX " << id); + if (!store) throw Exception(QPID_MSG(logPrefix << "No message store loaded.")); + + // Dispatch transaction events. + dispatch[TxEnqueueEvent::KEY] = + boost::bind(&TxReplicator::enqueue, this, _1, _2); + dispatch[TxDequeueEvent::KEY] = + boost::bind(&TxReplicator::dequeue, this, _1, _2); + dispatch[TxPrepareEvent::KEY] = + boost::bind(&TxReplicator::prepare, this, _1, _2); + dispatch[TxCommitEvent::KEY] = + boost::bind(&TxReplicator::commit, this, _1, _2); + dispatch[TxRollbackEvent::KEY] = + boost::bind(&TxReplicator::rollback, this, _1, _2); + dispatch[TxMembersEvent::KEY] = + boost::bind(&TxReplicator::members, this, _1, _2); +} + +TxReplicator::~TxReplicator() { + link->returnChannel(channel); +} + +// Send a message to the primary tx. +void TxReplicator::sendMessage(const broker::Message& msg, sys::Mutex::ScopedLock&) { + assert(sessionHandler); + const MessageTransfer& transfer(MessageTransfer::get(msg)); + for (FrameSet::const_iterator i = transfer.getFrames().begin(); + i != transfer.getFrames().end(); + ++i) + { + sessionHandler->out.handle(const_cast<AMQFrame&>(*i)); + } +} + +void TxReplicator::route(broker::Deliverable& deliverable) { + if (!ignore) QueueReplicator::route(deliverable); +} + +void TxReplicator::deliver(const broker::Message& m_) { + sys::Mutex::ScopedLock l(lock); + // Deliver message to the target queue, not the tx-queue. + broker::Message m(m_); + m.setReplicationId(enq.id); // Use replicated id. + boost::shared_ptr<broker::Queue> queue = + haBroker.getBroker().getQueues().get(enq.queue); + QPID_LOG(trace, logPrefix << "Deliver " << LogMessageId(*queue, m)); + DeliverableMessage dm(m, txBuffer.get()); + dm.deliverTo(queue); +} + +void TxReplicator::enqueue(const string& data, sys::Mutex::ScopedLock&) { + sys::Mutex::ScopedLock l(lock); + TxEnqueueEvent e; + decodeStr(data, e); + QPID_LOG(trace, logPrefix << "Enqueue: " << e); + enq = e; +} + +void TxReplicator::dequeue(const string& data, sys::Mutex::ScopedLock&) { + sys::Mutex::ScopedLock l(lock); + TxDequeueEvent e; + decodeStr(data, e); + QPID_LOG(trace, logPrefix << "Dequeue: " << e); + // NOTE: Backup does not see transactional dequeues until the transaction is + // prepared, then they are all receieved before the prepare event. + // We collect the events here so we can do a single scan of the queue in prepare. + dequeueState.add(e); +} + +void TxReplicator::DequeueState::add(const TxDequeueEvent& event) { + events[event.queue] += event.id; +} + +// Use this function as a seek() predicate to find the dequeued messages. +bool TxReplicator::DequeueState::addRecord( + const broker::Message& m, const boost::shared_ptr<Queue>& queue, + const ReplicationIdSet& rids) +{ + if (rids.contains(m.getReplicationId())) { + DeliveryRecord dr(cursor, m.getSequence(), m.getReplicationId(), queue, + string() /*tag*/, + boost::shared_ptr<Consumer>(), + true /*acquired*/, + false /*accepted*/, + false /*credit.isWindowMode()*/, + 0 /*credit*/); + // Generate record ids, unique within this transaction. + dr.setId(nextId++); + records.push_back(dr); + recordIds += dr.getId(); + } + return false; +} + +void TxReplicator::DequeueState::addRecords(const EventMap::value_type& entry) { + // Process all the dequeues for a single queue, in one pass of seek() + boost::shared_ptr<broker::Queue> q = queues.get(entry.first); + q->seek(cursor, boost::bind(&TxReplicator::DequeueState::addRecord, + this, _1, q, entry.second)); +} + +boost::shared_ptr<TxAccept> TxReplicator::DequeueState::makeAccept() { + for_each(events.begin(), events.end(), + boost::bind(&TxReplicator::DequeueState::addRecords, this, _1)); + return boost::shared_ptr<TxAccept>( + new TxAccept(boost::cref(recordIds), boost::ref(records))); +} + +void TxReplicator::prepare(const string&, sys::Mutex::ScopedLock& l) { + txBuffer->enlist(dequeueState.makeAccept()); + context = store->begin(); + if (txBuffer->prepare(context.get())) { + QPID_LOG(debug, logPrefix << "Prepared OK"); + sendMessage(TxPrepareOkEvent(haBroker.getSystemId()).message(queue->getName()), l); + } else { + QPID_LOG(debug, logPrefix << "Prepare failed"); + sendMessage(TxPrepareFailEvent(haBroker.getSystemId()).message(queue->getName()), l); + } +} + +void TxReplicator::commit(const string&, sys::Mutex::ScopedLock& l) { + QPID_LOG(debug, logPrefix << "Commit"); + if (context.get()) store->commit(*context); + txBuffer->commit(); + end(l); +} + +void TxReplicator::rollback(const string&, sys::Mutex::ScopedLock& l) { + QPID_LOG(debug, logPrefix << "Rollback"); + if (context.get()) store->abort(*context); + txBuffer->rollback(); + end(l); +} + +void TxReplicator::members(const string& data, sys::Mutex::ScopedLock&) { + TxMembersEvent e; + decodeStr(data, e); + QPID_LOG(debug, logPrefix << "Members: " << e.members); + if (!e.members.count(haBroker.getMembership().getSelf().getSystemId())) { + QPID_LOG(info, logPrefix << "Not participating in transaction"); + ignore = true; + } +} + +void TxReplicator::end(sys::Mutex::ScopedLock&) { + complete = true; + if (!getQueue()) return; // Already destroyed + // Destroy will cancel the subscription to the primary tx-queue which + // informs the primary that we have completed the transaction. + destroy(); +} + +void TxReplicator::destroy() { + QueueReplicator::destroy(); + sys::Mutex::ScopedLock l(lock); + if (!ignore && !complete) rollback(string(), l); +} + +}} // namespace qpid::ha diff --git a/qpid/cpp/src/qpid/ha/TxReplicator.h b/qpid/cpp/src/qpid/ha/TxReplicator.h new file mode 100644 index 0000000000..214b2a8a5f --- /dev/null +++ b/qpid/cpp/src/qpid/ha/TxReplicator.h @@ -0,0 +1,131 @@ +#ifndef QPID_HA_TRANSACTIONREPLICATOR_H +#define QPID_HA_TRANSACTIONREPLICATOR_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 "QueueReplicator.h" +#include "Event.h" +#include "qpid/broker/DeliveryRecord.h" +#include "qpid/broker/TransactionalStore.h" +#include "qpid/sys/Mutex.h" + +namespace qpid { + +namespace broker { +class TxBuffer; +class TxAccept; +class DtxBuffer; +class Broker; +class MessageStore; +class Deliverable; +} + +namespace ha { +class BrokerReplicator; + +/** + * Exchange created on a backup broker to replicate a transaction on the primary. + * + * Subscribes to a tx-queue like a normal queue but puts replicated messages and + * transaction events into a local TxBuffer. + * + * THREAD SAFE: Called in different connection threads. + */ +class TxReplicator : public QueueReplicator { + public: + typedef boost::shared_ptr<broker::Queue> QueuePtr; + typedef boost::shared_ptr<broker::Link> LinkPtr; + + static bool isTxQueue(const std::string& queue); + static std::string getTxId(const std::string& queue); + + TxReplicator(HaBroker&, const QueuePtr& txQueue, const LinkPtr& link); + ~TxReplicator(); + + std::string getType() const; + + // QueueReplicator overrides + void route(broker::Deliverable& deliverable); + void destroy(); + + protected: + + void deliver(const broker::Message&); + + private: + + typedef void (TxReplicator::*DispatchFunction)( + const std::string&, sys::Mutex::ScopedLock&); + typedef qpid::sys::unordered_map<std::string, DispatchFunction> DispatchMap; + typedef qpid::sys::unordered_map<std::string, ReplicationIdSet> DequeueMap; + + void sendMessage(const broker::Message&, sys::Mutex::ScopedLock&); + void enqueue(const std::string& data, sys::Mutex::ScopedLock&); + void dequeue(const std::string& data, sys::Mutex::ScopedLock&); + void prepare(const std::string& data, sys::Mutex::ScopedLock&); + void commit(const std::string& data, sys::Mutex::ScopedLock&); + void rollback(const std::string& data, sys::Mutex::ScopedLock&); + void members(const std::string& data, sys::Mutex::ScopedLock&); + void end(sys::Mutex::ScopedLock&); + + std::string logPrefix; + TxEnqueueEvent enq; // Enqueue data for next deliver. + boost::shared_ptr<broker::TxBuffer> txBuffer; + broker::MessageStore* store; + std::auto_ptr<broker::TransactionContext> context; + framing::ChannelId channel; // Channel to send prepare-complete. + bool complete, ignore; + + // Class to process dequeues and create DeliveryRecords to populate a + // TxAccept. + class DequeueState { + public: + DequeueState(broker::QueueRegistry& qr) : queues(qr) {} + void add(const TxDequeueEvent&); + boost::shared_ptr<broker::TxAccept> makeAccept(); + + private: + // Delivery record IDs are command IDs from the session. + // On a backup we will just fake these Ids. + typedef framing::SequenceNumber Id; + typedef framing::SequenceSet IdSet; + typedef qpid::sys::unordered_map<std::string, ReplicationIdSet> EventMap; + + bool addRecord(const broker::Message& m, + const boost::shared_ptr<broker::Queue>&, + const ReplicationIdSet& ); + void addRecords(const DequeueMap::value_type& entry); + + broker::QueueRegistry& queues; + EventMap events; + broker::DeliveryRecords records; + broker::QueueCursor cursor; + framing::SequenceNumber nextId; + IdSet recordIds; + }; + DequeueState dequeueState; +}; + + +}} // namespace qpid::ha + +#endif /*!QPID_HA_TRANSACTIONREPLICATOR_H*/ diff --git a/qpid/cpp/src/qpid/ha/hash.h b/qpid/cpp/src/qpid/ha/hash.h index a513673cce..8a7f3c00fe 100644 --- a/qpid/cpp/src/qpid/ha/hash.h +++ b/qpid/cpp/src/qpid/ha/hash.h @@ -22,19 +22,48 @@ * */ +#include "qpid/types/Uuid.h" #include <boost/shared_ptr.hpp> +#include <utility> namespace qpid { namespace ha { -template<class T> struct TrivialHasher { - size_t operator()(T value) const { return static_cast<size_t>(value); } -}; +// TODO aconway 2013-08-06: would like to use boost::hash or std::hash here +// but not available/working on some older compilers. +// Add overloads as needed. + +inline std::size_t hashValue(bool v) { return static_cast<std::size_t>(v); } +inline std::size_t hashValue(char v) { return static_cast<std::size_t>(v); } +inline std::size_t hashValue(unsigned char v) { return static_cast<std::size_t>(v); } +inline std::size_t hashValue(signed char v) { return static_cast<std::size_t>(v); } +inline std::size_t hashValue(short v) { return static_cast<std::size_t>(v); } +inline std::size_t hashValue(unsigned short v) { return static_cast<std::size_t>(v); } +inline std::size_t hashValue(int v) { return static_cast<std::size_t>(v); } +inline std::size_t hashValue(unsigned int v) { return static_cast<std::size_t>(v); } +inline std::size_t hashValue(long v) { return static_cast<std::size_t>(v); } +inline std::size_t hashValue(unsigned long v) { return static_cast<std::size_t>(v); } + +inline std::size_t hashValue(const types::Uuid& v) { return v.hash(); } + +template <class T> inline std::size_t hashValue(T* v) { + std::size_t x = static_cast<std::size_t>(reinterpret_cast<std::ptrdiff_t>(v)); + return x + (x >> 3); +} + +template <class T> inline void hashCombine(std::size_t& seed, const T& v) { + seed ^= hashValue(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); +} + +template <class T, class U> inline size_t hashValue(const std::pair<T,U>& v) { + std::size_t seed = 0; + hashCombine(seed, v.first); + hashCombine(seed, v.second); + return seed; +} -template<class T> struct SharedPtrHasher { - size_t operator()(const boost::shared_ptr<T>& ptr) const { - return reinterpret_cast<size_t>(ptr.get()); - } +template<class T> struct Hasher { + size_t operator()(const T& v) const { return hashValue(v); } }; }} // namespace qpid::ha diff --git a/qpid/cpp/src/qpid/ha/makeMessage.h b/qpid/cpp/src/qpid/ha/makeMessage.h deleted file mode 100644 index 4427cdd948..0000000000 --- a/qpid/cpp/src/qpid/ha/makeMessage.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef QPID_HA_MAKEMESSAGE_H -#define QPID_HA_MAKEMESSAGE_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/broker/Message.h" -#include "qpid/framing/Buffer.h" -#include <string> - -/** Utilities for creating messages used by HA internally. */ - -namespace qpid { -namespace framing { -class Buffer; -} -namespace ha { - -/** - * Create internal messages used by HA components. - */ -broker::Message makeMessage( - const framing::Buffer& content, - const std::string& destination=std::string() -); - -broker::Message makeMessage(const std::string& content, - const std::string& destination=std::string()); - -/** Encode value as a string. */ -template <class T> std::string encodeStr(const T& value) { - std::string encoded(value.encodedSize(), '\0'); - framing::Buffer buffer(&encoded[0], encoded.size()); - value.encode(buffer); - return encoded; -} - -/** Decode value from a string. */ -template <class T> T decodeStr(const std::string& encoded) { - framing::Buffer buffer(const_cast<char*>(&encoded[0]), encoded.size()); - T value; - value.decode(buffer); - return value; -} - -}} // namespace qpid::ha - -#endif /*!QPID_HA_MAKEMESSAGE_H*/ diff --git a/qpid/cpp/src/qpid/ha/types.cpp b/qpid/cpp/src/qpid/ha/types.cpp index 2246355339..c02ae33470 100644 --- a/qpid/cpp/src/qpid/ha/types.cpp +++ b/qpid/cpp/src/qpid/ha/types.cpp @@ -37,6 +37,14 @@ using namespace std; const string QPID_REPLICATE("qpid.replicate"); const string QPID_HA_UUID("qpid.ha-uuid"); +const char* QPID_HA_PREFIX = "qpid.ha-"; +const char* QUEUE_REPLICATOR_PREFIX = "qpid.ha-q:"; +const char* TRANSACTION_REPLICATOR_PREFIX = "qpid.ha-tx:"; + +bool startsWith(const string& name, const string& prefix) { + return name.compare(0, prefix.size(), prefix) == 0; +} + string EnumBase::str() const { assert(value < count); return names[value]; @@ -79,9 +87,11 @@ istream& operator>>(istream& i, EnumBase& e) { return i; } -ostream& operator<<(ostream& o, const IdSet& ids) { +ostream& operator<<(ostream& o, const UuidSet& ids) { ostream_iterator<qpid::types::Uuid> out(o, " "); + o << "{ "; copy(ids.begin(), ids.end(), out); + o << "}"; return o; } @@ -98,6 +108,24 @@ std::ostream& operator<<(std::ostream& o, const LogMessageId& m) { return o << m.queue << "[" << m.position << "]=" << m.replicationId; } +void UuidSet::encode(framing::Buffer& b) const { + b.putLong(size()); + for (const_iterator i = begin(); i != end(); ++i) + b.putRawData(i->data(), i->size()); +} + +void UuidSet::decode(framing::Buffer& b) { + size_t n = b.getLong(); + for ( ; n > 0; --n) { + types::Uuid id; + b.getRawData(const_cast<unsigned char*>(id.data()), id.size()); + insert(id); + } +} + +size_t UuidSet::encodedSize() const { + return sizeof(uint32_t) + size()*16; +} }} // namespace qpid::ha diff --git a/qpid/cpp/src/qpid/ha/types.h b/qpid/cpp/src/qpid/ha/types.h index 9a7e97c66d..92157d411b 100644 --- a/qpid/cpp/src/qpid/ha/types.h +++ b/qpid/cpp/src/qpid/ha/types.h @@ -105,14 +105,26 @@ inline bool isPrimary(BrokerStatus s) { inline bool isBackup(BrokerStatus s) { return !isPrimary(s); } -// String constants. +// String constants, defined as char* to avoid initialization order problems. extern const std::string QPID_REPLICATE; extern const std::string QPID_HA_UUID; -/** Define IdSet type, not a typedef so we can overload operator << */ -class IdSet : public std::set<types::Uuid> {}; +// Strings used as prefixes, defined as char* to avoid link order problems. +extern const char* QPID_HA_PREFIX; +extern const char* QUEUE_REPLICATOR_PREFIX; +extern const char* TRANSACTION_REPLICATOR_PREFIX; -std::ostream& operator<<(std::ostream& o, const IdSet& ids); +bool startsWith(const std::string& name, const std::string& prefix); + +/** Define IdSet type, not a typedef so we can overload operator << and add encoding.*/ +class UuidSet : public std::set<types::Uuid> { + public: + void encode(framing::Buffer&) const; + void decode(framing::Buffer&); + size_t encodedSize() const; +}; + +std::ostream& operator<<(std::ostream& o, const UuidSet& ids); // Use type names to distinguish Positions from Replication Ids typedef framing::SequenceNumber QueuePosition; @@ -132,5 +144,8 @@ struct LogMessageId { }; std::ostream& operator<<(std::ostream&, const LogMessageId&); +/** Return short version of human-readable UUID. */ +inline std::string shortStr(const types::Uuid& uuid) { return uuid.str().substr(0,8); } + }} // qpid::ha #endif /*!QPID_HA_ENUM_H*/ diff --git a/qpid/cpp/src/qpid/legacystore/MessageStoreImpl.cpp b/qpid/cpp/src/qpid/legacystore/MessageStoreImpl.cpp index 3b42c7bd5d..7863940534 100644 --- a/qpid/cpp/src/qpid/legacystore/MessageStoreImpl.cpp +++ b/qpid/cpp/src/qpid/legacystore/MessageStoreImpl.cpp @@ -21,6 +21,7 @@ #include "qpid/legacystore/MessageStoreImpl.h" +#include "db-inc.h" #include "qpid/broker/QueueSettings.h" #include "qpid/legacystore/BindingDbt.h" #include "qpid/legacystore/BufferValue.h" @@ -31,7 +32,6 @@ #include "qmf/org/apache/qpid/legacystore/Package.h" #include "qpid/legacystore/StoreException.h" #include <dirent.h> -#include <db.h> #define MAX_AIO_SLEEPS 100000 // tot: ~1 sec #define AIO_SLEEP_TIME_US 10 // 0.01 ms @@ -448,6 +448,8 @@ void MessageStoreImpl::closeDbs() MessageStoreImpl::~MessageStoreImpl() { + if (mgmtObject.get() != 0) + mgmtObject->debugStats("destroying"); finalize(); try { closeDbs(); diff --git a/qpid/cpp/src/qpid/legacystore/jrnl/jcfg.h b/qpid/cpp/src/qpid/legacystore/jrnl/jcfg.h index 0a0d0df28d..01d92ee985 100644 --- a/qpid/cpp/src/qpid/legacystore/jrnl/jcfg.h +++ b/qpid/cpp/src/qpid/legacystore/jrnl/jcfg.h @@ -33,13 +33,13 @@ #ifndef QPID_LEGACYSTORE_JRNL_JCFG_H #define QPID_LEGACYSTORE_JRNL_JCFG_H -#if defined(__i386__) /* little endian, 32 bits */ +#if defined(__i386__) || (__arm__) /* little endian, 32 bits */ #define JRNL_LITTLE_ENDIAN #define JRNL_32_BIT #elif defined(__PPC__) || defined(__s390__) /* big endian, 32 bits */ #define JRNL_BIG_ENDIAN #define JRNL_32_BIT -#elif defined(__ia64__) || defined(__x86_64__) || defined(__alpha__) /* little endian, 64 bits */ +#elif defined(__ia64__) || defined(__x86_64__) || defined(__alpha__) || (__arm64__) /* little endian, 64 bits */ #define JRNL_LITTLE_ENDIAN #define JRNL_64_BIT #elif defined(__powerpc64__) || defined(__s390x__) /* big endian, 64 bits */ diff --git a/qpid/cpp/src/qpid/log/Logger.cpp b/qpid/cpp/src/qpid/log/Logger.cpp index 16b2f56049..8242acc87e 100644 --- a/qpid/cpp/src/qpid/log/Logger.cpp +++ b/qpid/cpp/src/qpid/log/Logger.cpp @@ -24,6 +24,7 @@ #include "qpid/sys/Time.h" #include "qpid/DisableExceptionLogging.h" +#include "boost/version.hpp" #if (BOOST_VERSION >= 104000) #include <boost/serialization/singleton.hpp> #else diff --git a/qpid/cpp/src/qpid/log/Logger.h b/qpid/cpp/src/qpid/log/Logger.h new file mode 100644 index 0000000000..8c4beb0785 --- /dev/null +++ b/qpid/cpp/src/qpid/log/Logger.h @@ -0,0 +1,122 @@ +#ifndef QPID_LOG_LOGGER_H +#define QPID_LOG_LOGGER_H + +/* + * 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/log/Selector.h" +#include "qpid/log/Options.h" +#include "qpid/sys/Mutex.h" +#include <boost/ptr_container/ptr_vector.hpp> +#include <boost/noncopyable.hpp> +#include <set> +#include "qpid/CommonImportExport.h" + +namespace qpid { +namespace log { + +/** + * Central logging agent. + * + * Thread safe, singleton. + * + * The Logger provides all needed functionality for selecting and + * formatting logging output. The actual outputting of log records + * is handled by Logger::Output-derived classes instantiated by the + * platform's sink-related options. + */ +class QPID_COMMON_CLASS_EXTERN Logger : private boost::noncopyable { + public: + /** Flags indicating what to include in the log output */ + enum FormatFlag { FILE=1, LINE=2, FUNCTION=4, LEVEL=8, TIME=16, THREAD=32, HIRES=64, CATEGORY=128}; + + /** + * Logging output sink. + * + * The Output sink provides an interface to direct logging output to. + * Logging sinks are primarily platform-specific as provided for on + * each platform. + * + * Implementations of Output must be thread safe. + */ + class Output { + public: + QPID_COMMON_EXTERN Output(); + QPID_COMMON_EXTERN virtual ~Output(); + /** Receives the statemnt of origin and formatted message to log. */ + virtual void log(const Statement&, const std::string&) =0; + }; + + QPID_COMMON_EXTERN static Logger& instance(); + + QPID_COMMON_EXTERN Logger(); + QPID_COMMON_EXTERN ~Logger(); + + /** Select the messages to be logged. */ + QPID_COMMON_EXTERN void select(const Selector& s); + + /** Set the formatting flags, bitwise OR of FormatFlag values. */ + QPID_COMMON_EXTERN void format(int formatFlags); + + /** Set format flags from options object. + *@returns computed flags. + */ + QPID_COMMON_EXTERN int format(const Options&); + + /** Configure logger from Options */ + QPID_COMMON_EXTERN void configure(const Options& o); + + /** Reset the log selectors */ + QPID_COMMON_EXTERN void reconfigure(const std::vector<std::string>& selectors); + + /** Add a statement. */ + QPID_COMMON_EXTERN void add(Statement& s); + + /** Log a message. */ + QPID_COMMON_EXTERN void log(const Statement&, const std::string&); + + /** Add an output destination for messages */ + QPID_COMMON_EXTERN void output(std::auto_ptr<Output> out); + + /** Set a prefix for all messages */ + QPID_COMMON_EXTERN void setPrefix(const std::string& prefix); + + /** Reset the logger. */ + QPID_COMMON_EXTERN void clear(); + + /** Get the options used to configure the logger. */ + QPID_COMMON_INLINE_EXTERN const Options& getOptions() const { return options; } + + /** Get the hires timestamp setting */ + QPID_COMMON_EXTERN bool getHiresTimestamp(); + + /** Set the hires timestamp setting */ + QPID_COMMON_EXTERN void setHiresTimestamp(bool setting); + + private: + typedef boost::ptr_vector<Output> Outputs; + typedef std::set<Statement*> Statements; + + sys::Mutex lock; + inline void enable_unlocked(Statement* s); + + Statements statements; + Outputs outputs; + Selector selector; + int flags; + std::string prefix; + Options options; +}; + +}} // namespace qpid::log + + +#endif /*!QPID_LOG_LOGGER_H*/ diff --git a/qpid/cpp/src/qpid/log/Options.h b/qpid/cpp/src/qpid/log/Options.h new file mode 100644 index 0000000000..42a8fb40fe --- /dev/null +++ b/qpid/cpp/src/qpid/log/Options.h @@ -0,0 +1,51 @@ +#ifndef QPID_LOG_OPTIONS_H +#define QPID_LOG_OPTIONS_H + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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/Options.h" +#include "qpid/CommonImportExport.h" +#include "qpid/log/SinkOptions.h" +#include <iosfwd> +#include <memory> + +namespace qpid { +namespace log { + +/** Logging options for config parser. */ +struct Options : public qpid::Options { + /** Pass argv[0] for use in syslog output */ + QPID_COMMON_EXTERN Options(const std::string& argv0_=std::string(), + const std::string& name_="Logging options"); + QPID_COMMON_EXTERN Options(const Options &); + + QPID_COMMON_EXTERN Options& operator=(const Options&); + + std::string argv0; + std::string name; + std::vector<std::string> selectors; + std::vector<std::string> deselectors; + bool time, level, thread, source, function, hiresTs, category; + bool trace; + std::string prefix; + std::auto_ptr<SinkOptions> sinkOptions; +}; + +}} // namespace qpid::log + +#endif /*!QPID_LOG_OPTIONS_H*/ diff --git a/qpid/cpp/src/qpid/log/Selector.h b/qpid/cpp/src/qpid/log/Selector.h new file mode 100644 index 0000000000..1d025e9646 --- /dev/null +++ b/qpid/cpp/src/qpid/log/Selector.h @@ -0,0 +1,99 @@ +#ifndef SELECTOR_H +#define SELECTOR_H + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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/log/Statement.h" +#include "qpid/CommonImportExport.h" +#include <vector> + +namespace qpid { +namespace log { +struct Options; + +/** + * SelectorElement parses a cli/mgmt enable/disable entry into usable fields + * where cliEntry = [!]LEVEL[+-][:PATTERN] + */ +struct SelectorElement { + QPID_COMMON_EXTERN SelectorElement(const std::string cliEntry); + std::string levelStr; + std::string patternStr; + Level level; + Category category; + bool isDisable; + bool isCategory; + bool isLevelAndAbove; + bool isLevelAndBelow; +}; + +/** + * A selector identifies the set of log messages to enable. + * + * Thread object unsafe, pass-by-value type. + */ +class Selector { + public: + /** Empty selector selects nothing */ + QPID_COMMON_EXTERN Selector(); + + /** Set selector from Options */ + QPID_COMMON_EXTERN Selector(const Options&); + + /** Equavlient to: Selector s; s.enable(l, s) */ + QPID_COMMON_EXTERN Selector(Level l, const std::string& s=std::string()); + + /** Selector from string */ + QPID_COMMON_EXTERN Selector(const std::string& selector); + + /** push option settings into runtime lookup structs */ + QPID_COMMON_EXTERN void enable(const std::string& enableStr); + QPID_COMMON_EXTERN void disable(const std::string& disableStr); + + /** + * Enable/disable messages with level in levels where the file + * name contains substring. Empty string matches all. + */ + QPID_COMMON_EXTERN void enable(Level level, const std::string& substring=std::string()); + QPID_COMMON_EXTERN void disable(Level level, const std::string& substring=std::string()); + + /** Tests to determine if function names are in enable/disable tables */ + QPID_COMMON_EXTERN bool isEnabled(Level level, const char* function); + QPID_COMMON_EXTERN bool isDisabled(Level level, const char* function); + + /** Test to determine if log Statement is enabled */ + QPID_COMMON_EXTERN bool isEnabled(Level level, const char* function, Category category); + + private: + typedef std::vector<std::string> FunctionNameTable [LevelTraits::COUNT]; + FunctionNameTable enabledFunctions; // log function names explicitly enabled + FunctionNameTable disabledFunctions; // log function names explicitly disabled + bool enableFlags[LevelTraits::COUNT][CategoryTraits::COUNT]; + bool disableFlags[LevelTraits::COUNT][CategoryTraits::COUNT]; + + bool lookupFuncName(Level level, const char* function, FunctionNameTable& table); + /** Reset the category enable flags */ + QPID_COMMON_EXTERN void reset(); +}; + + +}} // namespace qpid::log + + +#endif /*!SELECTOR_H*/ diff --git a/qpid/cpp/src/qpid/log/SinkOptions.h b/qpid/cpp/src/qpid/log/SinkOptions.h new file mode 100644 index 0000000000..7ec2cfbc17 --- /dev/null +++ b/qpid/cpp/src/qpid/log/SinkOptions.h @@ -0,0 +1,64 @@ +#ifndef QPID_LOG_SINKOPTIONS_H +#define QPID_LOG_SINKOPTIONS_H + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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/Options.h" +#include <string> + +namespace qpid { +namespace log { + +class Logger; + +/** + * Logging sink options. + * + * Most logging sink options will be platform-specific, even if some are + * duplicated. The range of platforms to which this code may be ported + * can't be assumed to all have C++ iostreams or files. Thus, this class + * is primarily for implementing in a platform-specific way. + */ +struct SinkOptions : public qpid::Options { + + // Create a platform's SinkOptions. Pass argv0 as the program name, + // useful for syslog-type logging. + static SinkOptions *create(const std::string& argv0=std::string()); + + SinkOptions(const std::string& name="Logging sink options") + : qpid::Options(name) + {} + virtual ~SinkOptions() {} + + virtual SinkOptions& operator=(const SinkOptions&) = 0; + + // This allows the caller to indicate that there's no normal outputs + // available. For example, when running as a daemon. In these cases, the + // platform's "syslog"-type output should replace the default stderr + // unless some other sink has been selected. + virtual void detached(void) = 0; + + // The Logger acting on these options calls setup() to request any + // Sinks be set up and fed back to the logger. + virtual void setup(Logger *logger) = 0; +}; + +}} // namespace qpid::log + +#endif /*!QPID_LOG_OPTIONS_H*/ diff --git a/qpid/cpp/src/qpid/log/Statement.h b/qpid/cpp/src/qpid/log/Statement.h new file mode 100644 index 0000000000..e928e19f22 --- /dev/null +++ b/qpid/cpp/src/qpid/log/Statement.h @@ -0,0 +1,242 @@ +#ifndef STATEMENT_H +#define STATEMENT_H + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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/Msg.h" +#include "qpid/CommonImportExport.h" +#include <boost/current_function.hpp> + +namespace qpid { +namespace log { + +/** Debugging severity levels + * - trace: High-volume debugging messages. + * - debug: Debugging messages. + * - info: Informational messages. + * - notice: Normal but significant condition. + * - warning: Warn of a possible problem. + * - error: A definite error has occured. + * - critical: System in danger of severe failure. + */ +enum Level { trace, debug, info, notice, warning, error, critical }; +struct LevelTraits { + static const int COUNT=critical+1; + + /** Get level from string name. + *@exception if name invalid. + */ + static Level level(const char* name); + + /** Get level from string name. + *@exception if name invalid. + */ + static Level level(const std::string& name) { + return level(name.c_str()); + } + + /** String name of level */ + static const char* name(Level); +}; + +/** Formal message categories + * https://issues.apache.org/jira/browse/QPID-3902 + * + * Category Source code directory + * -------- --------------------- + * Security acl ssl gssapi sasl cyrus + * Broker broker + * Management agent console qmf + * Protocol amqp_0_10 framing + * System log sys types xml thread mutex fork pipe time ... + * HA cluster ha replication + * Messaging messaging + * Client client + * Store store + * Network tcp rdma AsynchIO socket epoll + * Test + * Model <not related to a directory> + * Unspecified <must be last in enum> + */ +enum Category { security, broker, management, protocol, system, ha, messaging, + store, network, test, client, model, unspecified }; +struct CategoryTraits { + static const int COUNT=unspecified+1; + + /** Test if given name is a Category name + */ + static bool isCategory(const std::string& name); + + /** Get category from string name + * @exception if name invalid. + */ + static Category category(const char* name); + + /** Get category from string name. + * @exception if name invalid. + */ + static Category category(const std::string& name) { + return category(name.c_str()); + } + + /** String name of category */ + static const char* name(Category); +}; + + /** POD struct representing a logging statement in source code. */ +struct Statement { + bool enabled; + const char* file; + int line; + const char* function; + Level level; + Category category; + + QPID_COMMON_EXTERN void log(const std::string& message); + QPID_COMMON_EXTERN static void categorize(Statement& s); + + struct Initializer { + QPID_COMMON_EXTERN Initializer(Statement& s); + Statement& statement; + }; +}; + +///@internal static initializer for a Statement. +#define QPID_LOG_STATEMENT_INIT_CAT(LEVEL, CATEGORY) \ +{ 0, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, (::qpid::log::LEVEL), \ +(::qpid::log::CATEGORY) } + + +///@internal static initializer for a Statement with unspecified category +#define QPID_LOG_STATEMENT_INIT(LEVEL) \ +QPID_LOG_STATEMENT_INIT_CAT ( LEVEL , unspecified ) + +/** + * Like QPID_LOG but computes an additional boolean test expression + * to determine if the message should be logged. Evaluation of both + * the test and message expressions occurs only if the requested log level + * is enabled. + *@param LEVEL severity Level for message, should be one of: + * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix. + *@param TEST message is logged only if expression TEST evaluates to true. + *@param MESSAGE any object with an @eostream operator<<, or a sequence + * like of ostreamable objects separated by @e<<. + */ +#define QPID_LOG_IF(LEVEL, TEST, MESSAGE) \ + do { \ + using ::qpid::log::Statement; \ + static Statement stmt_= QPID_LOG_STATEMENT_INIT(LEVEL); \ + static Statement::Initializer init_(stmt_); \ + if (stmt_.enabled && (TEST)) \ + stmt_.log(::qpid::Msg() << MESSAGE); \ + } while(0) + +/** + * Line QPID_LOG_IF but with the additional specification of a category. + * @param CATEGORY message category. + */ +#define QPID_LOG_IF_CAT(LEVEL, CATEGORY, TEST, MESSAGE) \ + do { \ + using ::qpid::log::Statement; \ + static Statement stmt_= QPID_LOG_STATEMENT_INIT_CAT(LEVEL, CATEGORY); \ + static Statement::Initializer init_(stmt_); \ + if (stmt_.enabled && (TEST)) \ + stmt_.log(::qpid::Msg() << MESSAGE); \ + } while(0) + +/** + * FLAG must be a boolean variable. Assigns FLAG to true iff logging + * is enabled for LEVEL in the calling context. Use when extra + * support code is needed to generate log messages, to ensure that it + * is only run if the logging level is enabled. + * e.g. + * bool logWarning; + * QPID_LOG_TEST(warning, logWarning); + * if (logWarning) { do stuff needed for warning log messages } + */ +#define QPID_LOG_TEST(LEVEL, FLAG) \ + do { \ + using ::qpid::log::Statement; \ + static Statement stmt_= QPID_LOG_STATEMENT_INIT(LEVEL); \ + static Statement::Initializer init_(stmt_); \ + FLAG = stmt_.enabled; \ + } while(0) + + /** + * FLAG must be a boolean variable. Assigns FLAG to true iff logging + * is enabled for LEVEL in the calling context. Use when extra + * support code is needed to generate log messages, to ensure that it + * is only run if the logging level is enabled. + * e.g. + * bool logWarning; + * QPID_LOG_TEST_CAT(warning, System, logWarning); + * if (logWarning) { do stuff needed for warning log messages } + */ + #define QPID_LOG_TEST_CAT(LEVEL, CATEGORY, FLAG) \ + do { \ + using ::qpid::log::Statement; \ + static Statement stmt_= QPID_LOG_STATEMENT_INIT_CAT(LEVEL, CATEGORY); \ + static Statement::Initializer init_(stmt_); \ + FLAG = stmt_.enabled; \ + } while(0) + +/** + * Macro for log statements. Example of use: + * @code + * QPID_LOG(debug, "There are " << foocount << " foos in the bar."); + * QPID_LOG(error, boost::format("Dohickey %s exploded") % dohicky.name()); + * @endcode + * Using QPID_LOG implies a category of Unspecified. + * + * You can subscribe to log messages by level, by component, by filename + * or a combination @see Configuration. + + *@param LEVEL severity Level for message, should be one of: + * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix. + *@param MESSAGE any object with an @eostream operator<<, or a sequence + * like of ostreamable objects separated by @e<<. + */ +#define QPID_LOG(LEVEL, MESSAGE) QPID_LOG_IF(LEVEL, true, MESSAGE); + +/** + * Macro for log statements. Example of use: + * @code + * QPID_LOG_CAT(debug, System, "There are " << foocount << " foos in the bar."); + * QPID_LOG_CAT(error, System, boost::format("Dohickey %s exploded") % dohicky.name()); + * @endcode + * Using QPID_LOG_CAT requires the specification of a category. + * + * You can subscribe to log messages by level, by component, by filename + * or a combination @see Configuration. + * + *@param LEVEL severity Level for message, should be one of: + * debug, info, notice, warning, error, critical. NB no qpid::log:: prefix. + *@param CATEGORY basic Category for the message. + *@param MESSAGE any object with an @eostream operator<<, or a sequence + * like of ostreamable objects separated by @e<<. + */ +#define QPID_LOG_CAT(LEVEL, CATEGORY, MESSAGE) QPID_LOG_IF_CAT(LEVEL, CATEGORY, true, MESSAGE); + +}} // namespace qpid::log + + + + +#endif /*!STATEMENT_H*/ + diff --git a/qpid/cpp/src/qpid/management/Args.h b/qpid/cpp/src/qpid/management/Args.h new file mode 100644 index 0000000000..5d1cb7e01d --- /dev/null +++ b/qpid/cpp/src/qpid/management/Args.h @@ -0,0 +1,44 @@ +#ifndef _Args_ +#define _Args_ + +// +// 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. +// + + +namespace qpid { +namespace management { + +class Args +{ + public: + + virtual ~Args (void) = 0; + +}; + +inline Args::~Args (void) {} + +class ArgsNone : public Args +{ +}; + +}} + + +#endif /*!_Args_*/ diff --git a/qpid/cpp/src/qpid/management/Buffer.h b/qpid/cpp/src/qpid/management/Buffer.h new file mode 100644 index 0000000000..1ac52bf276 --- /dev/null +++ b/qpid/cpp/src/qpid/management/Buffer.h @@ -0,0 +1,105 @@ +#ifndef _Management_Buffer_ +#define _Management_Buffer_ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "qpid/CommonImportExport.h" +#include "qpid/types/Exception.h" +#include "qpid/types/Variant.h" +#include <string> + +namespace qpid { +namespace framing { + class Buffer; +} + +namespace management { + +struct OutOfBounds : qpid::types::Exception { + OutOfBounds() : qpid::types::Exception(std::string("Out of Bounds")) {} +}; + + +/** + * This class is a wrapper around qpid::framing::Buffer that does not include any dependencies + * from boost or from qpid::framing. + */ +class Buffer +{ +public: + QPID_COMMON_EXTERN Buffer(char* data=0, uint32_t size=0); + QPID_COMMON_EXTERN ~Buffer(); + + QPID_COMMON_EXTERN void reset(); + + QPID_COMMON_EXTERN uint32_t available(); + QPID_COMMON_EXTERN uint32_t getSize(); + QPID_COMMON_EXTERN uint32_t getPosition(); + QPID_COMMON_EXTERN void setPosition(uint32_t); + QPID_COMMON_EXTERN char* getPointer(); + + QPID_COMMON_EXTERN void putOctet(uint8_t i); + QPID_COMMON_EXTERN void putShort(uint16_t i); + QPID_COMMON_EXTERN void putLong(uint32_t i); + QPID_COMMON_EXTERN void putLongLong(uint64_t i); + QPID_COMMON_EXTERN void putInt8(int8_t i); + QPID_COMMON_EXTERN void putInt16(int16_t i); + QPID_COMMON_EXTERN void putInt32(int32_t i); + QPID_COMMON_EXTERN void putInt64(int64_t i); + QPID_COMMON_EXTERN void putFloat(float f); + QPID_COMMON_EXTERN void putDouble(double f); + QPID_COMMON_EXTERN void putBin128(const uint8_t* b); + + QPID_COMMON_EXTERN uint8_t getOctet(); + QPID_COMMON_EXTERN uint16_t getShort(); + QPID_COMMON_EXTERN uint32_t getLong(); + QPID_COMMON_EXTERN uint64_t getLongLong(); + QPID_COMMON_EXTERN int8_t getInt8(); + QPID_COMMON_EXTERN int16_t getInt16(); + QPID_COMMON_EXTERN int32_t getInt32(); + QPID_COMMON_EXTERN int64_t getInt64(); + QPID_COMMON_EXTERN float getFloat(); + QPID_COMMON_EXTERN double getDouble(); + + QPID_COMMON_EXTERN void putShortString(const std::string& s); + QPID_COMMON_EXTERN void putMediumString(const std::string& s); + QPID_COMMON_EXTERN void putLongString(const std::string& s); + QPID_COMMON_EXTERN void getShortString(std::string& s); + QPID_COMMON_EXTERN void getMediumString(std::string& s); + QPID_COMMON_EXTERN void getLongString(std::string& s); + QPID_COMMON_EXTERN void getBin128(uint8_t* b); + + QPID_COMMON_EXTERN void putMap(const types::Variant::Map& map); + QPID_COMMON_EXTERN void putList(const types::Variant::List& list); + QPID_COMMON_EXTERN void getMap(types::Variant::Map& map); + QPID_COMMON_EXTERN void getList(types::Variant::List& list); + + QPID_COMMON_EXTERN void putRawData(const std::string& s); + QPID_COMMON_EXTERN void getRawData(std::string& s, uint32_t size); + + QPID_COMMON_EXTERN void putRawData(const uint8_t* data, size_t size); + QPID_COMMON_EXTERN void getRawData(uint8_t* data, size_t size); + +private: + framing::Buffer* impl; +}; + +}} // namespace qpid::management + +#endif diff --git a/qpid/cpp/src/qpid/management/ConnectionSettings.h b/qpid/cpp/src/qpid/management/ConnectionSettings.h new file mode 100644 index 0000000000..b631ffa658 --- /dev/null +++ b/qpid/cpp/src/qpid/management/ConnectionSettings.h @@ -0,0 +1,118 @@ +#ifndef _management_ConnectionSettings_h +#define _management_ConnectionSettings_h +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/CommonImportExport.h" +#include "qpid/types/Variant.h" +#include <string> + +namespace qpid { +namespace management { + +/** + * Settings for a Connection. + */ +struct ConnectionSettings { + + QPID_COMMON_EXTERN ConnectionSettings(); + QPID_COMMON_EXTERN virtual ~ConnectionSettings(); + + /** + * The protocol used for the connection (defaults to 'tcp') + */ + std::string protocol; + + /** + * The host (or ip address) to connect to (defaults to 'localhost'). + */ + std::string host; + /** + * The port to connect to (defaults to 5672). + */ + uint16_t port; + /** + * Allows an AMQP 'virtual host' to be specified for the + * connection. + */ + std::string virtualhost; + + /** + * The username to use when authenticating the connection. If not + * specified the current users login is used if available. + */ + std::string username; + /** + * The password to use when authenticating the connection. + */ + std::string password; + /** + * The SASL mechanism to use when authenticating the connection; + * the options are currently PLAIN or ANONYMOUS. + */ + std::string mechanism; + /** + * Allows a locale to be specified for the connection. + */ + std::string locale; + /** + * Allows a heartbeat frequency to be specified + */ + uint16_t heartbeat; + /** + * The maximum number of channels that the client will request for + * use on this connection. + */ + uint16_t maxChannels; + /** + * The maximum frame size that the client will request for this + * connection. + */ + uint16_t maxFrameSize; + /** + * Limit the size of the connections send buffer . The buffer + * is limited to bounds * maxFrameSize. + */ + unsigned int bounds; + /** + * If true, TCP_NODELAY will be set for the connection. + */ + bool tcpNoDelay; + /** + * SASL service name + */ + std::string service; + /** + * Minimum acceptable strength of any SASL negotiated security + * layer. 0 means no security layer required. + */ + unsigned int minSsf; + /** + * Maximum acceptable strength of any SASL negotiated security + * layer. 0 means no security layer allowed. + */ + unsigned int maxSsf; +}; + +}} + +#endif + diff --git a/qpid/cpp/src/qpid/management/Manageable.h b/qpid/cpp/src/qpid/management/Manageable.h new file mode 100644 index 0000000000..ede5c29e43 --- /dev/null +++ b/qpid/cpp/src/qpid/management/Manageable.h @@ -0,0 +1,81 @@ +#ifndef _Manageable_ +#define _Manageable_ + +// +// 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/management/ManagementObject.h" +#include "qpid/management/Args.h" +#include <string> +#include "qpid/CommonImportExport.h" + +namespace qpid { +namespace management { + +class QPID_COMMON_EXTERN Manageable +{ + public: + + virtual ~Manageable(void) = 0; + + // status_t is a type used to pass completion status from the method handler. + // + typedef uint32_t status_t; + static std::string StatusText(status_t status, std::string text = std::string()); + + static const status_t STATUS_OK = 0; + static const status_t STATUS_UNKNOWN_OBJECT = 1; + static const status_t STATUS_UNKNOWN_METHOD = 2; + static const status_t STATUS_NOT_IMPLEMENTED = 3; + static const status_t STATUS_PARAMETER_INVALID = 4; + static const status_t STATUS_FEATURE_NOT_IMPLEMENTED = 5; + static const status_t STATUS_FORBIDDEN = 6; + static const status_t STATUS_EXCEPTION = 7; + static const status_t STATUS_USER = 0x00010000; + + // Every "Manageable" object must hold a reference to exactly one + // management object. This object is always of a class derived from + // the pure-virtual "ManagementObject". + // + // This accessor function returns a pointer to the management object. + // +#ifdef _IN_QPID_BROKER + virtual ManagementObject::shared_ptr GetManagementObject() const = 0; +#else + virtual ManagementObject* GetManagementObject() const = 0; +#endif + + // Every "Manageable" object must implement ManagementMethod. This + // function is called when a remote management client invokes a method + // on this object. The input and output arguments are specific to the + // method being called and must be down-cast to the appropriate sub class + // before use. + virtual status_t ManagementMethod(uint32_t methodId, Args& args, std::string& text); + + // This optional method can be overridden to allow the agent application to + // authorize method invocations. Return true iff the authenticated user identified + // in userId us authorized to execute the method. + virtual bool AuthorizeMethod(uint32_t methodId, Args& args, const std::string& userId); +}; + +inline Manageable::~Manageable(void) {} + +}} + +#endif /*!_Manageable_*/ diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.cpp b/qpid/cpp/src/qpid/management/ManagementAgent.cpp index 5f653939ec..d80dd6e6a3 100644 --- a/qpid/cpp/src/qpid/management/ManagementAgent.cpp +++ b/qpid/cpp/src/qpid/management/ManagementAgent.cpp @@ -39,6 +39,7 @@ #include "qpid/sys/PollableQueue.h" #include "qpid/broker/Connection.h" #include "qpid/broker/AclModule.h" +#include "qpid/broker/Protocol.h" #include "qpid/types/Variant.h" #include "qpid/types/Uuid.h" #include "qpid/framing/List.h" @@ -169,7 +170,7 @@ ManagementAgent::RemoteAgent::~RemoteAgent () } ManagementAgent::ManagementAgent (const bool qmfV1, const bool qmfV2) : - threadPoolSize(1), publish(true), interval(10), broker(0), timer(0), + threadPoolSize(1), publish(true), interval(10), broker(0), timer(0), protocols(0), startTime(sys::now()), suppressed(false), disallowAllV1Methods(false), vendorNameKey(defaultVendorName), productNameKey(defaultProductName), @@ -221,6 +222,7 @@ void ManagementAgent::configure(const string& _dataDir, bool _publish, uint16_t timer = &broker->getTimer(); timer->add(new Periodic(boost::bind(&ManagementAgent::periodicProcessing, this), timer, interval)); + protocols = &broker->getProtocolRegistry(); // Get from file or generate and save to file. if (dataDir.empty()) { @@ -2132,9 +2134,9 @@ bool ManagementAgent::authorizeAgentMessage(Message& msg) uint32_t bufferLen = inBuffer.getPosition(); inBuffer.reset(); - qpid::broker::amqp_0_10::MessageTransfer& transfer(qpid::broker::amqp_0_10::MessageTransfer::get(msg)); + boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> transfer = protocols->translate(msg); const framing::MessageProperties* p = - transfer.getFrames().getHeaders()->get<framing::MessageProperties>(); + transfer ? transfer->getFrames().getHeaders()->get<framing::MessageProperties>() : 0; const framing::FieldTable *headers = p ? &p->getApplicationHeaders() : 0; @@ -2229,9 +2231,9 @@ bool ManagementAgent::authorizeAgentMessage(Message& msg) // authorization failed, send reply if replyTo present - qpid::broker::amqp_0_10::MessageTransfer& transfer(qpid::broker::amqp_0_10::MessageTransfer::get(msg)); + boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> transfer = protocols->translate(msg); const framing::MessageProperties* p = - transfer.getFrames().getHeaders()->get<framing::MessageProperties>(); + transfer ? transfer->getFrames().getHeaders()->get<framing::MessageProperties>() : 0; if (p && p->hasReplyTo()) { const framing::ReplyTo& rt = p->getReplyTo(); string rte = rt.getExchange(); @@ -2266,9 +2268,10 @@ void ManagementAgent::dispatchAgentCommand(Message& msg, bool viaLocal) { string rte; string rtk; - qpid::broker::amqp_0_10::MessageTransfer& transfer(qpid::broker::amqp_0_10::MessageTransfer::get(msg)); - const framing::MessageProperties* p = - transfer.getFrames().getHeaders()->get<framing::MessageProperties>(); + + boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> transfer = protocols->translate(msg); + const framing::MessageProperties* p = transfer ? + transfer->getFrames().getHeaders()->get<framing::MessageProperties>() : 0; if (p && p->hasReplyTo()) { const framing::ReplyTo& rt = p->getReplyTo(); rte = rt.getExchange(); diff --git a/qpid/cpp/src/qpid/management/ManagementAgent.h b/qpid/cpp/src/qpid/management/ManagementAgent.h index d2869a705f..c2eb5d4a31 100644 --- a/qpid/cpp/src/qpid/management/ManagementAgent.h +++ b/qpid/cpp/src/qpid/management/ManagementAgent.h @@ -44,6 +44,7 @@ namespace qpid { namespace broker { class Connection; +class ProtocolRegistry; } namespace sys { class Timer; @@ -256,6 +257,7 @@ private: uint16_t interval; qpid::broker::Broker* broker; qpid::sys::Timer* timer; + qpid::broker::ProtocolRegistry* protocols; uint16_t bootSequence; uint32_t nextObjectId; uint32_t brokerBank; diff --git a/qpid/cpp/src/qpid/management/ManagementEvent.h b/qpid/cpp/src/qpid/management/ManagementEvent.h new file mode 100644 index 0000000000..e80175096f --- /dev/null +++ b/qpid/cpp/src/qpid/management/ManagementEvent.h @@ -0,0 +1,53 @@ +#ifndef _ManagementEvent_ +#define _ManagementEvent_ + +/* + * + * 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/management/ManagementObject.h" +#include "qpid/types/Variant.h" +#include <string> + +namespace qpid { +namespace management { + +class ManagementAgent; + +class ManagementEvent : public ManagementItem { + public: + static const uint8_t MD5_LEN = 16; + //typedef void (*writeSchemaCall_t)(qpid::framing::Buffer&); + typedef void (*writeSchemaCall_t)(std::string&); + virtual ~ManagementEvent() {} + + virtual writeSchemaCall_t getWriteSchemaCall(void) = 0; + //virtual mapEncodeSchemaCall_t getMapEncodeSchemaCall(void) = 0; + virtual std::string& getEventName() const = 0; + virtual std::string& getPackageName() const = 0; + virtual uint8_t* getMd5Sum() const = 0; + virtual uint8_t getSeverity() const = 0; + virtual void encode(std::string&) const = 0; + virtual void mapEncode(qpid::types::Variant::Map&) const = 0; +}; + +}} + +#endif /*!_ManagementEvent_*/ diff --git a/qpid/cpp/src/qpid/management/ManagementObject.h b/qpid/cpp/src/qpid/management/ManagementObject.h new file mode 100644 index 0000000000..93fbec7bc7 --- /dev/null +++ b/qpid/cpp/src/qpid/management/ManagementObject.h @@ -0,0 +1,246 @@ +#ifndef _ManagementObject_ +#define _ManagementObject_ + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "qpid/CommonImportExport.h" + +#include "qpid/management/Mutex.h" +#include "qpid/types/Variant.h" +#include <map> +#include <vector> + +#ifdef _IN_QPID_BROKER +#include <boost/shared_ptr.hpp> +#endif + +namespace qpid { +namespace management { + +class Manageable; +class ObjectId; +class ManagementObject; + + +class AgentAttachment { + friend class ObjectId; +private: + uint64_t first; +public: + AgentAttachment() : first(0) {} + QPID_COMMON_EXTERN void setBanks(uint32_t broker, uint32_t bank); + uint64_t getFirst() const { return first; } +}; + + +class ObjectId { +protected: + const AgentAttachment* agent; + uint64_t first; + uint64_t second; + uint64_t agentEpoch; + std::string v2Key; + std::string agentName; + void fromString(const std::string&); +public: + QPID_COMMON_INLINE_EXTERN ObjectId() : agent(0), first(0), second(0), agentEpoch(0) {} + QPID_COMMON_INLINE_EXTERN ObjectId(const types::Variant& map) : + agent(0), first(0), second(0), agentEpoch(0) { mapDecode(map.asMap()); } + QPID_COMMON_EXTERN ObjectId(uint8_t flags, uint16_t seq, uint32_t broker); + QPID_COMMON_EXTERN ObjectId(AgentAttachment* _agent, uint8_t flags, uint16_t seq); + QPID_COMMON_EXTERN ObjectId(std::istream&); + QPID_COMMON_EXTERN ObjectId(const std::string&); + QPID_COMMON_INLINE_EXTERN ObjectId(const std::string& agentAddress, const std::string& key, + uint64_t epoch=0) : agent(0), first(0), second(0), + agentEpoch(epoch), v2Key(key), agentName(agentAddress) {} + + // Deprecated: + QPID_COMMON_EXTERN ObjectId(uint8_t flags, uint16_t seq, uint32_t broker, uint64_t object); + QPID_COMMON_EXTERN bool operator==(const ObjectId &other) const; + QPID_COMMON_EXTERN bool operator<(const ObjectId &other) const; + QPID_COMMON_EXTERN void mapEncode(types::Variant::Map& map) const; + QPID_COMMON_EXTERN void mapDecode(const types::Variant::Map& map); + QPID_COMMON_EXTERN operator types::Variant::Map() const; + QPID_COMMON_INLINE_EXTERN uint32_t encodedSize() const { return 16; }; + QPID_COMMON_EXTERN void encode(std::string& buffer) const; + QPID_COMMON_EXTERN void decode(const std::string& buffer); + QPID_COMMON_EXTERN bool equalV1(const ObjectId &other) const; + QPID_COMMON_INLINE_EXTERN void setV2Key(const std::string& _key) { v2Key = _key; } + QPID_COMMON_EXTERN void setV2Key(const ManagementObject& object); + QPID_COMMON_INLINE_EXTERN void setAgentName(const std::string& _name) { agentName = _name; } + QPID_COMMON_INLINE_EXTERN const std::string& getAgentName() const { return agentName; } + QPID_COMMON_INLINE_EXTERN const std::string& getV2Key() const { return v2Key; } + friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const ObjectId&); +}; + +class ManagementItem { +public: + static const uint8_t TYPE_U8 = 1; + static const uint8_t TYPE_U16 = 2; + static const uint8_t TYPE_U32 = 3; + static const uint8_t TYPE_U64 = 4; + static const uint8_t TYPE_SSTR = 6; + static const uint8_t TYPE_LSTR = 7; + static const uint8_t TYPE_ABSTIME = 8; + static const uint8_t TYPE_DELTATIME = 9; + static const uint8_t TYPE_REF = 10; + static const uint8_t TYPE_BOOL = 11; + static const uint8_t TYPE_FLOAT = 12; + static const uint8_t TYPE_DOUBLE = 13; + static const uint8_t TYPE_UUID = 14; + static const uint8_t TYPE_FTABLE = 15; + static const uint8_t TYPE_S8 = 16; + static const uint8_t TYPE_S16 = 17; + static const uint8_t TYPE_S32 = 18; + static const uint8_t TYPE_S64 = 19; + static const uint8_t TYPE_LIST = 21; + + static const uint8_t ACCESS_RC = 1; + static const uint8_t ACCESS_RW = 2; + static const uint8_t ACCESS_RO = 3; + + static const uint8_t DIR_I = 1; + static const uint8_t DIR_O = 2; + static const uint8_t DIR_IO = 3; + + static const uint8_t FLAG_CONFIG = 0x01; + static const uint8_t FLAG_INDEX = 0x02; + static const uint8_t FLAG_END = 0x80; + + const static uint8_t CLASS_KIND_TABLE = 1; + const static uint8_t CLASS_KIND_EVENT = 2; + + + +public: + virtual ~ManagementItem() {} +}; + +class QPID_COMMON_CLASS_EXTERN ManagementObject : public ManagementItem +{ +protected: + + uint64_t createTime; + uint64_t destroyTime; + uint64_t updateTime; + ObjectId objectId; + mutable bool configChanged; + mutable bool instChanged; + bool deleted; + Manageable* coreObject; + mutable Mutex accessLock; + uint32_t flags; + + static int nextThreadIndex; + bool forcePublish; + + QPID_COMMON_EXTERN int getThreadIndex(); + QPID_COMMON_EXTERN void writeTimestamps(std::string& buf) const; + QPID_COMMON_EXTERN void readTimestamps(const std::string& buf); + QPID_COMMON_EXTERN uint32_t writeTimestampsSize() const; + + public: +#ifdef _IN_QPID_BROKER + typedef boost::shared_ptr<ManagementObject> shared_ptr; +#endif + + QPID_COMMON_EXTERN static const uint8_t MD5_LEN = 16; + QPID_COMMON_EXTERN static int maxThreads; + //typedef void (*writeSchemaCall_t) (qpid::framing::Buffer&); + typedef void (*writeSchemaCall_t) (std::string&); + + QPID_COMMON_EXTERN ManagementObject(Manageable* _core); + virtual ~ManagementObject() {} + + virtual writeSchemaCall_t getWriteSchemaCall() = 0; + virtual std::string getKey() const = 0; + + // Encode & Decode the property and statistics values + // for this object. + virtual void mapEncodeValues(types::Variant::Map& map, + bool includeProperties, + bool includeStatistics) = 0; + virtual void mapDecodeValues(const types::Variant::Map& map) = 0; + virtual void doMethod(std::string& methodName, + const types::Variant::Map& inMap, + types::Variant::Map& outMap, + const std::string& userId) = 0; + QPID_COMMON_EXTERN void writeTimestamps(types::Variant::Map& map) const; + QPID_COMMON_EXTERN void readTimestamps(const types::Variant::Map& buf); + + /** + * The following five methods are not pure-virtual because they will only + * be overridden in cases where QMFv1 is to be supported. + */ + virtual uint32_t writePropertiesSize() const { return 0; } + virtual void readProperties(const std::string&) {} + virtual void writeProperties(std::string&) const {} + virtual void writeStatistics(std::string&, bool = false) {} + virtual void doMethod(std::string&, const std::string&, std::string&, const std::string&) {} + + QPID_COMMON_EXTERN virtual void setReference(ObjectId objectId); + + virtual std::string& getClassName() const = 0; + virtual std::string& getPackageName() const = 0; + virtual uint8_t* getMd5Sum() const = 0; + + void setObjectId(ObjectId oid) { objectId = oid; } + ObjectId getObjectId() { return objectId; } + inline bool getConfigChanged() { return configChanged; } + virtual bool getInstChanged() { return instChanged; } + virtual bool hasInst() { return true; } + inline void setForcePublish(bool f) { forcePublish = f; } + inline bool getForcePublish() { return forcePublish; } + QPID_COMMON_EXTERN void setUpdateTime(); + QPID_COMMON_EXTERN void resourceDestroy(); + inline bool isDeleted() { return deleted; } + inline void setFlags(uint32_t f) { flags = f; } + inline uint32_t getFlags() { return flags; } + bool isSameClass(ManagementObject& other) { + for (int idx = 0; idx < MD5_LEN; idx++) + if (other.getMd5Sum()[idx] != getMd5Sum()[idx]) + return false; + return other.getClassName() == getClassName() && + other.getPackageName() == getPackageName(); + } + + // QPID_COMMON_EXTERN void encode(qpid::framing::Buffer& buf) const { writeProperties(buf); } + // QPID_COMMON_EXTERN void decode(qpid::framing::Buffer& buf) { readProperties(buf); } + //QPID_COMMON_EXTERN uint32_t encodedSize() const { return writePropertiesSize(); } + + // Encode/Decode the entire object as a map + //QPID_COMMON_EXTERN void mapEncode(types::Variant::Map& map, + //bool includeProperties=true, + //bool includeStatistics=true); + + //QPID_COMMON_EXTERN void mapDecode(const types::Variant::Map& map); +}; + +#ifdef _IN_QPID_BROKER +typedef std::map<ObjectId, ManagementObject::shared_ptr> ManagementObjectMap; +typedef std::vector<ManagementObject::shared_ptr> ManagementObjectVector; +#endif + +}} + + + +#endif /*!_ManagementObject_*/ diff --git a/qpid/cpp/src/qpid/management/Mutex.h b/qpid/cpp/src/qpid/management/Mutex.h new file mode 100644 index 0000000000..67ae04bae9 --- /dev/null +++ b/qpid/cpp/src/qpid/management/Mutex.h @@ -0,0 +1,67 @@ +#ifndef _management_Mutex_h +#define _management_Mutex_h + +/* + * + * Copyright (c) 2008 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "qpid/CommonImportExport.h" + +namespace qpid { + namespace sys { + class Mutex; + } + + namespace management { + + /** + * Scoped lock template: calls lock() in ctor, unlock() in dtor. + * L can be any class with lock() and unlock() functions. + */ + template <class L> class ScopedLockTemplate { + public: + ScopedLockTemplate(L& l) : mutex(l) { mutex.lock(); } + ~ScopedLockTemplate() { mutex.unlock(); } + private: + L& mutex; + }; + + template <class L> class ScopedUnlockTemplate { + public: + ScopedUnlockTemplate(L& l) : mutex(l) { mutex.unlock(); } + ~ScopedUnlockTemplate() { mutex.lock(); } + private: + L& mutex; + }; + + class Mutex { + public: + typedef ScopedLockTemplate<Mutex> ScopedLock; + typedef ScopedUnlockTemplate<Mutex> ScopedUnlock; + + QPID_COMMON_EXTERN Mutex(); + QPID_COMMON_EXTERN ~Mutex(); + QPID_COMMON_EXTERN void lock(); + QPID_COMMON_EXTERN void unlock(); + private: + sys::Mutex* impl; + }; + } +} + +#endif + diff --git a/qpid/cpp/src/qpid/messaging/Connection.cpp b/qpid/cpp/src/qpid/messaging/Connection.cpp index fde931038b..71618d1057 100644 --- a/qpid/cpp/src/qpid/messaging/Connection.cpp +++ b/qpid/cpp/src/qpid/messaging/Connection.cpp @@ -68,7 +68,7 @@ Connection::Connection(const std::string& url, const Variant::Map& options) Connection::Connection() { Variant::Map options; - std::string url = "amqp:tcp:127.0.0.1:5672"; + std::string url = "127.0.0.1:5672"; PI::ctor(*this, new qpid::client::amqp0_10::ConnectionImpl(url, options)); } @@ -90,4 +90,18 @@ std::string Connection::getAuthenticatedUsername() { return impl->getAuthenticatedUsername(); } + +void Connection::reconnect(const std::string& url) +{ + impl->reconnect(url); +} +void Connection::reconnect() +{ + impl->reconnect(); +} +std::string Connection::getUrl() const +{ + return impl->getUrl(); +} + }} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/ConnectionImpl.h b/qpid/cpp/src/qpid/messaging/ConnectionImpl.h index 1e11d9a6d5..92c6d91b10 100644 --- a/qpid/cpp/src/qpid/messaging/ConnectionImpl.h +++ b/qpid/cpp/src/qpid/messaging/ConnectionImpl.h @@ -45,6 +45,9 @@ class ConnectionImpl : public virtual qpid::RefCounted virtual Session getSession(const std::string& name) const = 0; virtual void setOption(const std::string& name, const qpid::types::Variant& value) = 0; virtual std::string getAuthenticatedUsername() = 0; + virtual void reconnect(const std::string& url) = 0; + virtual void reconnect() = 0; + virtual std::string getUrl() const = 0; private: }; }} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/ConnectionOptions.cpp b/qpid/cpp/src/qpid/messaging/ConnectionOptions.cpp index 746666a79c..e534920876 100644 --- a/qpid/cpp/src/qpid/messaging/ConnectionOptions.cpp +++ b/qpid/cpp/src/qpid/messaging/ConnectionOptions.cpp @@ -52,7 +52,7 @@ void merge(const qpid::types::Variant::List& from, std::vector<std::string>& to) ConnectionOptions::ConnectionOptions(const std::map<std::string, qpid::types::Variant>& options) : replaceUrls(false), reconnect(false), timeout(FOREVER), limit(-1), minReconnectInterval(0.001), maxReconnectInterval(2), - retries(0), reconnectOnLimitExceeded(true) + retries(0), reconnectOnLimitExceeded(true), nestAnnotations(false) { for (qpid::types::Variant::Map::const_iterator i = options.begin(); i != options.end(); ++i) { set(i->first, i->second); @@ -115,6 +115,8 @@ void ConnectionOptions::set(const std::string& name, const qpid::types::Variant& reconnectOnLimitExceeded = value; } else if (name == "container-id" || name == "container_id") { identifier = value.asString(); + } else if (name == "nest-annotations" || name == "nest_annotations") { + nestAnnotations = value; } else { throw qpid::messaging::MessagingException(QPID_MSG("Invalid option: " << name << " not recognised")); } diff --git a/qpid/cpp/src/qpid/messaging/ConnectionOptions.h b/qpid/cpp/src/qpid/messaging/ConnectionOptions.h index 7a701fce65..5942592d78 100644 --- a/qpid/cpp/src/qpid/messaging/ConnectionOptions.h +++ b/qpid/cpp/src/qpid/messaging/ConnectionOptions.h @@ -21,6 +21,8 @@ * under the License. * */ +#include "qpid/messaging/ImportExport.h" + #include "qpid/client/ConnectionSettings.h" #include <map> #include <vector> @@ -43,9 +45,10 @@ struct ConnectionOptions : qpid::client::ConnectionSettings int32_t retries; bool reconnectOnLimitExceeded; std::string identifier; + bool nestAnnotations; - ConnectionOptions(const std::map<std::string, qpid::types::Variant>&); - void set(const std::string& name, const qpid::types::Variant& value); + QPID_MESSAGING_EXTERN ConnectionOptions(const std::map<std::string, qpid::types::Variant>&); + QPID_MESSAGING_EXTERN void set(const std::string& name, const qpid::types::Variant& value); }; }} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/Message.cpp b/qpid/cpp/src/qpid/messaging/Message.cpp index 0f03bc8ca3..62ee93b6c2 100644 --- a/qpid/cpp/src/qpid/messaging/Message.cpp +++ b/qpid/cpp/src/qpid/messaging/Message.cpp @@ -31,6 +31,10 @@ using namespace qpid::types; 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(qpid::types::Variant& c) : impl(new MessageImpl(std::string())) +{ + setContentObject(c); +} Message::Message(const Message& m) : impl(new MessageImpl(*m.impl)) {} Message::~Message() { delete impl; } @@ -69,12 +73,20 @@ void Message::setRedelivered(bool redelivered) { impl->setRedelivered(redelivere const Variant::Map& Message::getProperties() const { return impl->getHeaders(); } Variant::Map& Message::getProperties() { return impl->getHeaders(); } +void Message::setProperties(const Variant::Map& p) { getProperties() = p; } void Message::setProperty(const std::string& k, const qpid::types::Variant& v) { impl->setHeader(k,v); } void Message::setContent(const std::string& c) { impl->setBytes(c); } void Message::setContent(const char* chars, size_t count) { impl->setBytes(chars, count); } std::string Message::getContent() const { return impl->getBytes(); } +void Message::setContentBytes(const std::string& c) { impl->setBytes(c); } +std::string Message::getContentBytes() const { return impl->getBytes(); } + +qpid::types::Variant& Message::getContentObject() { return impl->getContent(); } +void Message::setContentObject(const qpid::types::Variant& c) { impl->getContent() = c; } +const qpid::types::Variant& Message::getContentObject() const { return impl->getContent(); } + const char* Message::getContentPtr() const { return impl->getBytes().data(); diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.cpp b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp index fc9bc5dfa1..e9232804d8 100644 --- a/qpid/cpp/src/qpid/messaging/MessageImpl.cpp +++ b/qpid/cpp/src/qpid/messaging/MessageImpl.cpp @@ -7,9 +7,9 @@ * 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 @@ -30,21 +30,44 @@ const std::string EMPTY_STRING = ""; using namespace qpid::types; -MessageImpl::MessageImpl(const std::string& c) : +MessageImpl::MessageImpl(const std::string& c) : priority(0), ttl(0), durable(false), redelivered(false), bytes(c), + contentDecoded(false), internalId(0) {} -MessageImpl::MessageImpl(const char* chars, size_t count) : +MessageImpl::MessageImpl(const char* chars, size_t count) : priority(0), ttl(0), durable (false), redelivered(false), bytes(chars, count), + contentDecoded(false), internalId(0) {} +void MessageImpl::clear() +{ + replyTo = Address(); + subject = std::string(); + contentType = std::string(); + messageId = std::string(); + userId= std::string(); + correlationId = std::string(); + priority = 0; + ttl = 0; + durable = false; + redelivered = false; + headers = qpid::types::Variant::Map(); + + bytes = std::string(); + content = qpid::types::Variant(); + contentDecoded = false; + encoded = boost::shared_ptr<const qpid::messaging::amqp::EncodedMessage>(); + internalId = 0; +} + void MessageImpl::setReplyTo(const Address& d) { replyTo = d; @@ -167,21 +190,35 @@ void MessageImpl::setBytes(const char* chars, size_t count) bytes.assign(chars, count); updated(); } -void MessageImpl::appendBytes(const char* chars, size_t count) -{ - bytes.append(chars, count); - updated(); -} const std::string& MessageImpl::getBytes() const { - if (!bytes.size() && encoded) encoded->getBody(bytes); - return bytes; + if (encoded && !contentDecoded) { + encoded->getBody(bytes, content); + contentDecoded = true; + } + if (bytes.empty() && !content.isVoid()) return content.getString(); + else return bytes; } std::string& MessageImpl::getBytes() { - if (!bytes.size() && encoded) encoded->getBody(bytes); updated();//have to assume body may be edited, invalidating our message - return bytes; + if (bytes.empty() && !content.isVoid()) return content.getString(); + else return bytes; +} + +qpid::types::Variant& MessageImpl::getContent() +{ + updated();//have to assume content may be edited, invalidating our message + return content; +} + +const qpid::types::Variant& MessageImpl::getContent() const +{ + if (encoded && !contentDecoded) { + encoded->getBody(bytes, content); + contentDecoded = true; + } + return content; } void MessageImpl::setInternalId(qpid::framing::SequenceNumber i) { internalId = i; } @@ -197,7 +234,10 @@ void MessageImpl::updated() if (!userId.size() && encoded) encoded->getUserId(userId); if (!correlationId.size() && encoded) encoded->getCorrelationId(correlationId); if (!headers.size() && encoded) encoded->populate(headers); - if (!bytes.size() && encoded) encoded->getBody(bytes); + if (encoded && !contentDecoded) { + encoded->getBody(bytes, content); + contentDecoded = true; + } encoded.reset(); } @@ -210,5 +250,4 @@ const MessageImpl& MessageImplAccess::get(const Message& msg) { return *msg.impl; } - }} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/MessageImpl.h b/qpid/cpp/src/qpid/messaging/MessageImpl.h index 915c790153..647972de16 100644 --- a/qpid/cpp/src/qpid/messaging/MessageImpl.h +++ b/qpid/cpp/src/qpid/messaging/MessageImpl.h @@ -10,9 +10,9 @@ * 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 @@ -21,6 +21,9 @@ * under the License. * */ + +#include "qpid/messaging/ImportExport.h" + #include "qpid/messaging/Address.h" #include "qpid/types/Variant.h" #include "qpid/framing/SequenceNumber.h" @@ -47,6 +50,8 @@ class MessageImpl mutable qpid::types::Variant::Map headers; mutable std::string bytes; + mutable qpid::types::Variant content; + mutable bool contentDecoded; boost::shared_ptr<const qpid::messaging::amqp::EncodedMessage> encoded; qpid::framing::SequenceNumber internalId; @@ -56,43 +61,45 @@ class MessageImpl MessageImpl(const std::string& c); MessageImpl(const char* chars, size_t count); + void clear(); void setReplyTo(const Address& d); - const Address& getReplyTo() const; + QPID_MESSAGING_EXTERN const Address& getReplyTo() const; void setSubject(const std::string& s); - const std::string& getSubject() const; + QPID_MESSAGING_EXTERN const std::string& getSubject() const; void setContentType(const std::string& s); - const std::string& getContentType() const; + QPID_MESSAGING_EXTERN const std::string& getContentType() const; void setMessageId(const std::string&); - const std::string& getMessageId() const; + QPID_MESSAGING_EXTERN const std::string& getMessageId() const; void setUserId(const std::string& ); - const std::string& getUserId() const; + QPID_MESSAGING_EXTERN const std::string& getUserId() const; void setCorrelationId(const std::string& ); - const std::string& getCorrelationId() const; + QPID_MESSAGING_EXTERN const std::string& getCorrelationId() const; void setPriority(uint8_t); - uint8_t getPriority() const; + QPID_MESSAGING_EXTERN uint8_t getPriority() const; void setTtl(uint64_t); - uint64_t getTtl() const; + QPID_MESSAGING_EXTERN uint64_t getTtl() const; void setDurable(bool); - bool isDurable() const; + QPID_MESSAGING_EXTERN bool isDurable() const; void setRedelivered(bool); - bool isRedelivered() const; + QPID_MESSAGING_EXTERN bool isRedelivered() const; - const qpid::types::Variant::Map& getHeaders() const; + QPID_MESSAGING_EXTERN const qpid::types::Variant::Map& getHeaders() const; qpid::types::Variant::Map& getHeaders(); void setHeader(const std::string& key, const qpid::types::Variant& val); void setBytes(const std::string& bytes); void setBytes(const char* chars, size_t count); - void appendBytes(const char* chars, size_t count); - const std::string& getBytes() const; + QPID_MESSAGING_EXTERN const std::string& getBytes() const; std::string& getBytes(); + qpid::types::Variant& getContent(); + QPID_MESSAGING_EXTERN const qpid::types::Variant& getContent() const; - void setInternalId(qpid::framing::SequenceNumber id); - qpid::framing::SequenceNumber getInternalId(); + QPID_MESSAGING_EXTERN void setInternalId(qpid::framing::SequenceNumber id); + QPID_MESSAGING_EXTERN qpid::framing::SequenceNumber getInternalId(); void setEncoded(boost::shared_ptr<const qpid::messaging::amqp::EncodedMessage> e) { encoded = e; } boost::shared_ptr<const qpid::messaging::amqp::EncodedMessage> getEncoded() const { return encoded; } }; @@ -106,8 +113,8 @@ class Message; */ struct MessageImplAccess { - static MessageImpl& get(Message&); - static const MessageImpl& get(const Message&); + QPID_MESSAGING_EXTERN static MessageImpl& get(Message&); + QPID_MESSAGING_EXTERN static const MessageImpl& get(const Message&); }; }} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/ProtocolRegistry.h b/qpid/cpp/src/qpid/messaging/ProtocolRegistry.h index bcb62248a5..25e8bd4ec8 100644 --- a/qpid/cpp/src/qpid/messaging/ProtocolRegistry.h +++ b/qpid/cpp/src/qpid/messaging/ProtocolRegistry.h @@ -21,6 +21,9 @@ * under the License. * */ + +#include "qpid/messaging/ImportExport.h" + #include "qpid/types/Variant.h" namespace qpid { @@ -34,7 +37,7 @@ class ProtocolRegistry public: typedef ConnectionImpl* Factory(const std::string& url, const qpid::types::Variant::Map& options); static ConnectionImpl* create(const std::string& url, const qpid::types::Variant::Map& options); - static void add(const std::string& name, Factory* factory); + QPID_MESSAGING_EXTERN static void add(const std::string& name, Factory* factory); private: }; }} // namespace qpid::messaging diff --git a/qpid/cpp/src/qpid/messaging/Receiver.cpp b/qpid/cpp/src/qpid/messaging/Receiver.cpp index c45ebd6760..f60e5f55b3 100644 --- a/qpid/cpp/src/qpid/messaging/Receiver.cpp +++ b/qpid/cpp/src/qpid/messaging/Receiver.cpp @@ -21,6 +21,7 @@ #include "qpid/messaging/Receiver.h" #include "qpid/messaging/Address.h" #include "qpid/messaging/Message.h" +#include "qpid/messaging/MessageImpl.h" #include "qpid/messaging/ReceiverImpl.h" #include "qpid/messaging/Session.h" #include "qpid/messaging/PrivateImplRef.h" @@ -36,7 +37,11 @@ Receiver::~Receiver() { PI::dtor(*this); } Receiver& Receiver::operator=(const Receiver& s) { return PI::assign(*this, s); } bool Receiver::get(Message& message, Duration timeout) { return impl->get(message, timeout); } Message Receiver::get(Duration timeout) { return impl->get(timeout); } -bool Receiver::fetch(Message& message, Duration timeout) { return impl->fetch(message, timeout); } +bool Receiver::fetch(Message& message, Duration timeout) +{ + MessageImplAccess::get(message).clear(); + return impl->fetch(message, timeout); +} Message Receiver::fetch(Duration timeout) { return impl->fetch(timeout); } void Receiver::setCapacity(uint32_t c) { impl->setCapacity(c); } uint32_t Receiver::getCapacity() { return impl->getCapacity(); } diff --git a/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.cpp b/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.cpp index 9ecb46d872..beac50cdac 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.cpp @@ -57,6 +57,7 @@ const std::string PROPERTIES("properties"); const std::string MODE("mode"); const std::string BROWSE("browse"); const std::string CONSUME("consume"); +const std::string TIMEOUT("timeout"); const std::string TYPE("type"); const std::string TOPIC("topic"); @@ -69,6 +70,14 @@ const std::string FILTER("filter"); const std::string DESCRIPTOR("descriptor"); const std::string VALUE("value"); const std::string SUBJECT_FILTER("subject-filter"); +const std::string SOURCE("sender-source"); +const std::string TARGET("receiver-target"); + +//reliability options: +const std::string UNRELIABLE("unreliable"); +const std::string AT_MOST_ONCE("at-most-once"); +const std::string AT_LEAST_ONCE("at-least-once"); +const std::string EXACTLY_ONCE("exactly-once"); //distribution modes: const std::string MOVE("move"); @@ -83,12 +92,11 @@ const std::string DELETE_IF_EMPTY("delete-if-empty"); const std::string DELETE_IF_UNUSED_AND_EMPTY("delete-if-unused-and-empty"); const std::string CREATE_ON_DEMAND("create-on-demand"); -const std::string DUMMY("."); - const std::string X_DECLARE("x-declare"); const std::string X_BINDINGS("x-bindings"); const std::string X_SUBSCRIBE("x-subscribe"); const std::string ARGUMENTS("arguments"); +const std::string EXCHANGE_TYPE("exchange-type"); const std::vector<std::string> RECEIVER_MODES = boost::assign::list_of<std::string>(ALWAYS) (RECEIVER); const std::vector<std::string> SENDER_MODES = boost::assign::list_of<std::string>(ALWAYS) (SENDER); @@ -144,6 +152,16 @@ bool test(const Variant::Map& options, const std::string& name) } } +template <typename T> T get(const Variant::Map& options, const std::string& name, T defaultValue) +{ + Variant::Map::const_iterator j = options.find(name); + if (j == options.end()) { + return defaultValue; + } else { + return j->second; + } +} + bool bind(const Variant::Map& options, const std::string& name, std::string& variable) { Variant::Map::const_iterator j = options.find(name); @@ -208,6 +226,18 @@ void flatten(Variant::Map& base, const std::string& nested) base.erase(i); } } +bool replace(Variant::Map& map, const std::string& original, const std::string& desired) +{ + Variant::Map::iterator i = map.find(original); + if (i != map.end()) { + map[desired] = i->second; + map.erase(original); + return true; + } else { + return false; + } +} + void write(pn_data_t* data, const Variant& value); void write(pn_data_t* data, const Variant::Map& map) @@ -260,6 +290,8 @@ void write(pn_data_t* data, const Variant& value) break; } } +const uint32_t DEFAULT_DURABLE_TIMEOUT(15*60);//15 minutes +const uint32_t DEFAULT_TIMEOUT(0); } AddressHelper::AddressHelper(const Address& address) : @@ -268,6 +300,7 @@ AddressHelper::AddressHelper(const Address& address) : type(address.getType()), durableNode(false), durableLink(false), + timeout(0), browse(false) { verifier.verify(address); @@ -279,13 +312,14 @@ AddressHelper::AddressHelper(const Address& address) : bind(address, LINK, link); bind(node, PROPERTIES, properties); bind(node, CAPABILITIES, capabilities); + bind(link, RELIABILITY, reliability); durableNode = test(node, DURABLE); durableLink = test(link, DURABLE); + timeout = get(link, TIMEOUT, durableLink ? DEFAULT_DURABLE_TIMEOUT : DEFAULT_TIMEOUT); std::string mode; if (bind(address, MODE, mode)) { if (mode == BROWSE) { browse = true; - throw qpid::messaging::AddressError("Browse mode not yet supported over AMQP 1.0."); } else if (mode != CONSUME) { throw qpid::messaging::AddressError("Invalid value for mode; must be 'browse' or 'consume'."); } @@ -310,6 +344,7 @@ AddressHelper::AddressHelper(const Address& address) : Variant::Map::iterator i = node.find(X_DECLARE); if (i != node.end()) { Variant::Map x_declare = i->second.asMap(); + replace(x_declare, TYPE, EXCHANGE_TYPE); flatten(x_declare, ARGUMENTS); add(properties, x_declare); node.erase(i); @@ -391,16 +426,23 @@ void AddressHelper::checkAssertion(pn_terminus_t* terminus, CheckMode mode) QPID_LOG(debug, "checking assertions: " << capabilities); //ensure all desired capabilities have been offered std::set<std::string> desired; - if (type.size()) desired.insert(type); - if (durableNode) desired.insert(DURABLE); for (Variant::List::const_iterator i = capabilities.begin(); i != capabilities.end(); ++i) { - desired.insert(i->asString()); + if (*i != CREATE_ON_DEMAND) desired.insert(i->asString()); } pn_data_t* data = pn_terminus_capabilities(terminus); - while (pn_data_next(data)) { - pn_bytes_t c = pn_data_get_symbol(data); - std::string s(c.start, c.size); - desired.erase(s); + if (pn_data_next(data)) { + pn_type_t type = pn_data_type(data); + if (type == PN_ARRAY) { + pn_data_enter(data); + while (pn_data_next(data)) { + desired.erase(convert(pn_data_get_symbol(data))); + } + pn_data_exit(data); + } else if (type == PN_SYMBOL) { + desired.erase(convert(pn_data_get_symbol(data))); + } else { + QPID_LOG(error, "Skipping capabilities field of type " << pn_type_name(type)); + } } if (desired.size()) { @@ -492,6 +534,11 @@ bool AddressHelper::enabled(const std::string& policy, CheckMode mode) const return result; } +bool AddressHelper::isUnreliable() const +{ + return reliability == AT_MOST_ONCE || reliability == UNRELIABLE; +} + const qpid::types::Variant::Map& AddressHelper::getNodeProperties() const { return node; @@ -501,12 +548,32 @@ const qpid::types::Variant::Map& AddressHelper::getLinkProperties() const return link; } -void AddressHelper::configure(pn_terminus_t* terminus, CheckMode mode) +bool AddressHelper::getLinkSource(std::string& out) const +{ + return getLinkOption(SOURCE, out); +} + +bool AddressHelper::getLinkTarget(std::string& out) const +{ + return getLinkOption(TARGET, out); +} + +bool AddressHelper::getLinkOption(const std::string& name, std::string& out) const +{ + qpid::types::Variant::Map::const_iterator i = link.find(name); + if (i != link.end()) { + out = i->second.asString(); + return true; + } else { + return false; + } +} + +void AddressHelper::configure(pn_link_t* link, pn_terminus_t* terminus, CheckMode mode) { bool createOnDemand(false); if (isTemporary) { //application expects a name to be generated - pn_terminus_set_address(terminus, DUMMY.c_str());//workaround for PROTON-277 pn_terminus_set_dynamic(terminus, true); setNodeProperties(terminus); } else { @@ -517,43 +584,57 @@ void AddressHelper::configure(pn_terminus_t* terminus, CheckMode mode) createOnDemand = true; } } + setCapabilities(terminus, createOnDemand); if (durableLink) { pn_terminus_set_durability(terminus, PN_DELIVERIES); } - if (mode == FOR_RECEIVER && browse) { - //when PROTON-139 is resolved, set the required delivery-mode - } - //set filter(s): - if (mode == FOR_RECEIVER && !filters.empty()) { - pn_data_t* filter = pn_terminus_filter(terminus); - pn_data_put_map(filter); - pn_data_enter(filter); - for (std::vector<Filter>::const_iterator i = filters.begin(); i != filters.end(); ++i) { - pn_data_put_symbol(filter, convert(i->name)); - pn_data_put_described(filter); + if (mode == FOR_RECEIVER) { + if (timeout) pn_terminus_set_timeout(terminus, timeout); + if (browse) { + pn_terminus_set_distribution_mode(terminus, PN_DIST_MODE_COPY); + } + //set filter(s): + if (!filters.empty()) { + pn_data_t* filter = pn_terminus_filter(terminus); + pn_data_put_map(filter); pn_data_enter(filter); - if (i->descriptorSymbol.size()) { - pn_data_put_symbol(filter, convert(i->descriptorSymbol)); - } else { - pn_data_put_ulong(filter, i->descriptorCode); + for (std::vector<Filter>::const_iterator i = filters.begin(); i != filters.end(); ++i) { + pn_data_put_symbol(filter, convert(i->name)); + pn_data_put_described(filter); + pn_data_enter(filter); + if (i->descriptorSymbol.size()) { + pn_data_put_symbol(filter, convert(i->descriptorSymbol)); + } else { + pn_data_put_ulong(filter, i->descriptorCode); + } + write(filter, i->value); + pn_data_exit(filter); } - write(filter, i->value); pn_data_exit(filter); } - pn_data_exit(filter); } - + if (isUnreliable()) { + pn_link_set_snd_settle_mode(link, PN_SND_SETTLED); + } } void AddressHelper::setCapabilities(pn_terminus_t* terminus, bool create) { + if (create) capabilities.push_back(CREATE_ON_DEMAND); + if (!type.empty()) capabilities.push_back(type); + if (durableNode) capabilities.push_back(DURABLE); + pn_data_t* data = pn_terminus_capabilities(terminus); - if (create) pn_data_put_symbol(data, convert(CREATE_ON_DEMAND)); - if (type.size()) pn_data_put_symbol(data, convert(type)); - if (durableNode) pn_data_put_symbol(data, convert(DURABLE)); - for (qpid::types::Variant::List::const_iterator i = capabilities.begin(); i != capabilities.end(); ++i) { - pn_data_put_symbol(data, convert(i->asString())); + if (capabilities.size() == 1) { + pn_data_put_symbol(data, convert(capabilities.front().asString())); + } else if (capabilities.size() > 1) { + pn_data_put_array(data, false, PN_SYMBOL); + pn_data_enter(data); + for (qpid::types::Variant::List::const_iterator i = capabilities.begin(); i != capabilities.end(); ++i) { + pn_data_put_symbol(data, convert(i->asString())); + } + pn_data_exit(data); } } std::string AddressHelper::getLinkName(const Address& address) @@ -632,6 +713,9 @@ Verifier::Verifier() link[NAME] = true; link[DURABLE] = true; link[RELIABILITY] = true; + link[TIMEOUT] = true; + link[SOURCE] = true; + link[TARGET] = true; link[X_SUBSCRIBE] = true; link[X_DECLARE] = true; link[X_BINDINGS] = true; diff --git a/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.h b/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.h index 4608981a69..3ee58cad8d 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.h +++ b/qpid/cpp/src/qpid/messaging/amqp/AddressHelper.h @@ -24,6 +24,7 @@ #include "qpid/types/Variant.h" #include <vector> +struct pn_link_t; struct pn_terminus_t; namespace qpid { @@ -36,10 +37,13 @@ class AddressHelper enum CheckMode {FOR_RECEIVER, FOR_SENDER}; AddressHelper(const Address& address); - void configure(pn_terminus_t* terminus, CheckMode mode); + void configure(pn_link_t* link, pn_terminus_t* terminus, CheckMode mode); void checkAssertion(pn_terminus_t* terminus, CheckMode mode); + bool isUnreliable() const; const qpid::types::Variant::Map& getNodeProperties() const; + bool getLinkSource(std::string& out) const; + bool getLinkTarget(std::string& out) const; const qpid::types::Variant::Map& getLinkProperties() const; static std::string getLinkName(const Address& address); private: @@ -66,8 +70,10 @@ class AddressHelper qpid::types::Variant::List capabilities; std::string name; std::string type; + std::string reliability; bool durableNode; bool durableLink; + uint32_t timeout; bool browse; std::vector<Filter> filters; @@ -82,6 +88,7 @@ class AddressHelper void addFilters(const qpid::types::Variant::List&); void confirmFilter(const std::string& descriptor); void confirmFilter(uint64_t descriptor); + bool getLinkOption(const std::string& name, std::string& out) const; }; }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.cpp b/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.cpp index 72bba608d1..dba5cb1e1c 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.cpp @@ -45,18 +45,17 @@ namespace qpid { namespace messaging { namespace amqp { -ConnectionContext::ConnectionContext(const std::string& u, const qpid::types::Variant::Map& o) +ConnectionContext::ConnectionContext(const std::string& url, const qpid::types::Variant::Map& o) : qpid::messaging::ConnectionOptions(o), - url(u, protocol.empty() ? qpid::Address::TCP : protocol), engine(pn_transport()), connection(pn_connection()), //note: disabled read/write of header as now handled by engine writeHeader(false), readHeader(false), haveOutput(false), - state(DISCONNECTED), - codecSwitch(*this) + state(DISCONNECTED) { + urls.insert(urls.begin(), url); if (pn_transport_bind(engine, connection)) { //error } @@ -77,84 +76,28 @@ ConnectionContext::~ConnectionContext() pn_connection_free(connection); } -namespace { -const std::string COLON(":"); -} -void ConnectionContext::open() -{ - qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); - if (state != DISCONNECTED) throw qpid::messaging::ConnectionError("Connection was already opened!"); - if (!driver) driver = DriverImpl::getDefault(); - if (url.getUser().size()) username = url.getUser(); - if (url.getPass().size()) password = url.getPass(); - - for (Url::const_iterator i = url.begin(); state != CONNECTED && i != url.end(); ++i) { - transport = driver->getTransport(i->protocol, *this); - std::stringstream port; - port << i->port; - id = i->host + COLON + port.str(); - if (useSasl()) { - sasl = std::auto_ptr<Sasl>(new Sasl(id, *this, i->host)); - } - state = CONNECTING; - try { - QPID_LOG(debug, id << " Connecting ..."); - transport->connect(i->host, port.str()); - } catch (const std::exception& e) { - QPID_LOG(info, id << " Error while connecting: " << e.what()); - } - while (state == CONNECTING) { - lock.wait(); - } - if (state == DISCONNECTED) { - QPID_LOG(debug, id << " Failed to connect"); - transport = boost::shared_ptr<Transport>(); - } else { - QPID_LOG(debug, id << " Connected"); - } - } - - if (state != CONNECTED) throw qpid::messaging::TransportFailure(QPID_MSG("Could not connect to " << url)); - - if (sasl.get()) { - wakeupDriver(); - while (!sasl->authenticated()) { - QPID_LOG(debug, id << " Waiting to be authenticated..."); - wait(); - } - QPID_LOG(debug, id << " Authenticated"); - } - - QPID_LOG(debug, id << " Opening..."); - setProperties(); - pn_connection_open(connection); - wakeupDriver(); //want to write - while (pn_connection_state(connection) & PN_REMOTE_UNINIT) { - wait(); - } - if (!(pn_connection_state(connection) & PN_REMOTE_ACTIVE)) { - throw qpid::messaging::ConnectionError("Failed to open connection"); - } - QPID_LOG(debug, id << " Opened"); -} - bool ConnectionContext::isOpen() const { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); - return pn_connection_state(connection) & (PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE); + return state == CONNECTED && pn_connection_state(connection) & (PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE); } void ConnectionContext::endSession(boost::shared_ptr<SessionContext> ssn) { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); - //wait for outstanding sends to settle - while (!ssn->settled()) { - QPID_LOG(debug, "Waiting for sends to settle before closing"); - wait(ssn);//wait until message has been confirmed + if (pn_session_state(ssn->session) & PN_REMOTE_ACTIVE) { + //wait for outstanding sends to settle + while (!ssn->settled()) { + QPID_LOG(debug, "Waiting for sends to settle before closing"); + wait(ssn);//wait until message has been confirmed + } + } + + if (pn_session_state(ssn->session) & PN_REMOTE_ACTIVE) { + pn_session_close(ssn->session); } + sessions.erase(ssn->getName()); - pn_session_close(ssn->session); - //TODO: need to destroy session and remove context from map wakeupDriver(); } @@ -260,6 +203,7 @@ bool ConnectionContext::get(boost::shared_ptr<SessionContext> ssn, boost::shared if (current) { qpid::messaging::MessageImpl& impl = MessageImplAccess::get(message); boost::shared_ptr<EncodedMessage> encoded(new EncodedMessage(pn_delivery_pending(current))); + encoded->setNestAnnotationsOption(nestAnnotations); ssize_t read = pn_link_recv(lnk->receiver, encoded->getData(), encoded->getSize()); if (read < 0) throw qpid::messaging::MessagingException("Failed to read message"); encoded->trim((size_t) read); @@ -290,55 +234,61 @@ void ConnectionContext::acknowledge(boost::shared_ptr<SessionContext> ssn, qpid: wakeupDriver(); } +void ConnectionContext::detach(boost::shared_ptr<SessionContext> ssn, boost::shared_ptr<SenderContext> lnk) +{ + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); + if (pn_link_state(lnk->sender) & PN_LOCAL_ACTIVE) { + lnk->close(); + } + wakeupDriver(); + while (pn_link_state(lnk->sender) & PN_REMOTE_ACTIVE) { + wait(); + } + ssn->removeSender(lnk->getName()); +} + +void ConnectionContext::detach(boost::shared_ptr<SessionContext> ssn, boost::shared_ptr<ReceiverContext> lnk) +{ + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); + if (pn_link_state(lnk->receiver) & PN_LOCAL_ACTIVE) { + lnk->close(); + } + wakeupDriver(); + while (pn_link_state(lnk->receiver) & PN_REMOTE_ACTIVE) { + wait(); + } + ssn->removeReceiver(lnk->getName()); +} void ConnectionContext::attach(boost::shared_ptr<SessionContext> ssn, boost::shared_ptr<SenderContext> lnk) { + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); lnk->configure(); - attach(ssn->session, (pn_link_t*) lnk->sender); - pn_terminus_t* t = pn_link_remote_target(lnk->sender); - if (!pn_terminus_get_address(t)) { - std::string msg("No such target : "); - msg += lnk->getTarget(); - QPID_LOG(debug, msg); - throw qpid::messaging::NotFound(msg); - } else if (AddressImpl::isTemporary(lnk->address)) { - lnk->address.setName(pn_terminus_get_address(t)); - QPID_LOG(debug, "Dynamic target name set to " << lnk->address.getName()); - } - lnk->verify(t); + attach(ssn, lnk->sender); checkClosed(ssn, lnk); + lnk->verify(); QPID_LOG(debug, "Attach succeeded to " << lnk->getTarget()); } void ConnectionContext::attach(boost::shared_ptr<SessionContext> ssn, boost::shared_ptr<ReceiverContext> lnk) { + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); lnk->configure(); - attach(ssn->session, lnk->receiver, lnk->capacity); - pn_terminus_t* s = pn_link_remote_source(lnk->receiver); - if (!pn_terminus_get_address(s)) { - std::string msg("No such source : "); - msg += lnk->getSource(); - QPID_LOG(debug, msg); - throw qpid::messaging::NotFound(msg); - } else if (AddressImpl::isTemporary(lnk->address)) { - lnk->address.setName(pn_terminus_get_address(s)); - QPID_LOG(debug, "Dynamic source name set to " << lnk->address.getName()); - } - lnk->verify(s); + attach(ssn, lnk->receiver, lnk->capacity); checkClosed(ssn, lnk); + lnk->verify(); QPID_LOG(debug, "Attach succeeded from " << lnk->getSource()); } -void ConnectionContext::attach(pn_session_t* /*session*/, pn_link_t* link, int credit) +void ConnectionContext::attach(boost::shared_ptr<SessionContext> ssn, pn_link_t* link, int credit) { - qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); pn_link_open(link); QPID_LOG(debug, "Link attach sent for " << link << ", state=" << pn_link_state(link)); if (credit) pn_link_flow(link, credit); wakeupDriver(); while (pn_link_state(link) & PN_REMOTE_UNINIT) { QPID_LOG(debug, "Waiting for confirmation of link attach for " << link << ", state=" << pn_link_state(link) << "..."); - wait(); + wait(ssn); } } @@ -347,12 +297,12 @@ void ConnectionContext::send(boost::shared_ptr<SessionContext> ssn, boost::share qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); checkClosed(ssn); SenderContext::Delivery* delivery(0); - while (!(delivery = snd->send(message))) { + while (!snd->send(message, &delivery)) { QPID_LOG(debug, "Waiting for capacity..."); wait(ssn, snd);//wait for capacity } wakeupDriver(); - if (sync) { + if (sync && delivery) { while (!delivery->accepted()) { QPID_LOG(debug, "Waiting for confirmation..."); wait(ssn, snd);//wait until message has been confirmed @@ -427,10 +377,32 @@ pn_state_t REQUIRES_CLOSE = PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED; pn_state_t IS_CLOSED = PN_LOCAL_CLOSED | PN_REMOTE_CLOSED; } +void ConnectionContext::reset() +{ + pn_transport_free(engine); + pn_connection_free(connection); + + engine = pn_transport(); + connection = pn_connection(); + pn_connection_set_container(connection, identifier.c_str()); + bool enableTrace(false); + QPID_LOG_TEST_CAT(trace, protocol, enableTrace); + if (enableTrace) pn_transport_trace(engine, PN_TRACE_FRM); + for (SessionMap::iterator i = sessions.begin(); i != sessions.end(); ++i) { + i->second->reset(connection); + } + pn_transport_bind(engine, connection); +} + void ConnectionContext::check() { if (state == DISCONNECTED) { - throw qpid::messaging::TransportFailure("Disconnected"); + if (ConnectionOptions::reconnect) { + reset(); + autoconnect(); + } else { + throw qpid::messaging::TransportFailure("Disconnected (reconnect disabled)"); + } } if ((pn_connection_state(connection) & REQUIRES_CLOSE) == REQUIRES_CLOSE) { pn_connection_close(connection); @@ -480,9 +452,17 @@ void ConnectionContext::waitUntil(boost::shared_ptr<SessionContext> ssn, boost:: } void ConnectionContext::checkClosed(boost::shared_ptr<SessionContext> ssn) { + check(); if ((pn_session_state(ssn->session) & REQUIRES_CLOSE) == REQUIRES_CLOSE) { + pn_condition_t* error = pn_session_remote_condition(ssn->session); + std::stringstream text; + if (pn_condition_is_set(error)) { + text << "Session ended by peer with " << pn_condition_get_name(error) << ": " << pn_condition_get_description(error); + } else { + text << "Session ended by peer"; + } pn_session_close(ssn->session); - throw qpid::messaging::SessionError("Session ended by peer"); + throw qpid::messaging::SessionError(text.str()); } else if ((pn_session_state(ssn->session) & IS_CLOSED) == IS_CLOSED) { throw qpid::messaging::SessionError("Session has ended"); } @@ -513,6 +493,31 @@ void ConnectionContext::checkClosed(boost::shared_ptr<SessionContext> ssn, pn_li throw qpid::messaging::LinkError("Link is not attached"); } } + +void ConnectionContext::restartSession(boost::shared_ptr<SessionContext> s) +{ + pn_session_open(s->session); + wakeupDriver(); + while (pn_session_state(s->session) & PN_REMOTE_UNINIT) { + wait(); + } + + for (SessionContext::SenderMap::iterator i = s->senders.begin(); i != s->senders.end(); ++i) { + QPID_LOG(debug, id << " reattaching sender " << i->first); + attach(s, i->second->sender); + i->second->verify(); + QPID_LOG(debug, id << " sender " << i->first << " reattached"); + i->second->resend(); + } + for (SessionContext::ReceiverMap::iterator i = s->receivers.begin(); i != s->receivers.end(); ++i) { + QPID_LOG(debug, id << " reattaching receiver " << i->first); + attach(s, i->second->receiver, i->second->capacity); + i->second->verify(); + QPID_LOG(debug, id << " receiver " << i->first << " reattached"); + } + wakeupDriver(); +} + boost::shared_ptr<SessionContext> ConnectionContext::newSession(bool transactional, const std::string& n) { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); @@ -521,13 +526,14 @@ boost::shared_ptr<SessionContext> ConnectionContext::newSession(bool transaction SessionMap::const_iterator i = sessions.find(name); if (i == sessions.end()) { boost::shared_ptr<SessionContext> s(new SessionContext(connection)); + s->setName(name); s->session = pn_session(connection); pn_session_open(s->session); - sessions[name] = s; wakeupDriver(); while (pn_session_state(s->session) & PN_REMOTE_UNINIT) { wait(); } + sessions[name] = s; return s; } else { throw qpid::messaging::KeyError(std::string("Session already exists: ") + name); @@ -554,7 +560,7 @@ std::string ConnectionContext::getAuthenticatedUsername() return sasl.get() ? sasl->getAuthenticatedUsername() : std::string(); } -std::size_t ConnectionContext::decode(const char* buffer, std::size_t size) +std::size_t ConnectionContext::decodePlain(const char* buffer, std::size_t size) { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); QPID_LOG(trace, id << " decode(" << size << ")"); @@ -584,7 +590,7 @@ std::size_t ConnectionContext::decode(const char* buffer, std::size_t size) } } -std::size_t ConnectionContext::encode(char* buffer, std::size_t size) +std::size_t ConnectionContext::encodePlain(char* buffer, std::size_t size) { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); QPID_LOG(trace, id << " encode(" << size << ")"); @@ -611,7 +617,7 @@ std::size_t ConnectionContext::encode(char* buffer, std::size_t size) return 0; } } -bool ConnectionContext::canEncode() +bool ConnectionContext::canEncodePlain() { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); return haveOutput && state == CONNECTED; @@ -685,47 +691,46 @@ bool ConnectionContext::useSasl() qpid::sys::Codec& ConnectionContext::getCodec() { - return codecSwitch; + return *this; } -ConnectionContext::CodecSwitch::CodecSwitch(ConnectionContext& p) : parent(p) {} -std::size_t ConnectionContext::CodecSwitch::decode(const char* buffer, std::size_t size) +std::size_t ConnectionContext::decode(const char* buffer, std::size_t size) { - qpid::sys::ScopedLock<qpid::sys::Monitor> l(parent.lock); + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); size_t decoded = 0; - if (parent.sasl.get() && !parent.sasl->authenticated()) { - decoded = parent.sasl->decode(buffer, size); - if (!parent.sasl->authenticated()) return decoded; + if (sasl.get() && !sasl->authenticated()) { + decoded = sasl->decode(buffer, size); + if (!sasl->authenticated()) return decoded; } if (decoded < size) { - if (parent.sasl.get() && parent.sasl->getSecurityLayer()) decoded += parent.sasl->getSecurityLayer()->decode(buffer+decoded, size-decoded); - else decoded += parent.decode(buffer+decoded, size-decoded); + if (sasl.get() && sasl->getSecurityLayer()) decoded += sasl->getSecurityLayer()->decode(buffer+decoded, size-decoded); + else decoded += decodePlain(buffer+decoded, size-decoded); } return decoded; } -std::size_t ConnectionContext::CodecSwitch::encode(char* buffer, std::size_t size) +std::size_t ConnectionContext::encode(char* buffer, std::size_t size) { - qpid::sys::ScopedLock<qpid::sys::Monitor> l(parent.lock); + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); size_t encoded = 0; - if (parent.sasl.get() && parent.sasl->canEncode()) { - encoded += parent.sasl->encode(buffer, size); - if (!parent.sasl->authenticated()) return encoded; + if (sasl.get() && sasl->canEncode()) { + encoded += sasl->encode(buffer, size); + if (!sasl->authenticated()) return encoded; } if (encoded < size) { - if (parent.sasl.get() && parent.sasl->getSecurityLayer()) encoded += parent.sasl->getSecurityLayer()->encode(buffer+encoded, size-encoded); - else encoded += parent.encode(buffer+encoded, size-encoded); + if (sasl.get() && sasl->getSecurityLayer()) encoded += sasl->getSecurityLayer()->encode(buffer+encoded, size-encoded); + else encoded += encodePlain(buffer+encoded, size-encoded); } return encoded; } -bool ConnectionContext::CodecSwitch::canEncode() +bool ConnectionContext::canEncode() { - qpid::sys::ScopedLock<qpid::sys::Monitor> l(parent.lock); - if (parent.sasl.get()) { - if (parent.sasl->canEncode()) return true; - else if (!parent.sasl->authenticated()) return false; - else if (parent.sasl->getSecurityLayer()) return parent.sasl->getSecurityLayer()->canEncode(); + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); + if (sasl.get()) { + if (sasl->canEncode()) return true; + else if (!sasl->authenticated()) return false; + else if (sasl->getSecurityLayer()) return sasl->getSecurityLayer()->canEncode(); } - return parent.canEncode(); + return canEncodePlain(); } namespace { @@ -742,10 +747,6 @@ pn_bytes_t convert(const std::string& s) } void ConnectionContext::setProperties() { - /** - * Enable when proton 0.5 is released and qpidc has been updated - * to use it - * pn_data_t* data = pn_connection_properties(connection); pn_data_put_map(data); pn_data_enter(data); @@ -760,7 +761,206 @@ void ConnectionContext::setProperties() pn_data_put_symbol(data, convert(CLIENT_PPID)); pn_data_put_int(data, sys::SystemInfo::getParentProcessId()); pn_data_exit(data); - **/ } +const qpid::sys::SecuritySettings* ConnectionContext::getTransportSecuritySettings() +{ + return transport ? transport->getSecuritySettings() : 0; +} + +void ConnectionContext::open() +{ + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); + if (state != DISCONNECTED) throw qpid::messaging::ConnectionError("Connection was already opened!"); + if (!driver) driver = DriverImpl::getDefault(); + + autoconnect(); +} + + +namespace { +std::string asString(const std::vector<std::string>& v) { + std::stringstream os; + os << "["; + for(std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i ) { + if (i != v.begin()) os << ", "; + os << *i; + } + os << "]"; + return os.str(); +} +double FOREVER(std::numeric_limits<double>::max()); +bool expired(const sys::AbsTime& start, double timeout) +{ + if (timeout == 0) return true; + if (timeout == FOREVER) return false; + qpid::sys::Duration used(start, qpid::sys::now()); + qpid::sys::Duration allowed((int64_t)(timeout*qpid::sys::TIME_SEC)); + return allowed < used; +} +const std::string COLON(":"); +} + +void ConnectionContext::autoconnect() +{ + qpid::sys::AbsTime started(qpid::sys::now()); + QPID_LOG(debug, "Starting connection, urls=" << asString(urls)); + for (double i = minReconnectInterval; !tryConnect(); i = std::min(i*2, maxReconnectInterval)) { + if (!ConnectionOptions::reconnect) { + throw qpid::messaging::TransportFailure("Failed to connect (reconnect disabled)"); + } + if (limit >= 0 && retries++ >= limit) { + throw qpid::messaging::TransportFailure("Failed to connect within reconnect limit"); + } + if (expired(started, timeout)) { + throw qpid::messaging::TransportFailure("Failed to connect within reconnect timeout"); + } + QPID_LOG(debug, "Connection retry in " << i*1000*1000 << " microseconds, urls=" + << asString(urls)); + qpid::sys::usleep(int64_t(i*1000*1000)); // Sleep in microseconds. + } + retries = 0; +} + +bool ConnectionContext::tryConnect() +{ + for (std::vector<std::string>::const_iterator i = urls.begin(); i != urls.end(); ++i) { + try { + QPID_LOG(info, "Trying to connect to " << *i << "..."); + if (tryConnect(qpid::Url(*i, protocol.empty() ? qpid::Address::TCP : protocol))) { + return true; + } + } catch (const qpid::messaging::TransportFailure& e) { + QPID_LOG(info, "Failed to connect to " << *i << ": " << e.what()); + } + } + return false; +} + +void ConnectionContext::reconnect(const std::string& url) +{ + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); + if (state != DISCONNECTED) throw qpid::messaging::ConnectionError("Connection was already opened!"); + if (!driver) driver = DriverImpl::getDefault(); + reset(); + if (!tryConnect(qpid::Url(url, protocol.empty() ? qpid::Address::TCP : protocol))) { + throw qpid::messaging::TransportFailure("Failed to connect"); + } +} + +void ConnectionContext::reconnect() +{ + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); + if (state != DISCONNECTED) throw qpid::messaging::ConnectionError("Connection was already opened!"); + if (!driver) driver = DriverImpl::getDefault(); + reset(); + if (!tryConnect()) { + throw qpid::messaging::TransportFailure("Failed to reconnect"); + } +} + +bool ConnectionContext::tryConnect(const Url& url) +{ + if (url.getUser().size()) username = url.getUser(); + if (url.getPass().size()) password = url.getPass(); + + for (Url::const_iterator i = url.begin(); i != url.end(); ++i) { + if (tryConnect(*i)) { + QPID_LOG(info, "Connected to " << *i); + setCurrentUrl(*i); + if (sasl.get()) { + wakeupDriver(); + while (!sasl->authenticated()) { + QPID_LOG(debug, id << " Waiting to be authenticated..."); + wait(); + } + QPID_LOG(debug, id << " Authenticated"); + } + + QPID_LOG(debug, id << " Opening..."); + setProperties(); + pn_connection_open(connection); + wakeupDriver(); //want to write + while (pn_connection_state(connection) & PN_REMOTE_UNINIT) { + wait(); + } + if (!(pn_connection_state(connection) & PN_REMOTE_ACTIVE)) { + throw qpid::messaging::ConnectionError("Failed to open connection"); + } + QPID_LOG(debug, id << " Opened"); + + return restartSessions(); + } + } + return false; +} + +void ConnectionContext::setCurrentUrl(const qpid::Address& a) +{ + std::stringstream u; + u << a; + currentUrl = u.str(); +} + +std::string ConnectionContext::getUrl() const +{ + qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); + if (state == CONNECTED) { + return currentUrl; + } else { + return std::string(); + } +} + + +bool ConnectionContext::tryConnect(const qpid::Address& address) +{ + transport = driver->getTransport(address.protocol, *this); + std::stringstream port; + port << address.port; + id = address.host + COLON + port.str(); + if (useSasl()) { + sasl = std::auto_ptr<Sasl>(new Sasl(id, *this, address.host)); + } + state = CONNECTING; + try { + QPID_LOG(debug, id << " Connecting ..."); + transport->connect(address.host, port.str()); + bool waiting(true); + while (waiting) { + switch (state) { + case CONNECTED: + QPID_LOG(debug, id << " Connected"); + return true; + case CONNECTING: + lock.wait(); + break; + case DISCONNECTED: + waiting = false; + QPID_LOG(debug, id << " Failed to connect"); + break; + } + } + } catch (const std::exception& e) { + QPID_LOG(info, id << " Error while connecting: " << e.what()); + state = DISCONNECTED; + } + transport = boost::shared_ptr<Transport>(); + return false; +} + +bool ConnectionContext::restartSessions() +{ + try { + for (SessionMap::iterator i = sessions.begin(); i != sessions.end(); ++i) { + restartSession(i->second); + } + return true; + } catch (const qpid::TransportFailure& e) { + QPID_LOG(debug, "Connection Failed to re-initialize sessions: " << e.what()); + return false; + } +} + + }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.h b/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.h index 37d73ea456..2fdba7a3b2 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.h +++ b/qpid/cpp/src/qpid/messaging/amqp/ConnectionContext.h @@ -44,6 +44,9 @@ namespace qpid { namespace framing { class ProtocolVersion; } +namespace sys { +struct SecuritySettings; +} namespace messaging { class Duration; class Message; @@ -72,6 +75,8 @@ class ConnectionContext : public qpid::sys::ConnectionCodec, public qpid::messag void endSession(boost::shared_ptr<SessionContext>); void attach(boost::shared_ptr<SessionContext>, boost::shared_ptr<SenderContext>); void attach(boost::shared_ptr<SessionContext>, boost::shared_ptr<ReceiverContext>); + void detach(boost::shared_ptr<SessionContext>, boost::shared_ptr<SenderContext>); + void detach(boost::shared_ptr<SessionContext>, boost::shared_ptr<ReceiverContext>); void send(boost::shared_ptr<SessionContext>, boost::shared_ptr<SenderContext> ctxt, const qpid::messaging::Message& message, bool sync); bool fetch(boost::shared_ptr<SessionContext> ssn, boost::shared_ptr<ReceiverContext> lnk, qpid::messaging::Message& message, qpid::messaging::Duration timeout); bool get(boost::shared_ptr<SessionContext> ssn, boost::shared_ptr<ReceiverContext> lnk, qpid::messaging::Message& message, qpid::messaging::Duration timeout); @@ -101,10 +106,13 @@ class ConnectionContext : public qpid::sys::ConnectionCodec, public qpid::messag framing::ProtocolVersion getVersion() const; //additionally, Transport needs: void opened();//signal successful connection + void reconnect(const std::string& url); + void reconnect(); + std::string getUrl() const; + const qpid::sys::SecuritySettings* getTransportSecuritySettings(); private: typedef std::map<std::string, boost::shared_ptr<SessionContext> > SessionMap; - qpid::Url url; boost::shared_ptr<DriverImpl> driver; boost::shared_ptr<Transport> transport; @@ -117,23 +125,13 @@ class ConnectionContext : public qpid::sys::ConnectionCodec, public qpid::messag bool readHeader; bool haveOutput; std::string id; + std::string currentUrl; enum { DISCONNECTED, CONNECTING, CONNECTED } state; std::auto_ptr<Sasl> sasl; - class CodecSwitch : public qpid::sys::Codec - { - public: - CodecSwitch(ConnectionContext&); - std::size_t decode(const char* buffer, std::size_t size); - std::size_t encode(char* buffer, std::size_t size); - bool canEncode(); - private: - ConnectionContext& parent; - }; - CodecSwitch codecSwitch; void check(); void wait(); @@ -149,7 +147,19 @@ class ConnectionContext : public qpid::sys::ConnectionCodec, public qpid::messag void checkClosed(boost::shared_ptr<SessionContext>, boost::shared_ptr<SenderContext>); void checkClosed(boost::shared_ptr<SessionContext>, pn_link_t*); void wakeupDriver(); - void attach(pn_session_t*, pn_link_t*, int credit=0); + void attach(boost::shared_ptr<SessionContext>, pn_link_t*, int credit=0); + void autoconnect(); + bool tryConnect(); + bool tryConnect(const qpid::Url& url); + bool tryConnect(const qpid::Address& address); + void reset(); + bool restartSessions(); + void restartSession(boost::shared_ptr<SessionContext>); + void setCurrentUrl(const qpid::Address&); + + std::size_t decodePlain(const char* buffer, std::size_t size); + std::size_t encodePlain(char* buffer, std::size_t size); + bool canEncodePlain(); std::size_t readProtocolHeader(const char* buffer, std::size_t size); std::size_t writeProtocolHeader(char* buffer, std::size_t size); diff --git a/qpid/cpp/src/qpid/messaging/amqp/ConnectionHandle.cpp b/qpid/cpp/src/qpid/messaging/amqp/ConnectionHandle.cpp index 0c4ec2bfcb..c1ab108a61 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/ConnectionHandle.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/ConnectionHandle.cpp @@ -81,4 +81,17 @@ std::string ConnectionHandle::getAuthenticatedUsername() return connection->getAuthenticatedUsername(); } +void ConnectionHandle::reconnect(const std::string& url) +{ + connection->reconnect(url); +} +void ConnectionHandle::reconnect() +{ + connection->reconnect(); +} +std::string ConnectionHandle::getUrl() const +{ + return connection->getUrl(); +} + }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/ConnectionHandle.h b/qpid/cpp/src/qpid/messaging/amqp/ConnectionHandle.h index d1eb27f6de..0238313f93 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/ConnectionHandle.h +++ b/qpid/cpp/src/qpid/messaging/amqp/ConnectionHandle.h @@ -49,6 +49,9 @@ class ConnectionHandle : public qpid::messaging::ConnectionImpl Session getSession(const std::string& name) const; void setOption(const std::string& name, const qpid::types::Variant& value); std::string getAuthenticatedUsername(); + void reconnect(const std::string& url); + void reconnect(); + std::string getUrl() const; private: boost::shared_ptr<ConnectionContext> connection; }; diff --git a/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.cpp b/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.cpp index b4e0819980..266060c117 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.cpp @@ -22,26 +22,31 @@ #include "qpid/messaging/Address.h" #include "qpid/messaging/MessageImpl.h" #include "qpid/amqp/Decoder.h" +#include "qpid/amqp/DataBuilder.h" +#include "qpid/amqp/ListBuilder.h" +#include "qpid/amqp/MapBuilder.h" +#include "qpid/amqp/typecodes.h" +#include "qpid/types/encodings.h" +#include "qpid/log/Statement.h" #include <boost/lexical_cast.hpp> #include <string.h> namespace qpid { namespace messaging { namespace amqp { - using namespace qpid::amqp; -EncodedMessage::EncodedMessage(size_t s) : size(s), data(size ? new char[size] : 0) +EncodedMessage::EncodedMessage(size_t s) : size(s), data(size ? new char[size] : 0), nestAnnotations(false) { init(); } -EncodedMessage::EncodedMessage() : size(0), data(0) +EncodedMessage::EncodedMessage() : size(0), data(0), nestAnnotations(false) { init(); } -EncodedMessage::EncodedMessage(const EncodedMessage& other) : size(other.size), data(size ? new char[size] : 0) +EncodedMessage::EncodedMessage(const EncodedMessage& other) : size(other.size), data(size ? new char[size] : 0), nestAnnotations(false) { init(); } @@ -105,6 +110,8 @@ void EncodedMessage::init(qpid::messaging::MessageImpl& impl) } } +void EncodedMessage::setNestAnnotationsOption(bool b) { nestAnnotations = b; } + void EncodedMessage::populate(qpid::types::Variant::Map& map) const { //decode application properties @@ -139,14 +146,20 @@ void EncodedMessage::populate(qpid::types::Variant::Map& map) const } //add in any annotations if (deliveryAnnotations) { - qpid::types::Variant::Map& annotations = map["x-amqp-delivery-annotations"].asMap(); qpid::amqp::Decoder decoder(deliveryAnnotations.data, deliveryAnnotations.size); - decoder.readMap(annotations); + if (nestAnnotations) { + map["x-amqp-delivery-annotations"] = decoder.readMap(); + } else { + decoder.readMap(map); + } } if (messageAnnotations) { - qpid::types::Variant::Map& annotations = map["x-amqp-message-annotations"].asMap(); qpid::amqp::Decoder decoder(messageAnnotations.data, messageAnnotations.size); - decoder.readMap(annotations); + if (nestAnnotations) { + map["x-amqp-message-annotations"] = decoder.readMap(); + } else { + decoder.readMap(map); + } } } qpid::amqp::CharSequence EncodedMessage::getBareMessage() const @@ -178,9 +191,38 @@ void EncodedMessage::getCorrelationId(std::string& s) const { correlationId.assign(s); } -void EncodedMessage::getBody(std::string& s) const +void EncodedMessage::getBody(std::string& raw, qpid::types::Variant& c) const { - s.assign(body.data, body.size); + if (!content.isVoid()) { + c = content;//integer types, floats, bool etc + //TODO: populate raw data? + } else { + if (bodyType.empty() + || bodyType == qpid::amqp::typecodes::BINARY_NAME + || bodyType == qpid::types::encodings::UTF8 + || bodyType == qpid::types::encodings::ASCII) + { + c = std::string(body.data, body.size); + c.setEncoding(bodyType); + } else if (bodyType == qpid::amqp::typecodes::LIST_NAME) { + qpid::amqp::ListBuilder builder; + qpid::amqp::Decoder decoder(body.data, body.size); + decoder.read(builder); + c = builder.getList(); + raw.assign(body.data, body.size); + } else if (bodyType == qpid::amqp::typecodes::MAP_NAME) { + qpid::amqp::DataBuilder builder = qpid::amqp::DataBuilder(qpid::types::Variant::Map()); + qpid::amqp::Decoder decoder(body.data, body.size); + decoder.read(builder); + c = builder.getValue().asMap(); + raw.assign(body.data, body.size); + } else if (bodyType == qpid::amqp::typecodes::UUID_NAME) { + if (body.size == qpid::types::Uuid::SIZE) c = qpid::types::Uuid(body.data); + raw.assign(body.data, body.size); + } else if (bodyType == qpid::amqp::typecodes::ARRAY_NAME) { + raw.assign(body.data, body.size); + } + } } qpid::amqp::CharSequence EncodedMessage::getBody() const @@ -216,6 +258,7 @@ bool EncodedMessage::hasHeaderChanged(const qpid::messaging::MessageImpl& msg) c } + EncodedMessage::InitialScan::InitialScan(EncodedMessage& e, qpid::messaging::MessageImpl& m) : em(e), mi(m) { //set up defaults as needed: @@ -249,15 +292,35 @@ void EncodedMessage::InitialScan::onGroupId(const qpid::amqp::CharSequence& v) { void EncodedMessage::InitialScan::onGroupSequence(uint32_t i) { em.groupSequence = i; } void EncodedMessage::InitialScan::onReplyToGroupId(const qpid::amqp::CharSequence& v) { em.replyToGroupId = v; } -void EncodedMessage::InitialScan::onApplicationProperties(const qpid::amqp::CharSequence& v) { em.applicationProperties = v; } -void EncodedMessage::InitialScan::onDeliveryAnnotations(const qpid::amqp::CharSequence& v) { em.deliveryAnnotations = v; } -void EncodedMessage::InitialScan::onMessageAnnotations(const qpid::amqp::CharSequence& v) { em.messageAnnotations = v; } -void EncodedMessage::InitialScan::onBody(const qpid::amqp::CharSequence& v, const qpid::amqp::Descriptor&) +void EncodedMessage::InitialScan::onApplicationProperties(const qpid::amqp::CharSequence& v, const qpid::amqp::CharSequence&) { em.applicationProperties = v; } +void EncodedMessage::InitialScan::onDeliveryAnnotations(const qpid::amqp::CharSequence& v, const qpid::amqp::CharSequence&) { em.deliveryAnnotations = v; } +void EncodedMessage::InitialScan::onMessageAnnotations(const qpid::amqp::CharSequence& v, const qpid::amqp::CharSequence&) { em.messageAnnotations = v; } + +void EncodedMessage::InitialScan::onData(const qpid::amqp::CharSequence& v) +{ + em.body = v; +} +void EncodedMessage::InitialScan::onAmqpSequence(const qpid::amqp::CharSequence& v) { - //TODO: how to communicate the type, i.e. descriptor? em.body = v; + em.bodyType = qpid::amqp::typecodes::LIST_NAME; } -void EncodedMessage::InitialScan::onBody(const qpid::types::Variant&, const qpid::amqp::Descriptor&) {} -void EncodedMessage::InitialScan::onFooter(const qpid::amqp::CharSequence& v) { em.footer = v; } +void EncodedMessage::InitialScan::onAmqpValue(const qpid::amqp::CharSequence& v, const std::string& type) +{ + em.body = v; + if (type == qpid::amqp::typecodes::STRING_NAME) { + em.bodyType = qpid::types::encodings::UTF8; + } else if (type == qpid::amqp::typecodes::SYMBOL_NAME) { + em.bodyType = qpid::types::encodings::ASCII; + } else { + em.bodyType = type; + } +} +void EncodedMessage::InitialScan::onAmqpValue(const qpid::types::Variant& v) +{ + em.content = v; +} + +void EncodedMessage::InitialScan::onFooter(const qpid::amqp::CharSequence& v, const qpid::amqp::CharSequence&) { em.footer = v; } }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.h b/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.h index 09a9d948d5..16a43aecea 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.h +++ b/qpid/cpp/src/qpid/messaging/amqp/EncodedMessage.h @@ -21,6 +21,9 @@ * under the License. * */ + +#include "qpid/messaging/ImportExport.h" + #include "qpid/amqp/CharSequence.h" #include "qpid/amqp/MessageId.h" #include "qpid/amqp/MessageReader.h" @@ -71,34 +74,36 @@ namespace amqp { class EncodedMessage { public: - EncodedMessage(); - EncodedMessage(size_t); - EncodedMessage(const EncodedMessage&); - ~EncodedMessage(); + QPID_MESSAGING_EXTERN EncodedMessage(); + QPID_MESSAGING_EXTERN EncodedMessage(size_t); + QPID_MESSAGING_EXTERN EncodedMessage(const EncodedMessage&); + QPID_MESSAGING_EXTERN ~EncodedMessage(); - size_t getSize() const; - char* getData(); - const char* getData() const; - void trim(size_t); - void resize(size_t); + QPID_MESSAGING_EXTERN size_t getSize() const; + QPID_MESSAGING_EXTERN char* getData(); + QPID_MESSAGING_EXTERN const char* getData() const; + QPID_MESSAGING_EXTERN void trim(size_t); + QPID_MESSAGING_EXTERN void resize(size_t); + QPID_MESSAGING_EXTERN void setNestAnnotationsOption(bool); void getReplyTo(qpid::messaging::Address&) const; void getSubject(std::string&) const; void getContentType(std::string&) const; void getMessageId(std::string&) const; void getUserId(std::string&) const; void getCorrelationId(std::string&) const; - - void init(qpid::messaging::MessageImpl&); void populate(qpid::types::Variant::Map&) const; - void getBody(std::string&) const; - qpid::amqp::CharSequence getBareMessage() const; + void getBody(std::string&, qpid::types::Variant&) const; + + QPID_MESSAGING_EXTERN void init(qpid::messaging::MessageImpl&); + QPID_MESSAGING_EXTERN qpid::amqp::CharSequence getBareMessage() const; qpid::amqp::CharSequence getBody() const; - bool hasHeaderChanged(const qpid::messaging::MessageImpl&) const; + QPID_MESSAGING_EXTERN bool hasHeaderChanged(const qpid::messaging::MessageImpl&) const; private: size_t size; char* data; + bool nestAnnotations; class InitialScan : public qpid::amqp::MessageReader { @@ -127,12 +132,16 @@ class EncodedMessage void onGroupSequence(uint32_t); void onReplyToGroupId(const qpid::amqp::CharSequence&); - void onApplicationProperties(const qpid::amqp::CharSequence&); - void onDeliveryAnnotations(const qpid::amqp::CharSequence&); - void onMessageAnnotations(const qpid::amqp::CharSequence&); - void onBody(const qpid::amqp::CharSequence&, const qpid::amqp::Descriptor&); - void onBody(const qpid::types::Variant&, const qpid::amqp::Descriptor&); - void onFooter(const qpid::amqp::CharSequence&); + void onApplicationProperties(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence&); + void onDeliveryAnnotations(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence&); + void onMessageAnnotations(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence&); + + void onData(const qpid::amqp::CharSequence&); + void onAmqpSequence(const qpid::amqp::CharSequence&); + void onAmqpValue(const qpid::amqp::CharSequence&, const std::string& type); + void onAmqpValue(const qpid::types::Variant&); + + void onFooter(const qpid::amqp::CharSequence&, const qpid::amqp::CharSequence&); private: EncodedMessage& em; qpid::messaging::MessageImpl& mi; @@ -164,7 +173,11 @@ class EncodedMessage qpid::amqp::CharSequence replyToGroupId; //application-properties: qpid::amqp::CharSequence applicationProperties; + //application data: qpid::amqp::CharSequence body; + std::string bodyType; + qpid::types::Variant content; + //footer: qpid::amqp::CharSequence footer; diff --git a/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.cpp b/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.cpp index 081a0ae78b..473c120e27 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.cpp @@ -89,8 +89,18 @@ const std::string& ReceiverContext::getSource() const { return address.getName(); } -void ReceiverContext::verify(pn_terminus_t* source) +void ReceiverContext::verify() { + pn_terminus_t* source = pn_link_remote_source(receiver); + if (!pn_terminus_get_address(source)) { + std::string msg("No such source : "); + msg += getSource(); + QPID_LOG(debug, msg); + throw qpid::messaging::NotFound(msg); + } else if (AddressImpl::isTemporary(address)) { + address.setName(pn_terminus_get_address(source)); + QPID_LOG(debug, "Dynamic source name set to " << address.getName()); + } helper.checkAssertion(source, AddressHelper::FOR_RECEIVER); } void ReceiverContext::configure() @@ -99,7 +109,13 @@ void ReceiverContext::configure() } void ReceiverContext::configure(pn_terminus_t* source) { - helper.configure(source, AddressHelper::FOR_RECEIVER); + helper.configure(receiver, source, AddressHelper::FOR_RECEIVER); + std::string option; + if (helper.getLinkTarget(option)) { + pn_terminus_set_address(pn_link_target(receiver), option.c_str()); + } else { + pn_terminus_set_address(pn_link_target(receiver), pn_terminus_get_address(pn_link_source(receiver))); + } } Address ReceiverContext::getAddress() const @@ -112,6 +128,10 @@ bool ReceiverContext::isClosed() const return false;//TODO } - +void ReceiverContext::reset(pn_session_t* session) +{ + receiver = pn_receiver(session, name.c_str()); + configure(); +} }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.h b/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.h index 79049d9263..fb8ea0d336 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.h +++ b/qpid/cpp/src/qpid/messaging/amqp/ReceiverContext.h @@ -46,6 +46,7 @@ class ReceiverContext public: ReceiverContext(pn_session_t* session, const std::string& name, const qpid::messaging::Address& source); ~ReceiverContext(); + void reset(pn_session_t* session); void setCapacity(uint32_t); uint32_t getCapacity(); uint32_t getAvailable(); @@ -56,7 +57,7 @@ class ReceiverContext const std::string& getSource() const; bool isClosed() const; void configure(); - void verify(pn_terminus_t*); + void verify(); Address getAddress() const; private: friend class ConnectionContext; diff --git a/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.cpp b/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.cpp index c601d05ed0..177f47896b 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/ReceiverHandle.cpp @@ -84,7 +84,7 @@ uint32_t ReceiverHandle::getUnsettled() void ReceiverHandle::close() { - session->closeReceiver(getName()); + connection->detach(session, receiver); } const std::string& ReceiverHandle::getName() const diff --git a/qpid/cpp/src/qpid/messaging/amqp/Sasl.cpp b/qpid/cpp/src/qpid/messaging/amqp/Sasl.cpp index 40f469cdcf..4b21f7b0d2 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/Sasl.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/Sasl.cpp @@ -93,7 +93,7 @@ void Sasl::mechanisms(const std::string& offered) mechanisms = offered; } - if (sasl->start(mechanisms, response)) { + if (sasl->start(mechanisms, response, context.getTransportSecuritySettings())) { init(sasl->getMechanism(), &response, hostname.size() ? &hostname : 0); } else { init(sasl->getMechanism(), 0, hostname.size() ? &hostname : 0); diff --git a/qpid/cpp/src/qpid/messaging/amqp/SenderContext.cpp b/qpid/cpp/src/qpid/messaging/amqp/SenderContext.cpp index d4a5ca4292..94851da273 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/SenderContext.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/SenderContext.cpp @@ -42,7 +42,7 @@ SenderContext::SenderContext(pn_session_t* session, const std::string& n, const : name(n), address(a), helper(address), - sender(pn_sender(session, n.c_str())), capacity(1000) {} + sender(pn_sender(session, n.c_str())), capacity(1000), unreliable(helper.isUnreliable()) {} SenderContext::~SenderContext() { @@ -67,7 +67,7 @@ uint32_t SenderContext::getCapacity() uint32_t SenderContext::getUnsettled() { - return processUnsettled(); + return processUnsettled(true/*always allow retrieval of unsettled count, even if link has failed*/); } const std::string& SenderContext::getName() const @@ -80,16 +80,26 @@ const std::string& SenderContext::getTarget() const return address.getName(); } -SenderContext::Delivery* SenderContext::send(const qpid::messaging::Message& message) +bool SenderContext::send(const qpid::messaging::Message& message, SenderContext::Delivery** out) { - if (processUnsettled() < capacity && pn_link_credit(sender)) { - deliveries.push_back(Delivery(nextId++)); - Delivery& delivery = deliveries.back(); - delivery.encode(MessageImplAccess::get(message), address); - delivery.send(sender); - return &delivery; + resend();//if there are any messages needing to be resent at the front of the queue, send them first + if (processUnsettled(false) < capacity && pn_link_credit(sender)) { + if (unreliable) { + Delivery delivery(nextId++); + delivery.encode(MessageImplAccess::get(message), address); + delivery.send(sender, unreliable); + *out = 0; + return true; + } else { + deliveries.push_back(Delivery(nextId++)); + Delivery& delivery = deliveries.back(); + delivery.encode(MessageImplAccess::get(message), address); + delivery.send(sender, unreliable); + *out = &delivery; + return true; + } } else { - return 0; + return false; } } @@ -108,11 +118,13 @@ void SenderContext::check() } } -uint32_t SenderContext::processUnsettled() +uint32_t SenderContext::processUnsettled(bool silent) { - check(); + if (!silent) { + check(); + } //remove messages from front of deque once peer has confirmed receipt - while (!deliveries.empty() && deliveries.front().delivered()) { + while (!deliveries.empty() && deliveries.front().delivered() && !(pn_link_state(sender) & PN_REMOTE_CLOSED)) { deliveries.front().settle(); deliveries.pop_front(); } @@ -122,6 +134,7 @@ namespace { const std::string X_AMQP("x-amqp-"); const std::string X_AMQP_FIRST_ACQUIRER("x-amqp-first-acquirer"); const std::string X_AMQP_DELIVERY_COUNT("x-amqp-delivery-count"); +const std::string X_AMQP_0_10_APP_ID("x-amqp-0-10.app-id"); class HeaderAdapter : public qpid::amqp::MessageEncoder::Header { @@ -341,7 +354,7 @@ class ApplicationPropertiesAdapter : public qpid::amqp::MessageEncoder::Applicat { for (qpid::types::Variant::Map::const_iterator i = headers.begin(); i != headers.end(); ++i) { //strip out values with special keys as they are sent in standard fields - if (!startsWith(i->first, X_AMQP)) { + if (!startsWith(i->first, X_AMQP) || i->first == X_AMQP_0_10_APP_ID) { qpid::amqp::CharSequence key(convert(i->first)); switch (i->second.getType()) { case qpid::types::VAR_VOID: @@ -413,7 +426,12 @@ bool changedSubject(const qpid::messaging::MessageImpl& msg, const qpid::messagi } -SenderContext::Delivery::Delivery(int32_t i) : id(i), token(0) {} +SenderContext::Delivery::Delivery(int32_t i) : id(i), token(0), presettled(false) {} + +void SenderContext::Delivery::reset() +{ + token = 0; +} void SenderContext::Delivery::encode(const qpid::messaging::MessageImpl& msg, const qpid::messaging::Address& address) { @@ -440,7 +458,15 @@ void SenderContext::Delivery::encode(const qpid::messaging::MessageImpl& msg, co PropertiesAdapter properties(msg, address.getSubject()); ApplicationPropertiesAdapter applicationProperties(msg.getHeaders()); //compute size: - encoded.resize(qpid::amqp::MessageEncoder::getEncodedSize(header, properties, applicationProperties, msg.getBytes())); + size_t contentSize = qpid::amqp::MessageEncoder::getEncodedSize(header) + + qpid::amqp::MessageEncoder::getEncodedSize(properties) + + qpid::amqp::MessageEncoder::getEncodedSize(applicationProperties); + if (msg.getContent().isVoid()) { + contentSize += qpid::amqp::MessageEncoder::getEncodedSizeForContent(msg.getBytes()); + } else { + contentSize += qpid::amqp::MessageEncoder::getEncodedSizeForValue(msg.getContent()) + 3/*descriptor*/; + } + encoded.resize(contentSize); QPID_LOG(debug, "Sending message, buffer is " << encoded.getSize() << " bytes") qpid::amqp::MessageEncoder encoder(encoded.getData(), encoded.getSize()); //write header: @@ -451,7 +477,12 @@ void SenderContext::Delivery::encode(const qpid::messaging::MessageImpl& msg, co //write application-properties encoder.writeApplicationProperties(applicationProperties); //write body - if (msg.getBytes().size()) encoder.writeBinary(msg.getBytes(), &qpid::amqp::message::DATA);//structured content not yet directly supported + if (!msg.getContent().isVoid()) { + //write as AmqpValue + encoder.writeValue(msg.getContent(), &qpid::amqp::message::AMQP_VALUE); + } else if (msg.getBytes().size()) { + encoder.writeBinary(msg.getBytes(), &qpid::amqp::message::DATA);//structured content not yet directly supported + } if (encoder.getPosition() < encoded.getSize()) { QPID_LOG(debug, "Trimming buffer from " << encoded.getSize() << " to " << encoder.getPosition()); encoded.trim(encoder.getPosition()); @@ -459,19 +490,27 @@ void SenderContext::Delivery::encode(const qpid::messaging::MessageImpl& msg, co //write footer (no annotations yet supported) } } -void SenderContext::Delivery::send(pn_link_t* sender) +void SenderContext::Delivery::send(pn_link_t* sender, bool unreliable) { pn_delivery_tag_t tag; tag.size = sizeof(id); tag.bytes = reinterpret_cast<const char*>(&id); token = pn_delivery(sender, tag); pn_link_send(sender, encoded.getData(), encoded.getSize()); + if (unreliable) { + pn_delivery_settle(token); + presettled = true; + } pn_link_advance(sender); } +bool SenderContext::Delivery::sent() const +{ + return presettled || token; +} bool SenderContext::Delivery::delivered() { - if (pn_delivery_remote_state(token) || pn_delivery_settled(token)) { + if (presettled || (token && (pn_delivery_remote_state(token) || pn_delivery_settled(token)))) { //TODO: need a better means for signalling outcomes other than accepted if (rejected()) { QPID_LOG(warning, "delivery " << id << " was rejected by peer"); @@ -495,8 +534,19 @@ void SenderContext::Delivery::settle() { pn_delivery_settle(token); } -void SenderContext::verify(pn_terminus_t* target) +void SenderContext::verify() { + pn_terminus_t* target = pn_link_remote_target(sender); + if (!pn_terminus_get_address(target)) { + std::string msg("No such target : "); + msg += getTarget(); + QPID_LOG(debug, msg); + throw qpid::messaging::NotFound(msg); + } else if (AddressImpl::isTemporary(address)) { + address.setName(pn_terminus_get_address(target)); + QPID_LOG(debug, "Dynamic target name set to " << address.getName()); + } + helper.checkAssertion(target, AddressHelper::FOR_SENDER); } void SenderContext::configure() @@ -505,12 +555,18 @@ void SenderContext::configure() } void SenderContext::configure(pn_terminus_t* target) { - helper.configure(target, AddressHelper::FOR_SENDER); + helper.configure(sender, target, AddressHelper::FOR_SENDER); + std::string option; + if (helper.getLinkSource(option)) { + pn_terminus_set_address(pn_link_source(sender), option.c_str()); + } else { + pn_terminus_set_address(pn_link_source(sender), pn_terminus_get_address(pn_link_target(sender))); + } } bool SenderContext::settled() { - return processUnsettled() == 0; + return processUnsettled(false) == 0; } Address SenderContext::getAddress() const @@ -518,4 +574,22 @@ Address SenderContext::getAddress() const return address; } + +void SenderContext::reset(pn_session_t* session) +{ + sender = pn_sender(session, name.c_str()); + configure(); + + for (Deliveries::iterator i = deliveries.begin(); i != deliveries.end(); ++i) { + i->reset(); + } +} + +void SenderContext::resend() +{ + for (Deliveries::iterator i = deliveries.begin(); i != deliveries.end() && pn_link_credit(sender) && !i->sent(); ++i) { + i->send(sender, false/*only resend reliable transfers*/); + } +} + }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/SenderContext.h b/qpid/cpp/src/qpid/messaging/amqp/SenderContext.h index e389cd2e35..27ffa1e81b 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/SenderContext.h +++ b/qpid/cpp/src/qpid/messaging/amqp/SenderContext.h @@ -52,28 +52,32 @@ class SenderContext public: Delivery(int32_t id); void encode(const qpid::messaging::MessageImpl& message, const qpid::messaging::Address&); - void send(pn_link_t*); + void send(pn_link_t*, bool unreliable); bool delivered(); bool accepted(); bool rejected(); void settle(); + void reset(); + bool sent() const; private: int32_t id; pn_delivery_t* token; EncodedMessage encoded; + bool presettled; }; SenderContext(pn_session_t* session, const std::string& name, const qpid::messaging::Address& target); ~SenderContext(); + void reset(pn_session_t* session); void close(); void setCapacity(uint32_t); uint32_t getCapacity(); uint32_t getUnsettled(); const std::string& getName() const; const std::string& getTarget() const; - Delivery* send(const qpid::messaging::Message& message); + bool send(const qpid::messaging::Message& message, Delivery**); void configure(); - void verify(pn_terminus_t*); + void verify(); void check(); bool settled(); Address getAddress() const; @@ -88,9 +92,11 @@ class SenderContext int32_t nextId; Deliveries deliveries; uint32_t capacity; + bool unreliable; - uint32_t processUnsettled(); + uint32_t processUnsettled(bool silent); void configure(pn_terminus_t*); + void resend(); }; }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.cpp b/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.cpp index cda8c032aa..367db701cb 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/SenderHandle.cpp @@ -44,7 +44,7 @@ void SenderHandle::send(const Message& message, bool sync) void SenderHandle::close() { - session->closeSender(getName()); + connection->detach(session, sender); } void SenderHandle::setCapacity(uint32_t capacity) diff --git a/qpid/cpp/src/qpid/messaging/amqp/SessionContext.cpp b/qpid/cpp/src/qpid/messaging/amqp/SessionContext.cpp index 9815721fa0..8f2a7d15d8 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/SessionContext.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/SessionContext.cpp @@ -79,14 +79,14 @@ boost::shared_ptr<ReceiverContext> SessionContext::getReceiver(const std::string } } -void SessionContext::closeReceiver(const std::string&) +void SessionContext::removeReceiver(const std::string& n) { - + receivers.erase(n); } -void SessionContext::closeSender(const std::string&) +void SessionContext::removeSender(const std::string& n) { - + senders.erase(n); } boost::shared_ptr<ReceiverContext> SessionContext::nextReceiver(qpid::messaging::Duration /*timeout*/) @@ -153,4 +153,25 @@ bool SessionContext::settled() } return result; } + +void SessionContext::setName(const std::string& n) +{ + name = n; +} +std::string SessionContext::getName() const +{ + return name; +} + +void SessionContext::reset(pn_connection_t* connection) +{ + session = pn_session(connection); + unacked.clear(); + for (SessionContext::SenderMap::iterator i = senders.begin(); i != senders.end(); ++i) { + i->second->reset(session); + } + for (SessionContext::ReceiverMap::iterator i = receivers.begin(); i != receivers.end(); ++i) { + i->second->reset(session); + } +} }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/SessionContext.h b/qpid/cpp/src/qpid/messaging/amqp/SessionContext.h index eca30a0e97..5d68f6d8de 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/SessionContext.h +++ b/qpid/cpp/src/qpid/messaging/amqp/SessionContext.h @@ -50,16 +50,19 @@ class SessionContext public: SessionContext(pn_connection_t*); ~SessionContext(); + void reset(pn_connection_t*); boost::shared_ptr<SenderContext> createSender(const qpid::messaging::Address& address); boost::shared_ptr<ReceiverContext> createReceiver(const qpid::messaging::Address& address); boost::shared_ptr<SenderContext> getSender(const std::string& name) const; boost::shared_ptr<ReceiverContext> getReceiver(const std::string& name) const; - void closeReceiver(const std::string&); - void closeSender(const std::string&); + void removeReceiver(const std::string&); + void removeSender(const std::string&); boost::shared_ptr<ReceiverContext> nextReceiver(qpid::messaging::Duration timeout); uint32_t getReceivable(); uint32_t getUnsettledAcks(); bool settled(); + void setName(const std::string&); + std::string getName() const; private: friend class ConnectionContext; typedef std::map<std::string, boost::shared_ptr<SenderContext> > SenderMap; @@ -70,6 +73,7 @@ class SessionContext ReceiverMap receivers; DeliveryMap unacked; qpid::framing::SequenceNumber next; + std::string name; qpid::framing::SequenceNumber record(pn_delivery_t*); void acknowledge(); diff --git a/qpid/cpp/src/qpid/messaging/amqp/SessionHandle.cpp b/qpid/cpp/src/qpid/messaging/amqp/SessionHandle.cpp index bf79771ca4..45635e4ced 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/SessionHandle.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/SessionHandle.cpp @@ -84,15 +84,25 @@ void SessionHandle::sync(bool /*block*/) qpid::messaging::Sender SessionHandle::createSender(const qpid::messaging::Address& address) { boost::shared_ptr<SenderContext> sender = session->createSender(address); - connection->attach(session, sender); - return qpid::messaging::Sender(new SenderHandle(connection, session, sender)); + try { + connection->attach(session, sender); + return qpid::messaging::Sender(new SenderHandle(connection, session, sender)); + } catch (...) { + session->removeSender(sender->getName()); + throw; + } } qpid::messaging::Receiver SessionHandle::createReceiver(const qpid::messaging::Address& address) { boost::shared_ptr<ReceiverContext> receiver = session->createReceiver(address); - connection->attach(session, receiver); - return qpid::messaging::Receiver(new ReceiverHandle(connection, session, receiver)); + try { + connection->attach(session, receiver); + return qpid::messaging::Receiver(new ReceiverHandle(connection, session, receiver)); + } catch (...) { + session->removeReceiver(receiver->getName()); + throw; + } } bool SessionHandle::nextReceiver(Receiver& receiver, Duration timeout) diff --git a/qpid/cpp/src/qpid/messaging/amqp/SslTransport.cpp b/qpid/cpp/src/qpid/messaging/amqp/SslTransport.cpp index ea2375cb26..a62a553d90 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/SslTransport.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/SslTransport.cpp @@ -157,4 +157,11 @@ void SslTransport::activateOutput() if (aio) aio->notifyPendingWrite(); } +const qpid::sys::SecuritySettings* SslTransport::getSecuritySettings() +{ + securitySettings.ssf = socket.getKeyLen(); + securitySettings.authid = "dummy";//set to non-empty string to enable external authentication + return &securitySettings; +} + }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/SslTransport.h b/qpid/cpp/src/qpid/messaging/amqp/SslTransport.h index aad82c2c2a..2972be4fac 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/SslTransport.h +++ b/qpid/cpp/src/qpid/messaging/amqp/SslTransport.h @@ -23,6 +23,7 @@ */ #include "qpid/messaging/amqp/Transport.h" #include "qpid/sys/Mutex.h" +#include "qpid/sys/SecuritySettings.h" #include "qpid/sys/ssl/SslSocket.h" #include <boost/shared_ptr.hpp> @@ -50,6 +51,7 @@ class SslTransport : public Transport void abort(); void connectionEstablished() {}; void close(); + const qpid::sys::SecuritySettings* getSecuritySettings(); private: qpid::sys::ssl::SslSocket socket; @@ -59,6 +61,7 @@ class SslTransport : public Transport boost::shared_ptr<qpid::sys::Poller> poller; bool closed; std::string id; + qpid::sys::SecuritySettings securitySettings; void connected(const qpid::sys::Socket&); void failed(const std::string& msg); diff --git a/qpid/cpp/src/qpid/messaging/amqp/TcpTransport.cpp b/qpid/cpp/src/qpid/messaging/amqp/TcpTransport.cpp index 98022d634c..c0a9560c6f 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/TcpTransport.cpp +++ b/qpid/cpp/src/qpid/messaging/amqp/TcpTransport.cpp @@ -159,4 +159,8 @@ void TcpTransport::activateOutput() if (aio) aio->notifyPendingWrite(); } +const qpid::sys::SecuritySettings* TcpTransport::getSecuritySettings() +{ + return 0; +} }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/messaging/amqp/TcpTransport.h b/qpid/cpp/src/qpid/messaging/amqp/TcpTransport.h index d7adf64f3e..406791417c 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/TcpTransport.h +++ b/qpid/cpp/src/qpid/messaging/amqp/TcpTransport.h @@ -50,6 +50,7 @@ class TcpTransport : public Transport void abort(); void connectionEstablished() {}; void close(); + const qpid::sys::SecuritySettings* getSecuritySettings(); private: boost::scoped_ptr<qpid::sys::Socket> socket; diff --git a/qpid/cpp/src/qpid/messaging/amqp/Transport.h b/qpid/cpp/src/qpid/messaging/amqp/Transport.h index ee021f645b..159916f9ae 100644 --- a/qpid/cpp/src/qpid/messaging/amqp/Transport.h +++ b/qpid/cpp/src/qpid/messaging/amqp/Transport.h @@ -21,12 +21,14 @@ * under the License. * */ +#include "qpid/CommonImportExport.h" #include "qpid/sys/OutputControl.h" #include <boost/shared_ptr.hpp> namespace qpid { namespace sys { class Poller; +struct SecuritySettings; } namespace messaging { namespace amqp { @@ -38,10 +40,11 @@ class Transport : public qpid::sys::OutputControl virtual ~Transport() {} virtual void connect(const std::string& host, const std::string& port) = 0; virtual void close() = 0; + virtual const qpid::sys::SecuritySettings* getSecuritySettings() = 0; typedef Transport* Factory(TransportContext&, boost::shared_ptr<qpid::sys::Poller>); - static Transport* create(const std::string& name, TransportContext&, boost::shared_ptr<qpid::sys::Poller>); - static void add(const std::string& name, Factory* factory); + QPID_COMMON_EXTERN static Transport* create(const std::string& name, TransportContext&, boost::shared_ptr<qpid::sys::Poller>); + QPID_COMMON_EXTERN static void add(const std::string& name, Factory* factory); }; }}} // namespace qpid::messaging::amqp diff --git a/qpid/cpp/src/qpid/store/CMakeLists.txt b/qpid/cpp/src/qpid/store/CMakeLists.txt index 31623f8e84..094ae9d5d0 100644 --- a/qpid/cpp/src/qpid/store/CMakeLists.txt +++ b/qpid/cpp/src/qpid/store/CMakeLists.txt @@ -32,7 +32,7 @@ set (store_SOURCES MessageStorePlugin.cpp ) add_library (store MODULE ${store_SOURCES}) -target_link_libraries (store qpidbroker ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries (store qpidbroker qpidcommon ${Boost_PROGRAM_OPTIONS_LIBRARY}) if (CMAKE_COMPILER_IS_GNUCXX) set (GCC_CATCH_UNDEFINED "-Wl,--no-undefined") # gcc on SunOS uses native linker whose "-z defs" is too fussy diff --git a/qpid/cpp/src/qpid/store/ms-clfs/MSSqlClfsProvider.cpp b/qpid/cpp/src/qpid/store/ms-clfs/MSSqlClfsProvider.cpp index 90785263d3..512e71230b 100644 --- a/qpid/cpp/src/qpid/store/ms-clfs/MSSqlClfsProvider.cpp +++ b/qpid/cpp/src/qpid/store/ms-clfs/MSSqlClfsProvider.cpp @@ -34,7 +34,6 @@ #include <qpid/store/StorageProvider.h> #include <qpid/sys/Mutex.h> #include <boost/foreach.hpp> -#include <boost/make_shared.hpp> // From ms-sql... #include "BlobAdapter.h" @@ -356,7 +355,7 @@ MSSqlClfsProvider::finalizeMe() MSSqlClfsProvider::MSSqlClfsProvider() : options("MS SQL/CLFS Provider options") { - transactions = boost::make_shared<TransactionLog>(); + transactions.reset(new TransactionLog()); } MSSqlClfsProvider::~MSSqlClfsProvider() diff --git a/qpid/cpp/src/qpid/sys/Condition.h b/qpid/cpp/src/qpid/sys/Condition.h new file mode 100644 index 0000000000..9be4b357fe --- /dev/null +++ b/qpid/cpp/src/qpid/sys/Condition.h @@ -0,0 +1,33 @@ +#ifndef _sys_Condition_h +#define _sys_Condition_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. + * + */ + +#ifdef USE_APR_PLATFORM +#include "apr/Condition.h" +#elif defined (_WIN32) +#include "windows/Condition.h" +#else +#include "posix/Condition.h" +#endif + +#endif /*!_sys_Condition_h*/ diff --git a/qpid/cpp/src/qpid/sys/ExceptionHolder.h b/qpid/cpp/src/qpid/sys/ExceptionHolder.h new file mode 100644 index 0000000000..4bc934cf75 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/ExceptionHolder.h @@ -0,0 +1,71 @@ +#ifndef QPID_EXCEPTIONHOLDER_H +#define QPID_EXCEPTIONHOLDER_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 <boost/shared_ptr.hpp> + + +namespace qpid { +namespace sys { + +struct Raisable { + virtual ~Raisable() {}; + virtual void raise() const=0; + virtual std::string what() const=0; +}; + +/** + * Holder for exceptions. Allows the thread that notices an error condition to + * create an exception and store it to be thrown by another thread. + */ +class ExceptionHolder : public Raisable { + public: + ExceptionHolder() {} + // Use default copy & assign. + + /** Take ownership of ex */ + template <class Ex> ExceptionHolder(Ex* ex) { wrap(ex); } + template <class Ex> ExceptionHolder& operator=(Ex* ex) { wrap(ex); return *this; } + + void raise() const { if (wrapper.get()) wrapper->raise() ; } + std::string what() const { return wrapper.get() ? wrapper->what() : std::string(); } + bool empty() const { return !wrapper.get(); } + operator bool() const { return !empty(); } + void reset() { wrapper.reset(); } + + private: + template <class Ex> struct Wrapper : public Raisable { + Wrapper(Ex* ptr) : exception(ptr) {} + void raise() const { throw *exception; } + std::string what() const { return exception->what(); } + boost::shared_ptr<Ex> exception; + }; + template <class Ex> void wrap(Ex* ex) { wrapper.reset(new Wrapper<Ex>(ex)); } + boost::shared_ptr<Raisable> wrapper; +}; + + +}} // namespace qpid::sys + + +#endif /*!QPID_EXCEPTIONHOLDER_H*/ diff --git a/qpid/cpp/src/qpid/sys/IOHandle.h b/qpid/cpp/src/qpid/sys/IOHandle.h new file mode 100644 index 0000000000..06ae65f879 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/IOHandle.h @@ -0,0 +1,36 @@ +#ifndef _sys_IOHandle_h +#define _sys_IOHandle_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. + * + */ + +namespace qpid { +namespace sys { + +/** + * This is a class intended to abstract the Unix concept of file descriptor + * or the Windows concept of HANDLE + */ +class IOHandle; + +}} + +#endif // _sys_IOHandle_h diff --git a/qpid/cpp/src/qpid/sys/Monitor.h b/qpid/cpp/src/qpid/sys/Monitor.h new file mode 100644 index 0000000000..123bf92dcb --- /dev/null +++ b/qpid/cpp/src/qpid/sys/Monitor.h @@ -0,0 +1,49 @@ +#ifndef _sys_Monitor_h +#define _sys_Monitor_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/Condition.h" + +namespace qpid { +namespace sys { + +/** + * A monitor is a condition variable and a mutex + */ +class Monitor : public Mutex, public Condition { + public: + inline void wait(); + inline bool wait(const AbsTime& absoluteTime); +}; + + +void Monitor::wait() { + Condition::wait(*this); +} + +bool Monitor::wait(const AbsTime& absoluteTime) { + return Condition::wait(*this, absoluteTime); +} + +}} +#endif /*!_sys_Monitor_h*/ diff --git a/qpid/cpp/src/qpid/sys/Mutex.h b/qpid/cpp/src/qpid/sys/Mutex.h new file mode 100644 index 0000000000..e718586a39 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/Mutex.h @@ -0,0 +1,91 @@ +#ifndef _sys_Mutex_h +#define _sys_Mutex_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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. + * + */ + +namespace qpid { +namespace sys { + +/** + * Scoped lock template: calls lock() in ctor, unlock() in dtor. + * L can be any class with lock() and unlock() functions. + */ +template <class L> +class ScopedLock +{ + public: + ScopedLock(L& l) : mutex(l) { mutex.lock(); } + ~ScopedLock() { mutex.unlock(); } + private: + L& mutex; +}; + +template <class L> +class ScopedUnlock +{ + public: + ScopedUnlock(L& l) : mutex(l) { mutex.unlock(); } + ~ScopedUnlock() { mutex.lock(); } + private: + L& mutex; +}; + +template <class L> +class ScopedRlock +{ + public: + ScopedRlock(L& l) : mutex(l) { mutex.rlock(); } + ~ScopedRlock() { mutex.unlock(); } + private: + L& mutex; +}; + +template <class L> +class ScopedWlock +{ + public: + ScopedWlock(L& l) : mutex(l) { mutex.wlock(); } + ~ScopedWlock() { mutex.unlock(); } + private: + L& mutex; +}; + +template <class L> +class ConditionalScopedLock +{ + public: + ConditionalScopedLock(L& l) : mutex(l) { acquired = mutex.trylock(); } + ~ConditionalScopedLock() { if (acquired) mutex.unlock(); } + bool lockAcquired() { return acquired; } + private: + L& mutex; + bool acquired; +}; + +}} + +#ifdef USE_APR_PLATFORM +#include "apr/Mutex.h" +#elif defined (_WIN32) +#include "windows/Mutex.h" +#else +#include "posix/Mutex.h" +#endif + +#endif /*!_sys_Mutex_h*/ diff --git a/qpid/cpp/src/qpid/console/Package.cpp b/qpid/cpp/src/qpid/sys/Runnable.h index e5d6fa29fd..fed7663cb6 100644 --- a/qpid/cpp/src/qpid/console/Package.cpp +++ b/qpid/cpp/src/qpid/sys/Runnable.h @@ -1,3 +1,5 @@ +#ifndef _Runnable_ +#define _Runnable_ /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -7,9 +9,9 @@ * 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 @@ -19,23 +21,31 @@ * */ -#include "qpid/console/Package.h" +#include <boost/function.hpp> +#include "qpid/CommonImportExport.h" -using namespace qpid::console; +namespace qpid { +namespace sys { -SchemaClass* Package::getClass(const std::string& className, uint8_t* hash) -{ - NameHash key(className, hash); - ClassMap::iterator iter = classes.find(key); - if (iter != classes.end()) - return iter->second; - return 0; -} - -void Package::addClass(const std::string& className, uint8_t* hash, SchemaClass* schemaClass) +/** + * Interface for objects that can be run, e.g. in a thread. + */ +class QPID_COMMON_CLASS_EXTERN Runnable { - NameHash key(className, hash); - ClassMap::iterator iter = classes.find(key); - if (iter == classes.end()) - classes[key] = schemaClass; -} + public: + /** Type to represent a runnable as a Functor */ + typedef boost::function0<void> Functor; + + QPID_COMMON_EXTERN virtual ~Runnable(); + + /** Derived classes override run(). */ + virtual void run() = 0; + + /** Create a functor object that will call this->run(). */ + Functor functor(); +}; + +}} + + +#endif diff --git a/qpid/cpp/src/qmf/engine/MessageImpl.h b/qpid/cpp/src/qpid/sys/StrError.h index b91291d2e4..36489dd0fc 100644 --- a/qpid/cpp/src/qmf/engine/MessageImpl.h +++ b/qpid/cpp/src/qpid/sys/StrError.h @@ -1,7 +1,8 @@ -#ifndef _QmfEngineMessageImpl_ -#define _QmfEngineMessageImpl_ +#ifndef _sys_StrError_h +#define _sys_StrError_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 @@ -9,36 +10,27 @@ * 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/Message.h" #include <string> -#include <boost/shared_ptr.hpp> +#include "qpid/CommonImportExport.h" -namespace qmf { -namespace engine { +namespace qpid { +namespace sys { - struct MessageImpl { - typedef boost::shared_ptr<MessageImpl> Ptr; - std::string body; - std::string destination; - std::string routingKey; - std::string replyExchange; - std::string replyKey; - std::string userId; +/** Get the error message for a system number err, e.g. errno. */ +QPID_COMMON_EXTERN std::string strError(int err); - Message copy(); - }; -} -} +}} // namespace qpid -#endif +#endif // _sys_StrError_h diff --git a/qpid/cpp/src/qpid/sys/SystemInfo.h b/qpid/cpp/src/qpid/sys/SystemInfo.h new file mode 100644 index 0000000000..1b5720a5f0 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/SystemInfo.h @@ -0,0 +1,109 @@ +#ifndef QPID_SYS_SYSTEMINFO_H +#define QPID_SYS_SYSTEMINFO_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/Address.h" +#include "qpid/CommonImportExport.h" +#include <vector> + +namespace qpid { +namespace sys { + +/** + * Retrieve information about the system we are running on. + * Results may be dependent on OS/hardware. + */ +namespace SystemInfo { +/** + * Estimate available concurrency, e.g. number of CPU cores. + * -1 means estimate not available on this platform. + */ +QPID_COMMON_EXTERN long concurrency(); + +/** + * Get the local host name and set it in the specified. + * Returns false if it can't be obtained and sets errno to any error value. + */ +QPID_COMMON_EXTERN bool getLocalHostname (Address &address); + +/** + * Get the names of all the network interfaces connected to + * this host. + * @param names Receives the list of interface names + */ +QPID_COMMON_EXTERN void getInterfaceNames(std::vector<std::string>& names ); + +/** + * Get strings for each of the IP addresses associated with a named network + * interface. + * If there is no interface of that name an empty list will be returned. + * + * @param interface The name of the network interface + * @param addresses The list of the strings for the IP addresses are pushed on the back of this parameter + * to get just the list you need to clear the vector before using it. + * @return true if an interface of the correct name was found, false otherwise + */ +QPID_COMMON_EXTERN bool getInterfaceAddresses(const std::string& interface, std::vector<std::string>& addresses); + +/** + * Retrieve system identifiers and versions. This is information that can + * generally be retrieved via POSIX uname(). + * + * @param osName Receives the OS name; e.g., GNU/Linux or Windows + * @param nodeName Receives the nodename. This may or may not match the + * set hostname from getLocalHostname(). + * @param release Receives the OS release identifier. + * @param version Receives the OS release version (kernel, build, sp, etc.) + * @param machine Receives the hardware type. + */ +QPID_COMMON_EXTERN void getSystemId (std::string &osName, + std::string &nodeName, + std::string &release, + std::string &version, + std::string &machine); + +/** + * Get the process ID of the current process. + */ +QPID_COMMON_EXTERN uint32_t getProcessId(); + +/** + * Get the process ID of the parent of the current process. + */ +QPID_COMMON_EXTERN uint32_t getParentProcessId(); + +/** + * Get the name of the current process (i.e. the name of the executable) + */ +QPID_COMMON_EXTERN std::string getProcessName(); + +/** + * Can thread related primitives be trusted during runtime house-cleaning? + * (i.e. static destructors, atexit()). + */ +QPID_COMMON_EXTERN bool threadSafeShutdown(); + + +}}} // namespace qpid::sys::SystemInfo + +#endif /*!QPID_SYS_SYSTEMINFO_H*/ diff --git a/qpid/cpp/src/qpid/sys/Thread.h b/qpid/cpp/src/qpid/sys/Thread.h new file mode 100644 index 0000000000..f556612908 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/Thread.h @@ -0,0 +1,71 @@ +#ifndef _sys_Thread_h +#define _sys_Thread_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 <boost/shared_ptr.hpp> +#include "qpid/CommonImportExport.h" + +#ifdef _WIN32 +# ifdef _MSC_VER +# define QPID_TSS __declspec(thread) +# else +# define QPID_TSS __thread +# endif +#elif defined (__GNUC__) +# define QPID_TSS __thread +#elif defined (__SUNPRO_CC) +# define QPID_TSS __thread +#else +# error "Dont know how to define QPID_TSS for this platform" +#endif + +namespace qpid { +namespace sys { + +class Runnable; +class ThreadPrivate; + +class Thread +{ + boost::shared_ptr<ThreadPrivate> impl; + + public: + QPID_COMMON_EXTERN Thread(); + QPID_COMMON_EXTERN explicit Thread(qpid::sys::Runnable*); + QPID_COMMON_EXTERN explicit Thread(qpid::sys::Runnable&); + + QPID_COMMON_EXTERN operator bool(); + QPID_COMMON_EXTERN bool operator==(const Thread&) const; + QPID_COMMON_EXTERN bool operator!=(const Thread&) const; + + QPID_COMMON_EXTERN void join(); + + QPID_COMMON_EXTERN static Thread current(); + + /** ID of current thread for logging. + * Workaround for broken Thread::current() in APR + */ + QPID_COMMON_EXTERN static unsigned long logId(); +}; + +}} +#endif /*!_sys_Thread_h*/ diff --git a/qpid/cpp/src/qpid/sys/Time.h b/qpid/cpp/src/qpid/sys/Time.h new file mode 100644 index 0000000000..2ccff92e7c --- /dev/null +++ b/qpid/cpp/src/qpid/sys/Time.h @@ -0,0 +1,176 @@ +#ifndef _sys_Time_h +#define _sys_Time_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" +/* + * The platform defines its notion of time as a TimePrivate type. The + * platform's implementation knows how to handle this type. + */ +#if defined (_WIN32) +# include "windows/Time.h" +#else +# include "posix/Time.h" +#endif + +#include "qpid/CommonImportExport.h" + +#include <limits> +#include <iosfwd> + +namespace qpid { +namespace sys { + +class Duration; + +/** + * @class AbsTime + * + * Class to represent an instant in time. + * + * The time resolution is in nanosecs, and this is held with 64 bits + * giving a total time span from about 25 million years ago to 25 million + * years hence. As an aside the internal time can sensibly be negative + * meaning before the epoch (probably 1/1/1970 although this class doesn't + * care). + * + * The AbsTime class is a value class and so you don't need to add any + * accessors to its internal state. If you think you want to replace its value, + * you need to construct a new AbsTime and assign it, viz: + * + * AbsTime when = now(); + * ... + * when = AbsTime(when, 2*TIME_SEC); // Advance timer 2 secs + * + * AbsTime is not intended to be used to represent calendar dates/times + * but you can construct a Duration since the Unix Epoch, 1970-1-1-00:00, + * so that you can convert to a date/time if needed: + * + * int64_t nanosec_since_epoch = Duration(EPOCH, now()); + * + * There are some sensible operations that are currently missing from + * AbsTime, but nearly all that's needed can be done with a mixture of + * AbsTimes and Durations. + * + * For example, convenience operators to add a Duration and AbsTime returning + * an AbsTime would fit here (although you can already perform the operation + * with one of the AbsTime constructors). However trying to add 2 AbsTimes + * doesn't make sense. + */ +class AbsTime { + friend class Duration; + friend class Condition; + + TimePrivate timepoint; + +public: + + inline AbsTime() : timepoint() {} + QPID_COMMON_EXTERN AbsTime(const AbsTime& time0, const Duration& duration); + // Default assignment operation fine + // Default copy constructor fine + + QPID_COMMON_EXTERN static AbsTime now(); + QPID_COMMON_EXTERN static AbsTime FarFuture(); + QPID_COMMON_EXTERN static AbsTime Epoch(); + + bool operator==(const AbsTime& t) const { return t.timepoint == timepoint; } + + friend bool operator<(const AbsTime& a, const AbsTime& b); + friend bool operator>(const AbsTime& a, const AbsTime& b); + QPID_COMMON_EXTERN friend std::ostream& operator << (std::ostream&, const AbsTime&); +}; + +QPID_COMMON_EXTERN std::ostream& operator << (std::ostream&, const AbsTime&); + +/** + * @class Duration + * Class to represent the duration between instants of time. + * + * As AbsTime, this class also uses nanosecs for its time + * resolution where possible. For the most part a duration can be dealt + * with like a 64 bit integer, and indeed there is an implicit conversion which + * makes this quite convenient. + */ +class Duration { + static int64_t max() { return std::numeric_limits<int64_t>::max(); } + int64_t nanosecs; + + friend class AbsTime; + +public: + QPID_COMMON_INLINE_EXTERN inline Duration(int64_t time0 = 0); + QPID_COMMON_EXTERN explicit Duration(const AbsTime& start, const AbsTime& finish); + inline operator int64_t() const; +}; + +QPID_COMMON_EXTERN std::ostream& operator << (std::ostream&, const Duration&); +QPID_COMMON_EXTERN std::istream& operator >> (std::istream&, Duration&); + +inline AbsTime now() { return AbsTime::now(); } + +inline bool operator<(const AbsTime& a, const AbsTime& b) +{ return a.timepoint < b.timepoint; } +inline bool operator>(const AbsTime& a, const AbsTime& b) +{ return a.timepoint > b.timepoint; } + +Duration::Duration(int64_t time0) : + nanosecs(time0) +{} + +Duration::operator int64_t() const +{ return nanosecs; } + +/** Nanoseconds per second. */ +const Duration TIME_SEC = 1000*1000*1000; +/** Nanoseconds per millisecond */ +const Duration TIME_MSEC = 1000*1000; +/** Nanoseconds per microseconds. */ +const Duration TIME_USEC = 1000; +/** Nanoseconds per nanosecond. */ +const Duration TIME_NSEC = 1; + +/** Value to represent an infinite timeout */ +const Duration TIME_INFINITE = std::numeric_limits<int64_t>::max(); + +/** Absolute time point for the Unix epoch: 1970-01-01T00:00:00 */ +const AbsTime EPOCH = AbsTime::Epoch(); + +/** Time greater than any other time */ +const AbsTime FAR_FUTURE = AbsTime::FarFuture(); + +/** Portable sleep for a number of seconds */ +QPID_COMMON_EXTERN void sleep(int secs); + +/** Portable sleep for a number of microseconds */ +QPID_COMMON_EXTERN void usleep(uint64_t usecs); + +/** Output formatted date/time for now*/ +void outputFormattedNow(std::ostream&); + +/** Output unformatted nanosecond-resolution time for now */ +void outputHiresNow(std::ostream&); + +}} + +#endif /*!_sys_Time_h*/ diff --git a/qpid/cpp/src/qpid/sys/posix/Condition.h b/qpid/cpp/src/qpid/sys/posix/Condition.h new file mode 100644 index 0000000000..36e7557ffd --- /dev/null +++ b/qpid/cpp/src/qpid/sys/posix/Condition.h @@ -0,0 +1,86 @@ +#ifndef _sys_posix_Condition_h +#define _sys_posix_Condition_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/posix/PrivatePosix.h" + +#include "qpid/sys/Mutex.h" +#include "qpid/sys/Time.h" + +#include <time.h> +#include <sys/errno.h> +#include <boost/noncopyable.hpp> + +namespace qpid { +namespace sys { + +/** + * A condition variable for thread synchronization. + */ +class Condition +{ + public: + inline Condition(); + inline ~Condition(); + inline void wait(Mutex&); + inline bool wait(Mutex&, const AbsTime& absoluteTime); + inline void notify(); + inline void notifyAll(); + + private: + pthread_cond_t condition; +}; + +Condition::Condition() { + QPID_POSIX_ASSERT_THROW_IF(pthread_cond_init(&condition, 0)); +} + +Condition::~Condition() { + QPID_POSIX_ABORT_IF(pthread_cond_destroy(&condition)); +} + +void Condition::wait(Mutex& mutex) { + QPID_POSIX_ASSERT_THROW_IF(pthread_cond_wait(&condition, &mutex.mutex)); +} + +bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){ + struct timespec ts; + toTimespec(ts, Duration(EPOCH, absoluteTime)); + int status = pthread_cond_timedwait(&condition, &mutex.mutex, &ts); + if (status != 0) { + if (status == ETIMEDOUT) return false; + throw QPID_POSIX_ERROR(status); + } + return true; +} + +void Condition::notify(){ + QPID_POSIX_ASSERT_THROW_IF(pthread_cond_signal(&condition)); +} + +void Condition::notifyAll(){ + QPID_POSIX_ASSERT_THROW_IF(pthread_cond_broadcast(&condition)); +} + +}} +#endif /*!_sys_posix_Condition_h*/ diff --git a/qpid/cpp/src/qpid/sys/posix/Mutex.h b/qpid/cpp/src/qpid/sys/posix/Mutex.h new file mode 100644 index 0000000000..e2b21b5a56 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/posix/Mutex.h @@ -0,0 +1,158 @@ +#ifndef _sys_posix_Mutex_h +#define _sys_posix_Mutex_h + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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/posix/check.h" + +#include <pthread.h> +#include <boost/noncopyable.hpp> + +namespace qpid { +namespace sys { + +class Condition; + +/** + * Mutex lock. + */ +class Mutex : private boost::noncopyable { + friend class Condition; + static const pthread_mutexattr_t* getAttribute(); + +public: + typedef ::qpid::sys::ScopedLock<Mutex> ScopedLock; + typedef ::qpid::sys::ScopedUnlock<Mutex> ScopedUnlock; + + inline Mutex(); + inline ~Mutex(); + inline void lock(); + inline void unlock(); + inline bool trylock(); + + +protected: + pthread_mutex_t mutex; +}; + +/** + * RW lock. + */ +class RWlock : private boost::noncopyable { + friend class Condition; + +public: + typedef ::qpid::sys::ScopedRlock<RWlock> ScopedRlock; + typedef ::qpid::sys::ScopedWlock<RWlock> ScopedWlock; + + inline RWlock(); + inline ~RWlock(); + inline void wlock(); // will write-lock + inline void rlock(); // will read-lock + inline void unlock(); + inline void trywlock(); // will write-try + inline void tryrlock(); // will read-try + +protected: + pthread_rwlock_t rwlock; +}; + + +/** + * PODMutex is a POD, can be static-initialized with + * PODMutex m = QPID_PODMUTEX_INITIALIZER + */ +struct PODMutex +{ + typedef ::qpid::sys::ScopedLock<PODMutex> ScopedLock; + + inline void lock(); + inline void unlock(); + inline bool trylock(); + + // Must be public to be a POD: + pthread_mutex_t mutex; +}; + +#define QPID_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER } + +void PODMutex::lock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_lock(&mutex)); +} + +void PODMutex::unlock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_unlock(&mutex)); +} + +bool PODMutex::trylock() { + return pthread_mutex_trylock(&mutex) == 0; +} + +Mutex::Mutex() { + QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_init(&mutex, getAttribute())); +} + +Mutex::~Mutex(){ + QPID_POSIX_ABORT_IF(pthread_mutex_destroy(&mutex)); +} + +void Mutex::lock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_lock(&mutex)); +} + +void Mutex::unlock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_mutex_unlock(&mutex)); +} + +bool Mutex::trylock() { + return pthread_mutex_trylock(&mutex) == 0; +} + + +RWlock::RWlock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_init(&rwlock, NULL)); +} + +RWlock::~RWlock(){ + QPID_POSIX_ABORT_IF(pthread_rwlock_destroy(&rwlock)); +} + +void RWlock::wlock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_wrlock(&rwlock)); +} + +void RWlock::rlock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_rdlock(&rwlock)); +} + +void RWlock::unlock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_unlock(&rwlock)); +} + +void RWlock::trywlock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_trywrlock(&rwlock)); +} + +void RWlock::tryrlock() { + QPID_POSIX_ASSERT_THROW_IF(pthread_rwlock_tryrdlock(&rwlock)); +} + + +}} +#endif /*!_sys_posix_Mutex_h*/ diff --git a/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h b/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h new file mode 100644 index 0000000000..0f59fe3176 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/posix/PrivatePosix.h @@ -0,0 +1,65 @@ +#ifndef _sys_posix_PrivatePosix_h +#define _sys_posix_PrivatePosix_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" + +struct timespec; +struct timeval; +struct addrinfo; + +namespace qpid { +namespace sys { + +// Private Time related implementation details +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&); + +// Posix fd as an IOHandle +class IOHandle { +public: + IOHandle(int fd0 = -1) : + fd(fd0) + {} + + int fd; +}; + +// Dummy IOHandle for places it's required in the API +// but we promise not to actually try to do any operations on the IOHandle +class NullIOHandle : public IOHandle { +public: + NullIOHandle() + {} +}; + +extern NullIOHandle DummyIOHandle; + +}} + +#endif /*!_sys_posix_PrivatePosix_h*/ diff --git a/qpid/cpp/src/qpid/sys/posix/Time.h b/qpid/cpp/src/qpid/sys/posix/Time.h new file mode 100755 index 0000000000..62d734c816 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/posix/Time.h @@ -0,0 +1,34 @@ +#ifndef QPID_SYS_POSIX_TIME_H +#define QPID_SYS_POSIX_TIME_H + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "qpid/sys/IntegerTypes.h" + +namespace qpid { +namespace sys { + +/** + * Class to represent an instant in time. + */ +typedef int64_t TimePrivate; + +}} // namespace qpid::sys + +#endif /*!QPID_SYS_POSIX_TIME_H*/ diff --git a/qpid/cpp/src/qpid/sys/posix/check.h b/qpid/cpp/src/qpid/sys/posix/check.h new file mode 100644 index 0000000000..1bfe5d6d78 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/posix/check.h @@ -0,0 +1,53 @@ +#ifndef _posix_check_h +#define _posix_check_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/Exception.h" +#include "qpid/Msg.h" + +#include <cerrno> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#define QPID_POSIX_ERROR(ERRNO) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRNO))) + +/** THROW QPID_POSIX_ERROR(errno) if RESULT is less than zero */ +#define QPID_POSIX_CHECK(RESULT) \ + if ((RESULT) < 0) throw QPID_POSIX_ERROR((errno)) + +/** Throw a posix error if ERRNO is non-zero */ +#define QPID_POSIX_THROW_IF(ERRNO) \ + do { int e=(ERRNO); if (e) throw QPID_POSIX_ERROR(e); } while(0) + +/** Same as _THROW_IF in a release build, but abort a debug build */ +#ifdef NDEBUG +#define QPID_POSIX_ASSERT_THROW_IF(ERRNO) QPID_POSIX_THROW_IF(ERRNO) +#else +#define QPID_POSIX_ASSERT_THROW_IF(ERRNO) \ + do { int e=(ERRNO); if (e) { errno=e; ::perror(0); assert(0); } } while(0) +#endif + +#define QPID_POSIX_ABORT_IF(ERRNO) if ((int) ERRNO) { errno=ERRNO; ::perror(0); abort(); } + +#endif /*!_posix_check_h*/ diff --git a/qpid/cpp/src/qpid/sys/windows/Condition.h b/qpid/cpp/src/qpid/sys/windows/Condition.h new file mode 100755 index 0000000000..cd5aebbf09 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/windows/Condition.h @@ -0,0 +1,77 @@ +#ifndef _sys_windows_Condition_h +#define _sys_windows_Condition_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/Mutex.h" +#include "qpid/sys/Time.h" + +#include <time.h> +#include <boost/noncopyable.hpp> +#include <boost/thread/condition.hpp> +#include <boost/thread/thread_time.hpp> +#include <windows.h> + +namespace qpid { +namespace sys { + +/** + * A condition variable for thread synchronization. + */ +class Condition : private boost::noncopyable +{ + public: + inline Condition(); + inline ~Condition(); + inline void wait(Mutex&); + inline bool wait(Mutex&, const AbsTime& absoluteTime); + inline void notify(); + inline void notifyAll(); + + private: + boost::condition_variable_any condition; +}; + +Condition::Condition() { +} + +Condition::~Condition() { +} + +void Condition::wait(Mutex& mutex) { + condition.wait(mutex.mutex); +} + +bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){ + return condition.timed_wait(mutex.mutex, absoluteTime.timepoint); +} + +void Condition::notify(){ + condition.notify_one(); +} + +void Condition::notifyAll(){ + condition.notify_all(); +} + +}} +#endif /*!_sys_windows_Condition_h*/ diff --git a/qpid/cpp/src/qpid/sys/windows/Mutex.h b/qpid/cpp/src/qpid/sys/windows/Mutex.h new file mode 100755 index 0000000000..5dcc69e836 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/windows/Mutex.h @@ -0,0 +1,188 @@ +#ifndef _sys_windows_Mutex_h +#define _sys_windows_Mutex_h + +/* + * + * Copyright (c) 2008 The Apache Software Foundation + * + * Licensed 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/windows/check.h" + +#include <boost/version.hpp> +#if (BOOST_VERSION < 103500) +#error The Windows port requires Boost version 1.35.0 or later +#endif + +#include <boost/noncopyable.hpp> +#include <boost/thread/recursive_mutex.hpp> +#include <boost/thread/shared_mutex.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/tss.hpp> + +namespace qpid { +namespace sys { + +class Condition; + +/** + * Mutex lock. + */ +class Mutex : private boost::noncopyable { + friend class Condition; + +public: + typedef ::qpid::sys::ScopedLock<Mutex> ScopedLock; + typedef ::qpid::sys::ScopedUnlock<Mutex> ScopedUnlock; + + inline Mutex(); + inline ~Mutex(); + inline void lock(); + inline void unlock(); + inline bool trylock(); + + +protected: + boost::recursive_mutex mutex; +}; + +/** + * RW lock. + */ +class RWlock : private boost::noncopyable { + friend class Condition; + +public: + typedef ::qpid::sys::ScopedRlock<RWlock> ScopedRlock; + typedef ::qpid::sys::ScopedWlock<RWlock> ScopedWlock; + + inline RWlock(); + inline ~RWlock(); + inline void wlock(); // will write-lock + inline void rlock(); // will read-lock + inline void unlock(); + inline void trywlock(); // will write-try + inline void tryrlock(); // will read-try + +protected: + boost::shared_mutex rwMutex; + boost::thread_specific_ptr<bool> haveWrite; + + inline bool &write (void); +}; + + +/** + * PODMutex is a POD, can be static-initialized with + * PODMutex m = QPID_PODMUTEX_INITIALIZER + */ +struct PODMutex +{ + typedef ::qpid::sys::ScopedLock<PODMutex> ScopedLock; + + inline void lock(); + inline void unlock(); + inline bool trylock(); + + // Must be public to be a POD: + boost::recursive_mutex mutex; +}; + +#define QPID_MUTEX_INITIALIZER 0 + +void PODMutex::lock() { + mutex.lock(); +} + +void PODMutex::unlock() { + mutex.unlock(); +} + +bool PODMutex::trylock() { + return mutex.try_lock(); +} + +Mutex::Mutex() { +} + +Mutex::~Mutex(){ +} + +void Mutex::lock() { + mutex.lock(); +} + +void Mutex::unlock() { + mutex.unlock(); +} + +bool Mutex::trylock() { + return mutex.try_lock(); +} + + +RWlock::RWlock() { +} + +RWlock::~RWlock(){ +} + +void RWlock::wlock() { + bool &writer = write(); + rwMutex.lock(); + writer = true; // Remember this thread has write lock held. +} + +void RWlock::rlock() { + bool &writer = write(); + rwMutex.lock_shared(); + writer = false; // Remember this thread has shared lock held. +} + +void RWlock::unlock() { + bool &writer = write(); + if (writer) + rwMutex.unlock(); + else + rwMutex.unlock_shared(); +} + +void RWlock::trywlock() { + bool &writer = write(); + // shared_mutex::try_lock() seems to not be available... emulate it with + // a timed lock(). + boost::system_time now = boost::get_system_time(); + if (rwMutex.timed_lock(now)) + writer = true; +} + +void RWlock::tryrlock() { + bool &writer = write(); + if (rwMutex.try_lock_shared()) + writer = false; +} + +bool & RWlock::write (void) { + // Accessing thread-specific and stack-local info, so no locks needed. + bool *writePtr = haveWrite.get(); + if (writePtr == 0) { + writePtr = new bool(false); + haveWrite.reset(writePtr); + } + return *writePtr; +} + +}} +#endif /*!_sys_windows_Mutex_h*/ diff --git a/qpid/cpp/src/qpid/sys/windows/Time.h b/qpid/cpp/src/qpid/sys/windows/Time.h new file mode 100644 index 0000000000..2987b1c8b2 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/windows/Time.h @@ -0,0 +1,36 @@ +#ifndef QPID_SYS_WINDOWS_TIME_H +#define QPID_SYS_WINDOWS_TIME_H + +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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 <boost/date_time/posix_time/posix_time_types.hpp> + +namespace qpid { +namespace sys { + +/** + * Class to represent an instant in time. Boost has this stuff already done + * so just reuse it. We can also grab this for quick use with the Condition + * wait operations. + */ +typedef boost::posix_time::ptime TimePrivate; + +}} // namespace qpid::sys + +#endif /*!QPID_SYS_WINDOWS_TIME_H*/ diff --git a/qpid/cpp/src/qpid/sys/windows/check.h b/qpid/cpp/src/qpid/sys/windows/check.h new file mode 100755 index 0000000000..2a8e439bed --- /dev/null +++ b/qpid/cpp/src/qpid/sys/windows/check.h @@ -0,0 +1,49 @@ +#ifndef _windows_check_h +#define _windows_check_h + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/Exception.h" +#include "qpid/Msg.h" +#include "qpid/sys/StrError.h" + +#define QPID_WINDOWS_ERROR(ERRVAL) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRVAL))) +#define QPID_WINDOWS_CRT_ERROR(ERRNO) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRNO))) + +/** THROW QPID_WINDOWS_ERROR(::GetLastError()) if RESULT is NULL */ +#define QPID_WINDOWS_CHECK_NULL(RESULT) \ + if ((RESULT) == NULL) throw QPID_WINDOWS_ERROR((::GetLastError())) + +#define QPID_WINDOWS_CHECK_NOT(RESULT,VAL) \ + if ((RESULT) == (VAL)) throw QPID_WINDOWS_ERROR((::GetLastError())) + +#define QPID_WINDOWS_CHECK_ASYNC_START(STATUS) \ + if (!(STATUS) && ::WSAGetLastError() != ERROR_IO_PENDING) \ + throw QPID_WINDOWS_ERROR((::WSAGetLastError())) + +#define QPID_WINDOWS_CHECK_CRT_NZ(VAL) \ + if ((VAL) == 0) throw QPID_WINDOWS_CRT_ERROR(errno) + +#define QPID_WINSOCK_CHECK(OP) \ + if ((OP) == SOCKET_ERROR) throw QPID_WINDOWS_ERROR((::WSAGetLastError())) + +#endif /*!_windows_check_h*/ diff --git a/qpid/cpp/src/qpid/types/Uuid.cpp b/qpid/cpp/src/qpid/types/Uuid.cpp index 1d6fbf430a..875e5925a9 100644 --- a/qpid/cpp/src/qpid/types/Uuid.cpp +++ b/qpid/cpp/src/qpid/types/Uuid.cpp @@ -52,6 +52,11 @@ Uuid::Uuid(const unsigned char* uuid) ::memcpy(bytes, uuid, Uuid::SIZE); } +Uuid::Uuid(const char* uuid) +{ + ::memcpy(bytes, uuid, Uuid::SIZE); +} + Uuid& Uuid::operator=(const Uuid& other) { if (this == &other) return *this; diff --git a/qpid/cpp/src/qpid/types/Variant.cpp b/qpid/cpp/src/qpid/types/Variant.cpp index 7a5f36851a..292bb5ef09 100644 --- a/qpid/cpp/src/qpid/types/Variant.cpp +++ b/qpid/cpp/src/qpid/types/Variant.cpp @@ -36,6 +36,7 @@ const std::string PREFIX("invalid conversion: "); } InvalidConversion::InvalidConversion(const std::string& msg) : Exception(PREFIX + msg) {} +InvalidConversion::~InvalidConversion() throw() {} class VariantImpl { diff --git a/qpid/cpp/src/qpid/types/encodings.h b/qpid/cpp/src/qpid/types/encodings.h new file mode 100644 index 0000000000..827b6964b9 --- /dev/null +++ b/qpid/cpp/src/qpid/types/encodings.h @@ -0,0 +1,33 @@ +#ifndef QPID_TYPES_ENCODINGS_H +#define QPID_TYPES_ENCODINGS_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. + * + */ +namespace qpid { +namespace types { +namespace encodings { +const std::string BINARY("binary"); +const std::string UTF8("utf8"); +const std::string ASCII("ascii"); +} +}} // namespace qpid::types + +#endif /*!QPID_TYPES_ENCODINGS_H*/ diff --git a/qpid/cpp/src/qpid/xml/XmlExchange.cpp b/qpid/cpp/src/qpid/xml/XmlExchange.cpp index 29ab859591..3802ec5f7f 100644 --- a/qpid/cpp/src/qpid/xml/XmlExchange.cpp +++ b/qpid/cpp/src/qpid/xml/XmlExchange.cpp @@ -372,6 +372,8 @@ bool XmlExchange::isBound(Queue::shared_ptr queue, const std::string* const bind XmlExchange::~XmlExchange() { + if (mgmtExchange != 0) + mgmtExchange->debugStats("destroying"); bindingsMap.clear(); } diff --git a/qpid/cpp/src/rdma.cmake b/qpid/cpp/src/rdma.cmake index 8c019020f1..7c0ec66bf9 100644 --- a/qpid/cpp/src/rdma.cmake +++ b/qpid/cpp/src/rdma.cmake @@ -78,7 +78,7 @@ if (BUILD_RDMA) COMPONENT ${QPID_COMPONENT_COMMON}) add_library (rdma MODULE qpid/sys/RdmaIOPlugin.cpp) - target_link_libraries (rdma qpidbroker rdmawrap) + target_link_libraries (rdma qpidbroker qpidcommon rdmawrap) set_target_properties (rdma PROPERTIES COMPILE_DEFINITIONS _IN_QPID_BROKER LINK_FLAGS "${CATCH_UNDEFINED}" @@ -94,7 +94,7 @@ if (BUILD_RDMA) COMPONENT ${QPID_COMPONENT_BROKER}) add_library (rdmaconnector MODULE qpid/client/RdmaConnector.cpp) - target_link_libraries (rdmaconnector qpidclient rdmawrap) + target_link_libraries (rdmaconnector qpidclient qpidcommon rdmawrap) set_target_properties (rdmaconnector PROPERTIES LINK_FLAGS "${CATCH_UNDEFINED}" PREFIX "") diff --git a/qpid/cpp/src/ssl.mk b/qpid/cpp/src/ssl.mk deleted file mode 100644 index 9a92c7abc7..0000000000 --- a/qpid/cpp/src/ssl.mk +++ /dev/null @@ -1,47 +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. -# -# -# Makefile fragment, conditionally included in Makefile.am -# -libqpidcommon_la_SOURCES += \ - qpid/sys/ssl/check.h \ - qpid/sys/ssl/check.cpp \ - qpid/sys/ssl/util.h \ - qpid/sys/ssl/util.cpp \ - qpid/sys/ssl/SslSocket.h \ - qpid/sys/ssl/SslSocket.cpp - -libqpidcommon_la_LIBADD += -lnss3 -lssl3 -lnspr4 -libqpidcommon_la_CXXFLAGS += $(SSL_CFLAGS) - -libqpidbroker_la_SOURCES += \ - qpid/sys/SslPlugin.cpp - -libqpidbroker_la_CXXFLAGS += $(SSL_CFLAGS) - -libqpidclient_la_SOURCES += \ - qpid/client/SslConnector.cpp - -libqpidclient_la_CXXFLAGS += $(SSL_CFLAGS) - -if HAVE_PROTON -libqpidclient_la_SOURCES += \ - qpid/messaging/amqp/SslTransport.cpp \ - qpid/messaging/amqp/SslTransport.h -endif #HAVE_PROTON diff --git a/qpid/cpp/src/tests/BrokerFixture.h b/qpid/cpp/src/tests/BrokerFixture.h index bc23867ee1..b7b0f9d34b 100644 --- a/qpid/cpp/src/tests/BrokerFixture.h +++ b/qpid/cpp/src/tests/BrokerFixture.h @@ -42,11 +42,45 @@ namespace tests { struct BrokerFixture : private boost::noncopyable { typedef qpid::broker::Broker Broker; typedef boost::intrusive_ptr<Broker> BrokerPtr; + typedef std::vector<std::string> Args; BrokerPtr broker; + uint16_t port; qpid::sys::Thread brokerThread; - BrokerFixture(Broker::Options opts=Broker::Options(), bool enableMgmt=false) { + BrokerFixture(const Args& args=Args(), const Broker::Options& opts=Broker::Options(), + bool isExternalPort_=false, uint16_t externalPort_=0) + { + init(args, opts, isExternalPort_, externalPort_); + } + + BrokerFixture(const Broker::Options& opts, + bool isExternalPort_=false, uint16_t externalPort_=0) + { + init(Args(), opts, isExternalPort_, externalPort_); + } + + void shutdownBroker() { + if (broker) { + broker->shutdown(); + brokerThread.join(); + broker = BrokerPtr(); + } + } + + ~BrokerFixture() { shutdownBroker(); } + + /** Open a connection to the broker. */ + void open(qpid::client::Connection& c) { + c.open("localhost", getPort()); + } + + uint16_t getPort() { return port; } + + private: + void init(const Args& args, Broker::Options opts, + bool isExternalPort=false, uint16_t externalPort=0) + { // Keep the tests quiet unless logging env. vars have been set by user. if (!::getenv("QPID_LOG_ENABLE") && !::getenv("QPID_TRACE")) { qpid::log::Options logOpts; @@ -55,38 +89,28 @@ struct BrokerFixture : private boost::noncopyable { logOpts.selectors.push_back("error+"); qpid::log::Logger::instance().configure(logOpts); } + // Default options, may be over-ridden when we parse args. opts.port=0; opts.listenInterfaces.push_back("127.0.0.1"); - // Management doesn't play well with multiple in-process brokers. - opts.enableMgmt=enableMgmt; opts.workerThreads=1; opts.dataDir=""; opts.auth=false; + + // Argument parsing + std::vector<const char*> argv(args.size()); + std::transform(args.begin(), args.end(), argv.begin(), + boost::bind(&std::string::c_str, _1)); + Plugin::addOptions(opts); + opts.parse(argv.size(), &argv[0]); broker = Broker::create(opts); // TODO aconway 2007-12-05: At one point BrokerFixture // tests could hang in Connection ctor if the following // line is removed. This may not be an issue anymore. broker->accept(); - broker->getPort(qpid::broker::Broker::TCP_TRANSPORT); + if (isExternalPort) port = externalPort; + else port = broker->getPort(qpid::broker::Broker::TCP_TRANSPORT); brokerThread = qpid::sys::Thread(*broker); }; - - void shutdownBroker() { - if (broker) { - broker->shutdown(); - brokerThread.join(); - broker = BrokerPtr(); - } - } - - ~BrokerFixture() { shutdownBroker(); } - - /** Open a connection to the broker. */ - void open(qpid::client::Connection& c) { - c.open("localhost", broker->getPort(qpid::broker::Broker::TCP_TRANSPORT)); - } - - uint16_t getPort() { return broker->getPort(qpid::broker::Broker::TCP_TRANSPORT); } }; /** Connection that opens in its constructor */ @@ -125,8 +149,8 @@ template <class ConnectionType, class SessionType=qpid::client::Session> struct SessionFixtureT : BrokerFixture, ClientT<ConnectionType,SessionType> { SessionFixtureT(Broker::Options opts=Broker::Options()) : - BrokerFixture(opts), - ClientT<ConnectionType,SessionType>(broker->getPort(qpid::broker::Broker::TCP_TRANSPORT)) + BrokerFixture(BrokerFixture::Args(), opts), + ClientT<ConnectionType,SessionType>(getPort()) {} }; diff --git a/qpid/cpp/src/tests/BrokerMgmtAgent.cpp b/qpid/cpp/src/tests/BrokerMgmtAgent.cpp index 29c3faf809..bad7e768a6 100644 --- a/qpid/cpp/src/tests/BrokerMgmtAgent.cpp +++ b/qpid/cpp/src/tests/BrokerMgmtAgent.cpp @@ -63,6 +63,7 @@ class AgentFixture qpid::broker::Broker::Options opts = qpid::broker::Broker::Options()) { opts.enableMgmt=true; + opts.qmf1Support=!qmfV2; opts.qmf2Support=qmfV2; opts.mgmtPubInterval=pubInterval; mFix = new MessagingFixture(opts, true); diff --git a/qpid/cpp/src/tests/CMakeLists.txt b/qpid/cpp/src/tests/CMakeLists.txt index 4763bc0b80..281464e65a 100644 --- a/qpid/cpp/src/tests/CMakeLists.txt +++ b/qpid/cpp/src/tests/CMakeLists.txt @@ -108,7 +108,6 @@ set(all_unit_tests ClientMessage ClientMessageTest ClientSessionTest - ConsoleTest DeliveryRecordTest DtxWorkRecordTest exception_test @@ -147,6 +146,7 @@ set(all_unit_tests TimerTest TopicExchangeTest TxBufferTest + TransactionObserverTest Url Uuid Variant @@ -171,7 +171,7 @@ add_executable (unit_test unit_test ${actual_unit_tests} ${platform_test_additions}) target_link_libraries (unit_test ${qpid_test_boost_libs} - qpidmessaging qpidbroker qmfconsole) + qpidmessaging qpidtypes qpidbroker qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") set_target_properties (unit_test PROPERTIES COMPILE_DEFINITIONS _IN_QPID_BROKER) remember_location(unit_test) @@ -191,105 +191,104 @@ endif (BUILD_SASL) # Other test programs # add_executable (qpid-perftest qpid-perftest.cpp ${platform_test_additions}) -target_link_libraries (qpid-perftest qpidclient) +target_link_libraries (qpid-perftest qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #qpid_perftest_SOURCES=qpid-perftest.cpp test_tools.h TestOptions.h ConnectionOptions.h remember_location(qpid-perftest) add_executable (qpid-txtest qpid-txtest.cpp ${platform_test_additions}) -target_link_libraries (qpid-txtest qpidclient) +target_link_libraries (qpid-txtest qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #qpid_txtest_SOURCES=qpid-txtest.cpp TestOptions.h ConnectionOptions.h remember_location(qpid-txtest) add_executable (qpid-latency-test qpid-latency-test.cpp ${platform_test_additions}) -target_link_libraries (qpid-latency-test qpidclient) +target_link_libraries (qpid-latency-test qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #qpid_latencytest_SOURCES=qpid-latency-test.cpp TestOptions.h ConnectionOptions.h remember_location(qpid-latency-test) add_executable (echotest echotest.cpp ${platform_test_additions}) -target_link_libraries (echotest qpidclient) +target_link_libraries (echotest qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #echotest_SOURCES=echotest.cpp TestOptions.h ConnectionOptions.h remember_location(echotest) add_executable (qpid-client-test qpid-client-test.cpp ${platform_test_additions}) -target_link_libraries (qpid-client-test qpidclient) +target_link_libraries (qpid-client-test qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #qpid_client_test_SOURCES=qpid-client-test.cpp TestOptions.h ConnectionOptions.h remember_location(qpid-client-test) add_executable (qpid-topic-listener qpid-topic-listener.cpp ${platform_test_additions}) -target_link_libraries (qpid-topic-listener qpidclient) +target_link_libraries (qpid-topic-listener qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #qpid_topic_listener_SOURCES=qpid-topic-listener.cpp TestOptions.h ConnectionOptions.h remember_location(qpid-topic-listener) add_executable (qpid-topic-publisher qpid-topic-publisher.cpp ${platform_test_additions}) -target_link_libraries (qpid-topic-publisher qpidclient) +target_link_libraries (qpid-topic-publisher qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #qpid_topic_publisher_SOURCES=qpid-topic-publisher.cpp TestOptions.h ConnectionOptions.h remember_location(qpid-topic-publisher) add_executable (publish publish.cpp ${platform_test_additions}) -target_link_libraries (publish qpidclient) +target_link_libraries (publish qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #publish_SOURCES=publish.cpp TestOptions.h ConnectionOptions.h remember_location(publish) add_executable (consume consume.cpp ${platform_test_additions}) -target_link_libraries (consume qpidclient) +target_link_libraries (consume qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #consume_SOURCES=consume.cpp TestOptions.h ConnectionOptions.h remember_location(consume) add_executable (header_test header_test.cpp ${platform_test_additions}) -target_link_libraries (header_test qpidclient) +target_link_libraries (header_test qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #header_test_SOURCES=header_test.cpp TestOptions.h ConnectionOptions.h remember_location(header_test) add_executable (declare_queues declare_queues.cpp ${platform_test_additions}) -target_link_libraries (declare_queues qpidclient) +target_link_libraries (declare_queues qpidclient qpidcommon) remember_location(declare_queues) add_executable (replaying_sender replaying_sender.cpp ${platform_test_additions}) -target_link_libraries (replaying_sender qpidclient) +target_link_libraries (replaying_sender qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") remember_location(replaying_sender) add_executable (resuming_receiver resuming_receiver.cpp ${platform_test_additions}) -target_link_libraries (resuming_receiver qpidclient) +target_link_libraries (resuming_receiver qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") remember_location(resuming_receiver) add_executable (txshift txshift.cpp ${platform_test_additions}) -target_link_libraries (txshift qpidclient) +target_link_libraries (txshift qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #txshift_SOURCES=txshift.cpp TestOptions.h ConnectionOptions.h remember_location(txshift) add_executable (txjob txjob.cpp ${platform_test_additions}) -target_link_libraries (txjob qpidclient) +target_link_libraries (txjob qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") #txjob_SOURCES=txjob.cpp TestOptions.h ConnectionOptions.h remember_location(txjob) add_executable (receiver receiver.cpp ${platform_test_additions}) -target_link_libraries (receiver qpidclient) -#receiver_SOURCES=receiver.cpp TestOptions.h ConnectionOptions.h +target_link_libraries (receiver qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") remember_location(receiver) +# This is bizarre - using both messaging and client libraries add_executable (sender sender.cpp Statistics.cpp ${platform_test_additions}) -target_link_libraries (sender qpidmessaging) -#sender_SOURCES=sender.cpp TestOptions.h ConnectionOptions.h +target_link_libraries (sender qpidmessaging qpidtypes qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") remember_location(sender) add_executable (qpid-receive qpid-receive.cpp Statistics.cpp ${platform_test_additions}) -target_link_libraries (qpid-receive qpidmessaging) +target_link_libraries (qpid-receive qpidmessaging qpidtypes qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") remember_location(qpid-receive) add_executable (qpid-send qpid-send.cpp Statistics.cpp ${platform_test_additions}) -target_link_libraries (qpid-send qpidmessaging) +target_link_libraries (qpid-send qpidmessaging qpidtypes qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") remember_location(qpid-send) add_executable (qpid-ping qpid-ping.cpp ${platform_test_additions}) -target_link_libraries (qpid-ping qpidclient) +target_link_libraries (qpid-ping qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") remember_location(qpid-ping) add_executable (datagen datagen.cpp ${platform_test_additions}) -target_link_libraries (datagen qpidclient) +target_link_libraries (datagen qpidclient qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") remember_location(datagen) add_executable (msg_group_test msg_group_test.cpp ${platform_test_additions}) -target_link_libraries (msg_group_test qpidmessaging) +target_link_libraries (msg_group_test qpidmessaging qpidtypes qpidcommon "${Boost_PROGRAM_OPTIONS_LIBRARY}") remember_location(msg_group_test) if (BUILD_SASL) @@ -357,6 +356,7 @@ if (PYTHON_EXECUTABLE) if (BUILD_AMQP) add_test (interlink_tests ${test_wrap} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/interlink_tests.py) endif (BUILD_AMQP) + add_test (swig_python_tests ${test_wrap} ${CMAKE_CURRENT_SOURCE_DIR}/swig_python_tests${test_script_suffix}) endif (PYTHON_EXECUTABLE) add_test (ipv6_test ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/ipv6_test${test_script_suffix}) add_test (federation_tests ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/run_federation_tests${test_script_suffix}) @@ -378,24 +378,7 @@ add_test (queue_redirect ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/run_queue_redirect add_library(test_store MODULE test_store.cpp) target_link_libraries (test_store qpidbroker qpidcommon) -set_target_properties (test_store PROPERTIES - COMPILE_DEFINITIONS _IN_QPID_BROKER - PREFIX "") +set_target_properties (test_store PROPERTIES PREFIX "" COMPILE_DEFINITIONS _IN_QPID_BROKER) add_library (dlclose_noop MODULE dlclose_noop.c) -#libdlclose_noop_la_LDFLAGS = -module -rpath $(abs_builddir) - -#CLEANFILES+=valgrind.out *.log *.vglog* dummy_test $(unit_wrappers) -# -## Longer running stability tests, not run by default check: target. -## Not run under valgrind, too slow -#LONG_TESTS=fanout_perftest shared_perftest multiq_perftest topic_perftest -#EXTRA_DIST+=$(LONG_TESTS) run_perftest -#check-long: -# $(MAKE) check TESTS="start_broker $(LONG_TESTS) stop_broker" VALGRIND= - -# -# legacystore -# -# add_subdirectory(legacystore) diff --git a/qpid/cpp/src/tests/ClientSessionTest.cpp b/qpid/cpp/src/tests/ClientSessionTest.cpp index 2da96bf30c..2236882eed 100644 --- a/qpid/cpp/src/tests/ClientSessionTest.cpp +++ b/qpid/cpp/src/tests/ClientSessionTest.cpp @@ -37,6 +37,7 @@ #include <boost/lexical_cast.hpp> #include <boost/bind.hpp> #include <boost/ptr_container/ptr_vector.hpp> +#include <boost/format.hpp> #include <vector> diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am deleted file mode 100644 index 808d9f9731..0000000000 --- a/qpid/cpp/src/tests/Makefile.am +++ /dev/null @@ -1,410 +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. -# - -AM_CXXFLAGS = $(WARNING_CFLAGS) -DBOOST_TEST_DYN_LINK -D_IN_QPID_BROKER -INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -PUBLIC_INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include # Use public API only -QMF_GEN=$(top_srcdir)/managementgen/qmf-gen - -abs_builddir=@abs_builddir@ -abs_srcdir=@abs_srcdir@ - -extra_libs = -lib_client = $(abs_builddir)/../libqpidclient.la -lib_messaging = $(abs_builddir)/../libqpidmessaging.la -lib_types = $(abs_builddir)/../libqpidtypes.la -lib_common = $(abs_builddir)/../libqpidcommon.la -lib_broker = $(abs_builddir)/../libqpidbroker.la -lib_console = $(abs_builddir)/../libqmfconsole.la -lib_qmf2 = $(abs_builddir)/../libqmf2.la -# lib_amqp_0_10 = $(abs_builddir)/../libqpidamqp_0_10.la - -# -# Initialize variables that are incremented with += -# -check_PROGRAMS= -check_LTLIBRARIES= -TESTS= -EXTRA_DIST= -CLEANFILES= -LONG_TESTS= -CLEAN_LOCAL= - -# -# Destination for intalled programs and tests defined here -# -qpidexecdir = $(libexecdir)/qpid -qpidexec_PROGRAMS = -qpidexec_SCRIPTS = -qpidexectestdir = $(qpidexecdir)/tests -qpidexectest_PROGRAMS = -qpidexectest_SCRIPTS = -tmoduledir = $(libdir)/qpid/tests -tmodule_LTLIBRARIES= - -# -# Unit test program -# -# Unit tests are built as a single program to reduce valgrind overhead -# when running the tests. If you want to build a subset of the tests do -# rm -f unit_test; make unit_test unit_test_OBJECTS="unit_test.o SelectedTest.o" -# - -TESTS+=unit_test -check_PROGRAMS+=unit_test -unit_test_LDADD=-lboost_unit_test_framework -lpthread \ - $(lib_messaging) $(lib_broker) $(lib_console) $(lib_qmf2) - -unit_test_SOURCES= unit_test.cpp unit_test.h \ - MessagingSessionTests.cpp \ - MessagingThreadTests.cpp \ - MessagingFixture.h \ - ClientSessionTest.cpp \ - BrokerFixture.h \ - exception_test.cpp \ - RefCounted.cpp \ - SessionState.cpp logging.cpp \ - AsyncCompletion.cpp \ - Url.cpp Uuid.cpp \ - Shlib.cpp FieldValue.cpp FieldTable.cpp Array.cpp \ - QueueOptionsTest.cpp \ - InlineAllocator.cpp \ - InlineVector.cpp \ - SequenceSet.cpp \ - StringUtils.cpp \ - RangeSet.cpp \ - AtomicValue.cpp \ - QueueTest.cpp \ - AccumulatedAckTest.cpp \ - DtxWorkRecordTest.cpp \ - DeliveryRecordTest.cpp \ - ExchangeTest.cpp \ - HeadersExchangeTest.cpp \ - MessageTest.cpp \ - QueueDepth.cpp \ - QueueRegistryTest.cpp \ - QueuePolicyTest.cpp \ - QueueFlowLimitTest.cpp \ - FramingTest.cpp \ - HeaderTest.cpp \ - SequenceNumberTest.cpp \ - TimerTest.cpp \ - TopicExchangeTest.cpp \ - TxBufferTest.cpp \ - ConnectionOptions.h \ - ManagementTest.cpp \ - MessageReplayTracker.cpp \ - ConsoleTest.cpp \ - ProxyTest.cpp \ - RetryList.cpp \ - FrameDecoder.cpp \ - ClientMessageTest.cpp \ - PollableCondition.cpp \ - Variant.cpp \ - Address.cpp \ - ClientMessage.cpp \ - Qmf2.cpp \ - BrokerOptions.cpp \ - Selector.cpp \ - SystemInfo.cpp - -if HAVE_XML -unit_test_SOURCES+= XmlClientSessionTest.cpp -endif - -TESTLIBFLAGS = -module -rpath $(abs_builddir) - -check_LTLIBRARIES += libshlibtest.la -libshlibtest_la_LDFLAGS = $(TESTLIBFLAGS) -libshlibtest_la_SOURCES = shlibtest.cpp - -tmodule_LTLIBRARIES += test_store.la -test_store_la_SOURCES = test_store.cpp -test_store_la_LIBADD = $(lib_broker) -test_store_la_LDFLAGS = -module - -include sasl.mk -if SSL -include ssl.mk -endif - -# Test programs that are installed and therefore built as part of make, not make check - -qpidexectest_SCRIPTS += qpid-cpp-benchmark qpid-cluster-benchmark install_env.sh qpidt -EXTRA_DIST += qpid-cpp-benchmark qpid-cluster-benchmark install_env.sh qpidt - -qpidexectest_PROGRAMS += receiver -receiver_SOURCES = \ - receiver.cpp \ - TestOptions.h \ - ConnectionOptions.h -receiver_LDADD = $(lib_client) -lboost_program_options $(lib_common) - -qpidexectest_PROGRAMS += sender -sender_SOURCES = \ - sender.cpp \ - TestOptions.h \ - ConnectionOptions.h \ - Statistics.cpp -sender_LDADD = $(lib_messaging) -lboost_program_options $(lib_common) $(lib_types) $(lib_client) - -qpidexectest_PROGRAMS += qpid-receive -qpid_receive_SOURCES = \ - qpid-receive.cpp \ - TestOptions.h \ - ConnectionOptions.h \ - Statistics.h \ - Statistics.cpp -qpid_receive_LDADD = $(lib_messaging) -lboost_program_options $(lib_common) $(lib_types) - -qpidexectest_PROGRAMS += qpid-send -qpid_send_SOURCES = \ - qpid-send.cpp \ - TestOptions.h \ - ConnectionOptions.h \ - Statistics.h \ - Statistics.cpp -qpid_send_LDADD = $(lib_messaging) -lboost_program_options $(lib_common) $(lib_types) - -qpidexectest_PROGRAMS+=qpid-perftest -qpid_perftest_SOURCES=qpid-perftest.cpp test_tools.h TestOptions.h ConnectionOptions.h -qpid_perftest_INCLUDES=$(PUBLIC_INCLUDES) -qpid_perftest_LDADD=$(lib_client) -lboost_program_options $(lib_common) - -qpidexectest_PROGRAMS+=qpid-txtest -qpid_txtest_INCLUDES=$(PUBLIC_INCLUDES) -qpid_txtest_SOURCES=qpid-txtest.cpp TestOptions.h ConnectionOptions.h -qpid_txtest_LDADD=$(lib_client) -lboost_program_options $(lib_common) - -qpidexectest_PROGRAMS+=qpid-latency-test -qpid_latency_test_INCLUDES=$(PUBLIC_INCLUDES) -qpid_latency_test_SOURCES=qpid-latency-test.cpp TestOptions.h ConnectionOptions.h -qpid_latency_test_LDADD=$(lib_client) -lboost_program_options $(lib_common) - -qpidexectest_PROGRAMS+=qpid-client-test -qpid_client_test_INCLUDES=$(PUBLIC_INCLUDES) -qpid_client_test_SOURCES=qpid-client-test.cpp TestOptions.h ConnectionOptions.h -qpid_client_test_LDADD=$(lib_client) -lboost_program_options $(lib_common) - -qpidexectest_PROGRAMS+=qpid-topic-listener -qpid_topic_listener_INCLUDES=$(PUBLIC_INCLUDES) -qpid_topic_listener_SOURCES=qpid-topic-listener.cpp TestOptions.h ConnectionOptions.h -qpid_topic_listener_LDADD=$(lib_client) -lboost_program_options $(lib_common) - -qpidexectest_PROGRAMS+=qpid-topic-publisher -qpid_topic_publisher_INCLUDES=$(PUBLIC_INCLUDES) -qpid_topic_publisher_SOURCES=qpid-topic-publisher.cpp TestOptions.h ConnectionOptions.h -qpid_topic_publisher_LDADD=$(lib_client) -lboost_program_options $(lib_common) - -qpidexectest_PROGRAMS+=qpid-ping -qpid_ping_INCLUDES=$(PUBLIC_INCLUDES) -qpid_ping_SOURCES=qpid-ping.cpp test_tools.h TestOptions.h ConnectionOptions.h -qpid_ping_LDADD=$(lib_client) -lboost_program_options $(lib_common) - -# -# Other test programs -# - -check_PROGRAMS+=echotest -echotest_INCLUDES=$(PUBLIC_INCLUDES) -echotest_SOURCES=echotest.cpp TestOptions.h ConnectionOptions.h -echotest_LDADD=$(lib_client) - -check_PROGRAMS+=publish -publish_INCLUDES=$(PUBLIC_INCLUDES) -publish_SOURCES=publish.cpp TestOptions.h ConnectionOptions.h -publish_LDADD=$(lib_client) - -check_PROGRAMS+=consume -consume_INCLUDES=$(PUBLIC_INCLUDES) -consume_SOURCES=consume.cpp TestOptions.h ConnectionOptions.h -consume_LDADD=$(lib_client) - -check_PROGRAMS+=header_test -header_test_INCLUDES=$(PUBLIC_INCLUDES) -header_test_SOURCES=header_test.cpp TestOptions.h ConnectionOptions.h -header_test_LDADD=$(lib_client) - -check_PROGRAMS+=declare_queues -declare_queues_INCLUDES=$(PUBLIC_INCLUDES) -declare_queues_SOURCES=declare_queues.cpp -declare_queues_LDADD=$(lib_client) - -check_PROGRAMS+=replaying_sender -replaying_sender_INCLUDES=$(PUBLIC_INCLUDES) -replaying_sender_SOURCES=replaying_sender.cpp -replaying_sender_LDADD=$(lib_client) - -check_PROGRAMS+=resuming_receiver -resuming_receiver_INCLUDES=$(PUBLIC_INCLUDES) -resuming_receiver_SOURCES=resuming_receiver.cpp -resuming_receiver_LDADD=$(lib_client) - -check_PROGRAMS+=txshift -txshift_INCLUDES=$(PUBLIC_INCLUDES) -txshift_SOURCES=txshift.cpp TestOptions.h ConnectionOptions.h -txshift_LDADD=$(lib_client) - -check_PROGRAMS+=txjob -txjob_INCLUDES=$(PUBLIC_INCLUDES) -txjob_SOURCES=txjob.cpp TestOptions.h ConnectionOptions.h -txjob_LDADD=$(lib_client) - -check_PROGRAMS+=PollerTest -PollerTest_SOURCES=PollerTest.cpp -PollerTest_LDADD=$(lib_common) $(lib_client) $(SOCKLIBS) - -check_PROGRAMS+=DispatcherTest -DispatcherTest_SOURCES=DispatcherTest.cpp -DispatcherTest_LDADD=$(lib_common) $(lib_client) $(SOCKLIBS) - -check_PROGRAMS+=datagen -datagen_SOURCES=datagen.cpp -datagen_LDADD=$(lib_common) $(lib_client) - -check_PROGRAMS+=qpid-stream -qpid_stream_INCLUDES=$(PUBLIC_INCLUDES) -qpid_stream_SOURCES=qpid-stream.cpp -qpid_stream_LDADD=$(lib_messaging) - -check_PROGRAMS+=msg_group_test -msg_group_test_INCLUDES=$(PUBLIC_INCLUDES) -msg_group_test_SOURCES=msg_group_test.cpp -msg_group_test_LDADD=$(lib_messaging) - -TESTS_ENVIRONMENT = \ - VALGRIND=$(VALGRIND) \ - LIBTOOL="$(LIBTOOL)" \ - QPID_DATA_DIR= \ - $(srcdir)/run_test - -system_tests = qpid-client-test quick_perftest quick_topictest run_header_test quick_txtest \ - run_msg_group_tests -TESTS += start_broker $(system_tests) python_tests stop_broker \ - run_ha_tests run_interlink_tests run_federation_tests run_federation_sys_tests \ - run_acl_tests run_cli_tests dynamic_log_level_test \ - dynamic_log_hires_timestamp run_queue_flow_limit_tests ipv6_test - -EXTRA_DIST += \ - run_test vg_check \ - run-unit-tests start_broker python_tests stop_broker \ - quick_topictest \ - quick_perftest \ - quick_txtest \ - topictest \ - run_header_test \ - header_test.py \ - ssl_test \ - ping_broker \ - config.null \ - run_federation_tests \ - run_federation_sys_tests \ - run_long_federation_sys_tests \ - run_cli_tests \ - run_acl_tests \ - .valgrind.supp \ - MessageUtils.h \ - TestMessageStore.h \ - TxMocks.h \ - run_perftest \ - ring_queue_test \ - run_ring_queue_test \ - run_paged_queue_tests \ - dynamic_log_level_test \ - dynamic_log_hires_timestamp \ - qpid-ctrl \ - CMakeLists.txt \ - windows/DisableWin32ErrorWindows.cpp \ - background.ps1 \ - find_prog.ps1 \ - python_tests.ps1 \ - quick_topictest.ps1 \ - run_federation_tests.ps1 \ - run_header_test.ps1 \ - run_test.ps1 \ - start_broker.ps1 \ - stop_broker.ps1 \ - topictest.ps1 \ - run_queue_flow_limit_tests \ - run_msg_group_tests \ - ipv6_test \ - run_ha_tests \ - ha_test.py \ - ha_tests.py \ - run_interlink_tests \ - interlink_tests.py \ - brokertest.py \ - test_env.ps1.in - -check_LTLIBRARIES += libdlclose_noop.la -libdlclose_noop_la_LDFLAGS = -module -rpath $(abs_builddir) -libdlclose_noop_la_SOURCES = dlclose_noop.c - -CLEANFILES+=valgrind.out *.log *.vglog* dummy_test qpidd.port $(unit_wrappers) - -# Longer running stability tests, not run by default check: target. -# Not run under valgrind, too slow - -LONG_TESTS+=start_broker \ - fanout_perftest shared_perftest multiq_perftest topic_perftest run_ring_queue_test run_paged_queue_tests\ - run_msg_group_tests_soak \ - stop_broker \ - run_long_federation_sys_tests - -EXTRA_DIST+= \ - fanout_perftest \ - shared_perftest \ - multiq_perftest \ - topic_perftest \ - sasl_test_setup.sh \ - run_msg_group_tests_soak \ - qpidd-empty.conf \ - qpidd-p0 - -check-long: - $(MAKE) check TESTS="$(LONG_TESTS)" VALGRIND= - -# Things that should be built before the check target runs. -check-am: python_prep test_env.sh install_env.sh sasl_config - -PYTHON_SRC_DIR=$(abs_srcdir)/../../../python -PYTHON_BLD_DIR=$(abs_builddir)/python - -# 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); \ - then cd $(PYTHON_SRC_DIR) && python $(PYTHON_SRC_DIR)/setup.py install \ - --prefix=$(PYTHON_BLD_DIR) --install-lib=$(PYTHON_BLD_DIR) \ - --install-scripts=$(PYTHON_BLD_DIR)/commands; \ - else echo "WARNING: python client not built, missing $(PYTHON_SRC_DIR)"; fi - -sasl_config: sasl_test_setup.sh - sh $(srcdir)/sasl_test_setup.sh - touch sasl_config - -CLEAN_LOCAL += sasl_config - -clean-local: - rm -rf $(CLEAN_LOCAL) - -include testagent.mk -include brokermgmt.mk - diff --git a/qpid/cpp/src/tests/ManagementTest.cpp b/qpid/cpp/src/tests/ManagementTest.cpp index 8944c084c0..98ef591fae 100644 --- a/qpid/cpp/src/tests/ManagementTest.cpp +++ b/qpid/cpp/src/tests/ManagementTest.cpp @@ -21,7 +21,6 @@ #include "qpid/management/ManagementObject.h" #include "qpid/framing/Buffer.h" -#include "qpid/console/ObjectId.h" #include "unit_test.h" namespace qpid { @@ -93,32 +92,6 @@ QPID_AUTO_TEST_CASE(testObjectIdCreate) { BOOST_CHECK_EQUAL(oid.getV2Key(), "an-object-name"); } -QPID_AUTO_TEST_CASE(testConsoleObjectId) { - qpid::console::ObjectId oid1, oid2; - - oid1.setValue(1, 2); - oid2.setValue(3, 4); - - BOOST_CHECK(oid1 < oid2); - BOOST_CHECK(oid1 <= oid2); - BOOST_CHECK(oid2 > oid1); - BOOST_CHECK(oid2 >= oid1); - BOOST_CHECK(oid1 != oid2); - BOOST_CHECK(oid1 == oid1); - - oid1.setValue(3, 6); - oid2.setValue(3, 4); - - BOOST_CHECK(oid1 > oid2); - BOOST_CHECK(oid1 >= oid2); - BOOST_CHECK(oid2 < oid1); - BOOST_CHECK(oid2 <= oid1); - BOOST_CHECK(oid1 != oid2); - - oid2.setValue(3, 6); - BOOST_CHECK(oid1 == oid2); -} - QPID_AUTO_TEST_SUITE_END() }} // namespace qpid::tests diff --git a/qpid/cpp/src/tests/MessageReplayTracker.cpp b/qpid/cpp/src/tests/MessageReplayTracker.cpp index e35f673683..c0778247f0 100644 --- a/qpid/cpp/src/tests/MessageReplayTracker.cpp +++ b/qpid/cpp/src/tests/MessageReplayTracker.cpp @@ -23,6 +23,8 @@ #include "qpid/client/MessageReplayTracker.h" #include "qpid/sys/Time.h" +#include <boost/format.hpp> + namespace qpid { namespace tests { diff --git a/qpid/cpp/src/tests/MessagingFixture.h b/qpid/cpp/src/tests/MessagingFixture.h index 2312a87e9d..1d70d4cfa6 100644 --- a/qpid/cpp/src/tests/MessagingFixture.h +++ b/qpid/cpp/src/tests/MessagingFixture.h @@ -35,6 +35,8 @@ #include "qpid/messaging/Message.h" #include "qpid/types/Variant.h" +#include <boost/format.hpp> + namespace qpid { namespace tests { @@ -115,6 +117,7 @@ struct MessagingFixture : public BrokerFixture (boost::format("amqp:tcp:localhost:%1%") % (port)).str()); connection.open(); return connection; + } /** Open a connection to the broker. */ @@ -231,9 +234,10 @@ inline void receive(messaging::Receiver& receiver, uint count = 1, uint start = class MethodInvoker { public: - MethodInvoker(messaging::Session& session) : replyTo("#; {create:always, node:{x-declare:{auto-delete:true}}}"), - sender(session.createSender("qmf.default.direct/broker")), - receiver(session.createReceiver(replyTo)) {} + MethodInvoker(messaging::Session session) : + replyTo("#; {create:always, node:{x-declare:{auto-delete:true}}}"), + sender(session.createSender("qmf.default.direct/broker")), + receiver(session.createReceiver(replyTo)) {} void createExchange(const std::string& name, const std::string& type, bool durable=false) { @@ -292,11 +296,14 @@ class MethodInvoker methodRequest("delete", params); } - void methodRequest(const std::string& method, const Variant::Map& inParams, Variant::Map* outParams = 0) + void methodRequest( + const std::string& method, + const Variant::Map& inParams, Variant::Map* outParams = 0, + const std::string& objectName="org.apache.qpid.broker:broker:amqp-broker") { Variant::Map content; Variant::Map objectId; - objectId["_object_name"] = "org.apache.qpid.broker:broker:amqp-broker"; + objectId["_object_name"] = objectName;; content["_object_id"] = objectId; content["_method_name"] = method; content["_arguments"] = inParams; diff --git a/qpid/cpp/src/tests/MessagingSessionTests.cpp b/qpid/cpp/src/tests/MessagingSessionTests.cpp index b388f2c13a..5cc595c56f 100644 --- a/qpid/cpp/src/tests/MessagingSessionTests.cpp +++ b/qpid/cpp/src/tests/MessagingSessionTests.cpp @@ -1289,6 +1289,95 @@ QPID_AUTO_TEST_CASE(testSimpleRequestResponse) BOOST_CHECK_EQUAL(m.getSubject(), original.getSubject()); } +QPID_AUTO_TEST_CASE(testSelfDestructQueue) +{ + MessagingFixture fix; + Session other = fix.connection.createSession(); + Receiver r1 = other.createReceiver("amq.fanout; {link:{reliability:at-least-once, x-declare:{arguments:{qpid.max_count:10,qpid.policy_type:self-destruct}}}}"); + Receiver r2 = fix.session.createReceiver("amq.fanout"); + //send request + Sender s = fix.session.createSender("amq.fanout"); + for (uint i = 0; i < 20; ++i) { + s.send(Message((boost::format("MSG_%1%") % (i+1)).str())); + } + try { + ScopedSuppressLogging sl; + for (uint i = 0; i < 20; ++i) { + r1.fetch(Duration::SECOND); + } + BOOST_FAIL("Expected exception."); + } catch (const qpid::messaging::MessagingException&) { + } + + for (uint i = 0; i < 20; ++i) { + BOOST_CHECK_EQUAL(r2.fetch(Duration::SECOND).getContent(), (boost::format("MSG_%1%") % (i+1)).str()); + } +} + +QPID_AUTO_TEST_CASE(testReroutingRingQueue) +{ + MessagingFixture fix; + Receiver r1 = fix.session.createReceiver("my-queue; {create:always, node:{x-declare:{alternate-exchange:amq.fanout, auto-delete:True, arguments:{qpid.max_count:10,qpid.policy_type:ring}}}}"); + Receiver r2 = fix.session.createReceiver("amq.fanout"); + + Sender s = fix.session.createSender("my-queue"); + for (uint i = 0; i < 20; ++i) { + s.send(Message((boost::format("MSG_%1%") % (i+1)).str())); + } + for (uint i = 10; i < 20; ++i) { + BOOST_CHECK_EQUAL(r1.fetch(Duration::SECOND).getContent(), (boost::format("MSG_%1%") % (i+1)).str()); + } + for (uint i = 0; i < 10; ++i) { + BOOST_CHECK_EQUAL(r2.fetch(Duration::SECOND).getContent(), (boost::format("MSG_%1%") % (i+1)).str()); + } +} + +QPID_AUTO_TEST_CASE(testReleaseOnPriorityQueue) +{ + MessagingFixture fix; + std::string queue("queue; {create:always, node:{x-declare:{auto-delete:True, arguments:{qpid.priorities:10}}}}"); + std::string text("my message"); + Sender sender = fix.session.createSender(queue); + sender.send(Message(text)); + Receiver receiver = fix.session.createReceiver(queue); + Message msg; + for (uint i = 0; i < 10; ++i) { + if (receiver.fetch(msg, Duration::SECOND)) { + BOOST_CHECK_EQUAL(msg.getContent(), text); + fix.session.release(msg); + } else { + BOOST_FAIL("Released message not redelivered as expected."); + } + } + fix.session.acknowledge(); +} + +QPID_AUTO_TEST_CASE(testRollbackWithFullPrefetch) +{ + QueueFixture fix; + std::string first("first"); + std::string second("second"); + Sender sender = fix.session.createSender(fix.queue); + for (uint i = 0; i < 10; ++i) { + sender.send(Message((boost::format("MSG_%1%") % (i+1)).str())); + } + Session txsession = fix.connection.createTransactionalSession(); + Receiver receiver = txsession.createReceiver(fix.queue); + receiver.setCapacity(9); + Message msg; + for (uint i = 0; i < 10; ++i) { + if (receiver.fetch(msg, Duration::SECOND)) { + BOOST_CHECK_EQUAL(msg.getContent(), std::string("MSG_1")); + txsession.rollback(); + } else { + BOOST_FAIL("Released message not redelivered as expected."); + break; + } + } + txsession.acknowledge(); + txsession.commit(); +} + 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 00e964602a..ce1b0addea 100644 --- a/qpid/cpp/src/tests/QueuePolicyTest.cpp +++ b/qpid/cpp/src/tests/QueuePolicyTest.cpp @@ -28,6 +28,8 @@ #include "qpid/framing/reply_exceptions.h" #include "BrokerFixture.h" +#include <boost/format.hpp> + using namespace qpid::broker; using namespace qpid::client; using namespace qpid::framing; diff --git a/qpid/cpp/src/tests/Shlib.cpp b/qpid/cpp/src/tests/Shlib.cpp index d8ad4c14d8..7f01323e3c 100644 --- a/qpid/cpp/src/tests/Shlib.cpp +++ b/qpid/cpp/src/tests/Shlib.cpp @@ -35,13 +35,7 @@ typedef void (*CallMe)(int*); QPID_AUTO_TEST_CASE(testShlib) { - // The CMake-based build passes in the shared lib suffix; if it's not - // there, this is a Linux/UNIX libtool-based build. -#if defined (QPID_SHLIB_PREFIX) && defined (QPID_SHLIB_SUFFIX) Shlib sh("./" QPID_SHLIB_PREFIX "shlibtest" QPID_SHLIB_POSTFIX QPID_SHLIB_SUFFIX); -#else - Shlib sh(".libs/libshlibtest.so"); -#endif // Double cast to avoid ISO warning. CallMe callMe=sh.getSymbol<CallMe>("callMe"); BOOST_REQUIRE(callMe != 0); @@ -59,11 +53,7 @@ QPID_AUTO_TEST_CASE(testShlib) { QPID_AUTO_TEST_CASE(testAutoShlib) { int unloaded = 0; { -#if defined (QPID_SHLIB_PREFIX) && defined (QPID_SHLIB_SUFFIX) AutoShlib sh("./" QPID_SHLIB_PREFIX "shlibtest" QPID_SHLIB_POSTFIX QPID_SHLIB_SUFFIX); -#else - AutoShlib sh(".libs/libshlibtest.so"); -#endif CallMe callMe=sh.getSymbol<CallMe>("callMe"); BOOST_REQUIRE(callMe != 0); callMe(&unloaded); diff --git a/qpid/cpp/src/tests/TransactionObserverTest.cpp b/qpid/cpp/src/tests/TransactionObserverTest.cpp new file mode 100644 index 0000000000..fd1c331ae7 --- /dev/null +++ b/qpid/cpp/src/tests/TransactionObserverTest.cpp @@ -0,0 +1,144 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "unit_test.h" +#include "test_tools.h" +#include "MessagingFixture.h" +#include "qpid/broker/BrokerObserver.h" +#include "qpid/broker/TransactionObserver.h" +#include "qpid/broker/TxBuffer.h" +#include "qpid/broker/Queue.h" +#include "qpid/ha/types.h" + +#include <boost/bind.hpp> +#include <boost/function.hpp> +#include <boost/lexical_cast.hpp> +#include <iostream> +#include <vector> + +namespace qpid { +namespace tests { + +using framing::SequenceSet; +using messaging::Message; +using boost::shared_ptr; + +using namespace boost::assign; +using namespace boost; +using namespace broker; +using namespace std; +using namespace messaging; +using namespace types; + +QPID_AUTO_TEST_SUITE(TransactionalObserverTest) + +Message msg(string content) { return Message(content); } + +struct MockTransactionObserver : public TransactionObserver { + bool prep; + vector<string> events; + + MockTransactionObserver(bool prep_=true) : prep(prep_) {} + + void record(const string& e) { events.push_back(e); } + + void enqueue(const shared_ptr<Queue>& q, const broker::Message& m) { + record("enqueue "+q->getName()+" "+m.getContent()); + } + void dequeue(const Queue::shared_ptr& q, SequenceNumber p, SequenceNumber r) { + record("dequeue "+q->getName()+" "+ + lexical_cast<string>(p)+" "+lexical_cast<string>(r)); + } + bool prepare() { record("prepare"); return prep; } + void commit() { record("commit"); } + void rollback() {record("rollback"); } +}; + +struct MockBrokerObserver : public BrokerObserver { + bool prep; + shared_ptr<MockTransactionObserver> tx; + + MockBrokerObserver(bool prep_=true) : prep(prep_) {} + + void startTx(const shared_ptr<TxBuffer>& buffer) { + tx.reset(new MockTransactionObserver(prep)); + buffer->setObserver(tx); + } +}; + +Session simpleTxTransaction(MessagingFixture& fix) { + fix.session.createSender("q1;{create:always}").send(msg("foo")); // Not in TX + // Transaction with 1 enqueue and 1 dequeue. + Session txSession = fix.connection.createTransactionalSession(); + BOOST_CHECK_EQUAL("foo", txSession.createReceiver("q1").fetch().getContent()); + txSession.acknowledge(); + txSession.createSender("q2;{create:always}").send(msg("bar")); + return txSession; +} + +QPID_AUTO_TEST_CASE(tesTxtCommit) { + MessagingFixture fix; + shared_ptr<MockBrokerObserver> brokerObserver(new MockBrokerObserver); + fix.broker->getBrokerObservers().add(brokerObserver); + Session txSession = simpleTxTransaction(fix); + txSession.commit(); + // Note on ordering: observers see enqueues as they happen, but dequeues just + // before prepare. + BOOST_CHECK_EQUAL( + list_of<string>("enqueue q2 bar")("dequeue q1 1 0")("prepare")("commit"), + brokerObserver->tx->events + ); +} + +QPID_AUTO_TEST_CASE(testTxFail) { + MessagingFixture fix; + shared_ptr<MockBrokerObserver> brokerObserver(new MockBrokerObserver(false)); + fix.broker->getBrokerObservers().add(brokerObserver); + Session txSession = simpleTxTransaction(fix); + try { + txSession.commit(); + BOOST_FAIL("Expected exception"); + } catch(...) {} + + BOOST_CHECK_EQUAL( + list_of<string>("enqueue q2 bar")("dequeue q1 1 0")("prepare")("rollback"), + brokerObserver->tx->events + ); +} + +QPID_AUTO_TEST_CASE(testTxRollback) { + MessagingFixture fix; + shared_ptr<MockBrokerObserver> brokerObserver(new MockBrokerObserver(false)); + fix.broker->getBrokerObservers().add(brokerObserver); + Session txSession = simpleTxTransaction(fix); + txSession.rollback(); + // Note: The dequeue does not appear here. This is because TxAccepts + // (i.e. dequeues) are not enlisted until SemanticState::commit and are + // never enlisted if the transaction is rolled back. + BOOST_CHECK_EQUAL( + list_of<string>("enqueue q2 bar")("rollback"), + brokerObserver->tx->events + ); +} + +QPID_AUTO_TEST_SUITE_END() + +}} // namespace qpid::tests diff --git a/qpid/cpp/src/tests/TxMocks.h b/qpid/cpp/src/tests/TxMocks.h index bf21104f70..8b54e7484b 100644 --- a/qpid/cpp/src/tests/TxMocks.h +++ b/qpid/cpp/src/tests/TxMocks.h @@ -103,6 +103,9 @@ public: if(!debugName.empty()) std::cout << std::endl << "MockTxOp[" << debugName << "]::rollback()" << std::endl; actual.push_back(ROLLBACK); } + + void callObserver(const boost::shared_ptr<TransactionObserver>&) {} + MockTxOp& expectPrepare(){ expected.push_back(PREPARE); return *this; diff --git a/qpid/cpp/src/tests/brokermgmt.mk b/qpid/cpp/src/tests/brokermgmt.mk deleted file mode 100644 index cf9a47200c..0000000000 --- a/qpid/cpp/src/tests/brokermgmt.mk +++ /dev/null @@ -1,44 +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. -# - -# Build a unit test for the broker's internal management agent. - -BROKERMGMT_GEN_SRC= \ - brokermgmt_gen/qmf/org/apache/qpid/broker/mgmt/test/Package.cpp \ - brokermgmt_gen/qmf/org/apache/qpid/broker/mgmt/test/Package.h \ - brokermgmt_gen/qmf/org/apache/qpid/broker/mgmt/test/TestObject.h \ - brokermgmt_gen/qmf/org/apache/qpid/broker/mgmt/test/TestObject.cpp - -$(BROKERMGMT_GEN_SRC): brokermgmt_gen.timestamp - -if GENERATE -BROKERMGMT_DEPS=../mgen.timestamp -endif # GENERATE -brokermgmt_gen.timestamp: BrokerMgmtAgent.xml ${BROKERMGMT_DEPS} - $(QMF_GEN) -b -o brokermgmt_gen/qmf $(srcdir)/BrokerMgmtAgent.xml - touch $@ - -BrokerMgmtAgent.$(OBJEXT): $(BROKERMGMT_GEN_SRC) - -CLEANFILES+=$(BROKERMGMT_GEN_SRC) brokermgmt_gen.timestamp - -unit_test_SOURCES+=BrokerMgmtAgent.cpp ${BROKERMGMT_GEN_SRC} -INCLUDES+= -Ibrokermgmt_gen - -EXTRA_DIST+=BrokerMgmtAgent.xml diff --git a/qpid/cpp/src/tests/brokertest.py b/qpid/cpp/src/tests/brokertest.py index 15372b312d..2786454399 100644 --- a/qpid/cpp/src/tests/brokertest.py +++ b/qpid/cpp/src/tests/brokertest.py @@ -78,7 +78,7 @@ def error_line(filename, n=1): except: return "" return ":\n" + "".join(result) -def retry(function, timeout=10, delay=.01, max_delay=1): +def retry(function, timeout=10, delay=.001, max_delay=1): """Call function until it returns a true value or timeout expires. Double the delay for each retry up to max_delay. Returns what function returns if true, None if timeout expires.""" @@ -141,7 +141,7 @@ class Popen(subprocess.Popen): finally: f.close() log.debug("Started process %s: %s" % (self.pname, " ".join(self.cmd))) - def __str__(self): return "Popen<%s>"%(self.pname) + def __repr__(self): return "Popen<%s>"%(self.pname) def outfile(self, ext): return "%s.%s" % (self.pname, ext) @@ -242,16 +242,12 @@ class Broker(Popen): _broker_count = 0 _log_count = 0 - def __str__(self): return "Broker<%s %s :%d>"%(self.log, self.pname, self.port()) - - def find_log(self): - self.log = "%03d:%s.log" % (Broker._log_count, self.name) - Broker._log_count += 1 + def __repr__(self): return "<Broker:%s:%d>"%(self.log, self.port()) def get_log(self): return os.path.abspath(self.log) - def __init__(self, test, args=[], name=None, expect=EXPECT_RUNNING, port=0, log_level=None, wait=None, show_cmd=False): + def __init__(self, test, args=[], test_store=False, name=None, expect=EXPECT_RUNNING, port=0, log_level=None, wait=None, show_cmd=False): """Start a broker daemon. name determines the data-dir and log file names.""" @@ -273,11 +269,18 @@ class Broker(Popen): else: self.name = "broker%d" % Broker._broker_count Broker._broker_count += 1 - self.find_log() + + self.log = "%03d:%s.log" % (Broker._log_count, self.name) + self.store_log = "%03d:%s.store.log" % (Broker._log_count, self.name) + Broker._log_count += 1 + cmd += ["--log-to-file", self.log] cmd += ["--log-to-stderr=no"] cmd += ["--log-enable=%s"%(log_level or "info+") ] + if test_store: cmd += ["--load-module", BrokerTest.test_store_lib, + "--test-store-events", self.store_log] + self.datadir = self.name cmd += ["--data-dir", self.datadir] if show_cmd: print cmd @@ -285,7 +288,6 @@ class Broker(Popen): test.cleanup_stop(self) self._host = "127.0.0.1" log.debug("Started broker %s (%s, %s)" % (self.name, self.pname, self.log)) - self._log_ready = False def startQmf(self, handler=None): self.qmf_session = qmf.console.Session(handler) @@ -363,29 +365,21 @@ class Broker(Popen): def host_port(self): return "%s:%s" % (self.host(), self.port()) - def log_contains(self, str, timeout=1): - """Wait for str to appear in the log file up to timeout. Return true if found""" - return retry(lambda: find_in_file(str, self.log), timeout) - - def log_ready(self): - """Return true if the log file exists and contains a broker ready message""" - if not self._log_ready: - self._log_ready = find_in_file("notice Broker running", self.log) - return self._log_ready - def ready(self, timeout=30, **kwargs): """Wait till broker is ready to serve clients""" - # First make sure the broker is listening by checking the log. - if not retry(self.log_ready, timeout=timeout): - raise Exception( - "Timed out waiting for broker %s%s"%(self.name, error_line(self.log,5))) - # Create a connection and a session. - try: - c = self.connect(**kwargs) - try: c.session() - finally: c.close() - except Exception,e: raise RethrownException( - "Broker %s not responding: (%s)%s"%(self.name,e,error_line(self.log, 5))) + deadline = time.time()+timeout + while True: + try: + c = self.connect(timeout=timeout, **kwargs) + try: + c.session() + return # All good + finally: c.close() + except Exception,e: # Retry up to timeout + if time.time() > deadline: + raise RethrownException( + "Broker %s not responding: (%s)%s"%( + self.name,e,error_line(self.log, 5))) def browse(session, queue, timeout=0, transform=lambda m: m.content): """Return a list with the contents of each message on queue.""" @@ -407,7 +401,7 @@ def assert_browse(session, queue, expect_contents, timeout=0, transform=lambda m if msg: msg = "%s: %r != %r"%(msg, expect_contents, actual_contents) assert expect_contents == actual_contents, msg -def assert_browse_retry(session, queue, expect_contents, timeout=1, delay=.01, transform=lambda m:m.content, msg="browse failed"): +def assert_browse_retry(session, queue, expect_contents, timeout=1, delay=.001, transform=lambda m:m.content, msg="browse failed"): """Wait up to timeout for contents of queue to match expect_contents""" test = lambda: browse(session, queue, 0, transform=transform) == expect_contents retry(test, timeout, delay) @@ -421,6 +415,10 @@ class BrokerTest(TestCase): Provides a well-known working directory for each test. """ + def __init__(self, *args, **kwargs): + self.longMessage = True # Enable long messages for assert*(..., msg=xxx) + TestCase.__init__(self, *args, **kwargs) + # Environment settings. qpidd_exec = os.path.abspath(checkenv("QPIDD_EXEC")) ha_lib = os.getenv("HA_LIB") @@ -480,7 +478,7 @@ class BrokerTest(TestCase): def assert_browse(self, *args, **kwargs): assert_browse(*args, **kwargs) def assert_browse_retry(self, *args, **kwargs): assert_browse_retry(*args, **kwargs) -def join(thread, timeout=10): +def join(thread, timeout=30): thread.join(timeout) if thread.isAlive(): raise Exception("Timed out joining thread %s"%thread) diff --git a/qpid/cpp/src/tests/cli_tests.py b/qpid/cpp/src/tests/cli_tests.py index dceafc5427..eee9bc648c 100755 --- a/qpid/cpp/src/tests/cli_tests.py +++ b/qpid/cpp/src/tests/cli_tests.py @@ -69,47 +69,39 @@ class CliTests(TestBase010): self.startBrokerAccess() queue1 = self.makeQueue("test_queue_params1", "--limit-policy none") queue2 = self.makeQueue("test_queue_params2", "--limit-policy reject") - queue3 = self.makeQueue("test_queue_params3", "--limit-policy flow-to-disk") - queue4 = self.makeQueue("test_queue_params4", "--limit-policy ring") - queue5 = self.makeQueue("test_queue_params5", "--limit-policy ring-strict") + queue3 = self.makeQueue("test_queue_params3", "--limit-policy ring") LIMIT = "qpid.policy_type" assert LIMIT not in queue1.arguments self.assertEqual(queue2.arguments[LIMIT], "reject") - self.assertEqual(queue3.arguments[LIMIT], "flow_to_disk") - self.assertEqual(queue4.arguments[LIMIT], "ring") - self.assertEqual(queue5.arguments[LIMIT], "ring_strict") + self.assertEqual(queue3.arguments[LIMIT], "ring") - queue6 = self.makeQueue("test_queue_params6", "--lvq-key lkey") + queue4 = self.makeQueue("test_queue_params4", "--lvq-key lkey") LVQKEY = "qpid.last_value_queue_key" - assert LVQKEY not in queue5.arguments - assert LVQKEY in queue6.arguments - assert queue6.arguments[LVQKEY] == "lkey" + assert LVQKEY not in queue3.arguments + assert LVQKEY in queue4.arguments + assert queue4.arguments[LVQKEY] == "lkey" def test_queue_params_api(self): self.startBrokerAccess() queue1 = self.makeQueue("test_queue_params_api1", "--limit-policy none", True) queue2 = self.makeQueue("test_queue_params_api2", "--limit-policy reject", True) - queue3 = self.makeQueue("test_queue_params_api3", "--limit-policy flow-to-disk", True) - queue4 = self.makeQueue("test_queue_params_api4", "--limit-policy ring", True) - queue5 = self.makeQueue("test_queue_params_api5", "--limit-policy ring-strict", True) + queue3 = self.makeQueue("test_queue_params_api3", "--limit-policy ring", True) LIMIT = "qpid.policy_type" assert LIMIT not in queue1.arguments self.assertEqual(queue2.arguments[LIMIT], "reject") - self.assertEqual(queue3.arguments[LIMIT], "flow_to_disk") - self.assertEqual(queue4.arguments[LIMIT], "ring") - self.assertEqual(queue5.arguments[LIMIT], "ring_strict") + self.assertEqual(queue3.arguments[LIMIT], "ring") - queue6 = self.makeQueue("test_queue_params_api6", "--lvq-key lkey") + queue4 = self.makeQueue("test_queue_params_api4", "--lvq-key lkey") LVQKEY = "qpid.last_value_queue_key" - assert LVQKEY not in queue5.arguments - assert LVQKEY in queue6.arguments - assert queue6.arguments[LVQKEY] == "lkey" + assert LVQKEY not in queue3.arguments + assert LVQKEY in queue4.arguments + assert queue4.arguments[LVQKEY] == "lkey" def test_qpid_config(self): diff --git a/qpid/cpp/src/tests/failing-amqp0-10-python-tests b/qpid/cpp/src/tests/failing-amqp0-10-python-tests new file mode 100644 index 0000000000..cb742a25e5 --- /dev/null +++ b/qpid/cpp/src/tests/failing-amqp0-10-python-tests @@ -0,0 +1,7 @@ +#The following four tests fail the because pure python client excludes +#the node type for queues from the reply-to address, weheras the swigged +#client does not (as that prevents it resolving the node on every send) +qpid.tests.messaging.message.MessageEchoTests.testReplyTo +qpid.tests.messaging.message.MessageEchoTests.testReplyToQueue +qpid.tests.messaging.message.MessageEchoTests.testReplyToQueueSubject +qpid.tests.messaging.message.MessageEchoTests.testProperties diff --git a/qpid/cpp/src/tests/failing-amqp1.0-python-tests b/qpid/cpp/src/tests/failing-amqp1.0-python-tests new file mode 100644 index 0000000000..2cae7b6306 --- /dev/null +++ b/qpid/cpp/src/tests/failing-amqp1.0-python-tests @@ -0,0 +1,2 @@ +qpid_tests.broker_0_10.new_api.GeneralTests.test_qpid_3481_acquired_to_alt_exchange_2_consumers +qpid_tests.broker_0_10.new_api.GeneralTests.test_qpid_3481_acquired_to_alt_exchange diff --git a/qpid/cpp/src/tests/ha_test.py b/qpid/cpp/src/tests/ha_test.py index f2fc50054f..3b5874875a 100755 --- a/qpid/cpp/src/tests/ha_test.py +++ b/qpid/cpp/src/tests/ha_test.py @@ -48,6 +48,24 @@ class QmfAgent(object): address, client_properties={"qpid.ha-admin":1}, **kwargs) self._agent = BrokerAgent(self._connection) + def queues(self): + return [q.values['name'] for q in self._agent.getAllQueues()] + + def repsub_queue(self, sub): + """If QMF subscription sub is a replicating subscription return + the name of the replicated queue, else return None""" + session_name = self.getSession(sub.sessionRef).name + m = re.search("qpid.ha-q:(.*)\.", session_name) + return m and m.group(1) + + def repsub_queues(self): + """Return queue names for all replicating subscriptions""" + return filter(None, [self.repsub_queue(s) for s in self.getAllSubscriptions()]) + + def tx_queues(self): + """Return names of all tx-queues""" + return [q for q in self.queues() if q.startswith("qpid.ha-tx")] + def __getattr__(self, name): a = getattr(self._agent, name) return a @@ -101,6 +119,9 @@ class HaBroker(Broker): """Start a broker with HA enabled @param client_cred: (user, password, mechanism) for admin clients started by the HaBroker. """ + + heartbeat=2 + def __init__(self, test, ha_port=None, args=[], brokers_url=None, ha_cluster=True, ha_replicate="all", client_credentials=None, **kwargs): assert BrokerTest.ha_lib, "Cannot locate HA plug-in" @@ -112,7 +133,7 @@ class HaBroker(Broker): "--link-maintenance-interval=0.1", # Heartbeat and negotiate time are needed so that a broker wont # stall on an address that doesn't currently have a broker running. - "--link-heartbeat-interval=1", + "--link-heartbeat-interval=%s"%(HaBroker.heartbeat), "--max-negotiate-time=1000", "--ha-cluster=%s"%ha_cluster] if ha_replicate is not None: @@ -139,15 +160,18 @@ acl allow all all self.client_credentials = client_credentials self.ha_port = ha_port - def __str__(self): return Broker.__str__(self) + def __repr__(self): return "<HaBroker:%s:%d>"%(self.log, self.port()) def qpid_ha(self, args): - cred = self.client_credentials - url = self.host_port() - if cred: - url =cred.add_user(url) - args = args + ["--sasl-mechanism", cred.mechanism] - self.qpid_ha_script.main_except(["", "-b", url]+args) + try: + cred = self.client_credentials + url = self.host_port() + if cred: + url =cred.add_user(url) + args = args + ["--sasl-mechanism", cred.mechanism] + self.qpid_ha_script.main_except(["", "-b", url]+args) + except Exception, e: + raise Exception("Error in qpid_ha -b %s %s: %s"%(url, args,e)) def promote(self): self.ready(); self.qpid_ha(["promote"]) def set_public_url(self, url): self.qpid_ha(["set", "--public-url", url]) @@ -221,6 +245,12 @@ acl allow all all def wait_backup(self, address): self.wait_address(address) + def browse(self, queue, timeout=0, transform=lambda m: m.content): + c = self.connect_admin() + try: + return browse(c.session(), queue, timeout, transform) + finally: c.close() + def assert_browse(self, queue, expected, **kwargs): """Verify queue contents by browsing.""" bs = self.connect().session() @@ -247,8 +277,10 @@ acl allow all all try: return self.connect() except ConnectionError: return None - def ready(self): - return Broker.ready(self, client_properties={"qpid.ha-admin":1}) + def ready(self, *args, **kwargs): + if not 'client_properties' in kwargs: kwargs['client_properties'] = {} + kwargs['client_properties']['qpid.ha-admin'] = True + return Broker.ready(self, *args, **kwargs) def kill(self, final=True): if final: self.ha_port.stop() @@ -259,16 +291,19 @@ acl allow all all class HaCluster(object): _cluster_count = 0 - def __init__(self, test, n, promote=True, wait=True, args=[], **kwargs): + def __init__(self, test, n, promote=True, wait=True, args=[], s_args=[], **kwargs): """Start a cluster of n brokers. @test: The test being run @n: start n brokers @promote: promote self[0] to primary @wait: wait for primary active and backups ready. Ignored if promote=False + @args: args for all brokers in the cluster. + @s_args: args for specific brokers: s_args[i] for broker i. """ self.test = test - self.args = args + self.args = copy(args) + self.s_args = copy(s_args) self.kwargs = kwargs self._ports = [HaPort(test) for i in xrange(n)] self._set_url() @@ -288,10 +323,13 @@ class HaCluster(object): self.broker_id += 1 return name - def _ha_broker(self, ha_port, name): + def _ha_broker(self, i, name): + args = self.args + if i < len(self.s_args): args += self.s_args[i] + ha_port = self._ports[i] b = HaBroker(ha_port.test, ha_port, brokers_url=self.url, name=name, - args=self.args, **self.kwargs) - b.ready() + args=args, **self.kwargs) + b.ready(timeout=5) return b def start(self): @@ -302,7 +340,7 @@ class HaCluster(object): self._ports.append(HaPort(self.test)) self._set_url() self._update_urls() - b = self._ha_broker(self._ports[i], self.next_name()) + b = self._ha_broker(i, self.next_name()) self._brokers.append(b) return b @@ -328,7 +366,7 @@ class HaCluster(object): a separate log file: foo.n.log""" if self._ports[i].stopped: raise Exception("Restart after final kill: %s"%(self)) b = self._brokers[i] - self._brokers[i] = self._ha_broker(self._ports[i], b.name) + self._brokers[i] = self._ha_broker(i, b.name) self._brokers[i].ready() def bounce(self, i, promote_next=True): diff --git a/qpid/cpp/src/tests/ha_tests.py b/qpid/cpp/src/tests/ha_tests.py index 293712fe80..6941a2b545 100755 --- a/qpid/cpp/src/tests/ha_tests.py +++ b/qpid/cpp/src/tests/ha_tests.py @@ -20,7 +20,7 @@ import os, signal, sys, time, imp, re, subprocess, glob, random, logging, shutil, math, unittest import traceback -from qpid.messaging import Message, SessionError, NotFound, ConnectionError, ReceiverError, Connection, Timeout, Disposition, REJECTED, Empty +from qpid.messaging import Message, SessionError, NotFound, ConnectionError, ReceiverError, Connection, Timeout, Disposition, REJECTED, Empty, ServerError from qpid.datatypes import uuid4, UUID from brokertest import * from ha_test import * @@ -37,6 +37,7 @@ def grep(filename, regexp): class HaBrokerTest(BrokerTest): """Base class for HA broker tests""" + def assert_log_no_errors(self, broker): log = broker.get_log() if grep(log, re.compile("] error|] critical")): @@ -219,7 +220,8 @@ class ReplicationTests(HaBrokerTest): backup.connect_admin().close() # Test discovery: should connect to primary after reject by backup - c = backup.connect(reconnect_urls=[primary.host_port(), backup.host_port()], reconnect=True) + c = backup.connect(reconnect_urls=[primary.host_port(), backup.host_port()], + reconnect=True) s = c.session() sender = s.sender("q;{create:always}") backup.wait_backup("q") @@ -561,9 +563,9 @@ class ReplicationTests(HaBrokerTest): return acl=os.path.join(os.getcwd(), "policy.acl") aclf=file(acl,"w") - # Verify that replication works with auth=yes and HA user has at least the following - # privileges: + # Minimum set of privileges required for the HA user. aclf.write(""" +# HA user acl allow zag@QPID access queue acl allow zag@QPID create queue acl allow zag@QPID consume queue @@ -575,6 +577,9 @@ acl allow zag@QPID publish exchange acl allow zag@QPID delete exchange acl allow zag@QPID access method acl allow zag@QPID create link +# Normal user +acl allow zig@QPID all all + acl deny all all """) aclf.close() @@ -585,14 +590,16 @@ acl deny all all "--ha-username=zag", "--ha-password=zag", "--ha-mechanism=PLAIN" ], client_credentials=Credentials("zag", "zag", "PLAIN")) - s0 = cluster[0].connect(username="zag", password="zag").session(); - s0.receiver("q;{create:always}") - s0.receiver("ex;{create:always,node:{type:topic,x-declare:{type:'fanout'},x-bindings:[{exchange:'ex',queue:'q'}]}}") - cluster[1].wait_backup("q") - cluster[1].wait_backup("ex") - s1 = cluster[1].connect_admin().session(); # Uses Credentials above. - s1.sender("ex").send("foo"); - self.assertEqual(s1.receiver("q").fetch().content, "foo") + c = cluster[0].connect(username="zig", password="zig") + s0 = c.session(); + s0.sender("q;{create:always}") + s0.sender("ex;{create:always,node:{type:topic,x-declare:{type:'fanout'},x-bindings:[{exchange:'ex',queue:'q'}]}}") + s0.sender("ex").send("foo"); + s1 = c.session(transactional=True) + s1.sender("ex").send("foo-tx"); + cluster[1].assert_browse_backup("q", ["foo"]) + s1.commit() + cluster[1].assert_browse_backup("q", ["foo", "foo-tx"]) def test_alternate_exchange(self): """Verify that alternate-exchange on exchanges and queues is propagated @@ -927,20 +934,22 @@ class LongTests(HaBrokerTest): if d: return float(d)*60 else: return 3 # Default is to be quick - # FIXME aconway 2013-06-27: skip this test pending a fix for - # https://issues.apache.org/jira/browse/QPID-4944 - def skip_test_failover_send_receive(self): + def test_failover_send_receive(self): """Test failover with continuous send-receive""" brokers = HaCluster(self, 3) # Start sender and receiver threads n = 10 - senders = [NumberedSender(brokers[0], url=brokers.url, - max_depth=1024, failover_updates=False, - queue="test%s"%(i)) for i in xrange(n)] - receivers = [NumberedReceiver(brokers[0], url=brokers.url, sender=senders[i], - failover_updates=False, - queue="test%s"%(i)) for i in xrange(n)] + senders = [ + NumberedSender( + brokers[0], url=brokers.url,max_depth=50, failover_updates=False, + queue="test%s"%(i), args=["--capacity=10"]) for i in xrange(n)] + + receivers = [ + NumberedReceiver( + brokers[0], url=brokers.url, sender=senders[i],failover_updates=False, + queue="test%s"%(i), args=["--capacity=10"]) for i in xrange(n)] + for r in receivers: r.start() for s in senders: s.start() @@ -991,7 +1000,7 @@ class LongTests(HaBrokerTest): finally: for s in senders: s.stop() for r in receivers: r.stop() - dead = filter(lambda i: not brokers[i].is_running(), xrange(3)) + dead = filter(lambda b: not b.is_running(), brokers) if dead: raise Exception("Brokers not running: %s"%dead) def test_qmf_order(self): @@ -1200,7 +1209,7 @@ class ConfigurationTests(HaBrokerTest): cluster[0].set_brokers_url(cluster.url+",xxx:1234") self.assertRaises(Empty, r.fetch, 0) # Not updated for brokers URL -class StoreTests(BrokerTest): +class StoreTests(HaBrokerTest): """Test for HA with persistence.""" def check_skip(self): @@ -1248,7 +1257,7 @@ class StoreTests(BrokerTest): doing catch-up from the primary.""" if self.check_skip(): return cluster = HaCluster(self, 2) - sn = cluster[0].connect(heartbeat=1).session() + sn = cluster[0].connect(heartbeat=HaBroker.heartbeat).session() s1 = sn.sender("q1;{create:always,node:{durable:true}}") for m in ["foo","bar"]: s1.send(Message(m, durable=True)) s2 = sn.sender("q2;{create:always,node:{durable:true}}") @@ -1259,7 +1268,7 @@ class StoreTests(BrokerTest): cluster[1].assert_browse_backup("q2", ["hello"]) # Make changes that the backup doesn't see cluster.kill(1, promote_next=False, final=False) - r1 = cluster[0].connect(heartbeat=1).session().receiver("q1") + r1 = cluster[0].connect(heartbeat=HaBroker.heartbeat).session().receiver("q1") for m in ["foo", "bar"]: self.assertEqual(r1.fetch().content, m) r1.session.acknowledge() for m in ["x","y","z"]: s1.send(Message(m, durable=True)) @@ -1278,7 +1287,7 @@ class StoreTests(BrokerTest): cluster[0].assert_browse("q1", ["x","y","z"]) cluster[1].assert_browse_backup("q1", ["x","y","z"]) - sn = cluster[0].connect(heartbeat=1).session() # FIXME aconway 2012-09-25: should fail over! + sn = cluster[0].connect(heartbeat=HaBroker.heartbeat).session() sn.sender("ex/k1").send("boo") cluster[0].assert_browse_backup("q1", ["x","y","z", "boo"]) cluster[1].assert_browse_backup("q1", ["x","y","z", "boo"]) @@ -1287,6 +1296,185 @@ class StoreTests(BrokerTest): cluster[0].assert_browse("q2", ["hello", "end"]) cluster[1].assert_browse_backup("q2", ["hello", "end"]) +def open_read(name): + try: + f = open(name) + return f.read() + finally: f.close() + +class TransactionTests(HaBrokerTest): + + load_store=["--load-module", BrokerTest.test_store_lib] + + def tx_simple_setup(self, broker): + """Start a transaction, remove messages from queue a, add messages to queue b""" + c = broker.connect() + # Send messages to a, no transaction. + sa = c.session().sender("a;{create:always,node:{durable:true}}") + tx_msgs = ["x","y","z"] + for m in tx_msgs: sa.send(Message(content=m, durable=True)) + + # Receive messages from a, in transaction. + tx = c.session(transactional=True) + txr = tx.receiver("a") + tx_msgs2 = [txr.fetch(1).content for i in xrange(3)] + self.assertEqual(tx_msgs, tx_msgs2) + + # Send messages to b, transactional, mixed with non-transactional. + sb = c.session().sender("b;{create:always,node:{durable:true}}") + txs = tx.sender("b") + msgs = [str(i) for i in xrange(3)] + for tx_m,m in zip(tx_msgs2, msgs): + txs.send(tx_m); + sb.send(m) + return tx + + def tx_subscriptions(self, broker): + """Return list of queue names for tx subscriptions""" + return [q for q in broker.agent().repsub_queues() + if q.startswith("qpid.ha-tx")] + + def test_tx_simple_commit(self): + cluster = HaCluster(self, 2, test_store=True) + tx = self.tx_simple_setup(cluster[0]) + tx.sync() + tx_queues = cluster[0].agent().tx_queues() + + # NOTE: backup does not process transactional dequeues until prepare + cluster[1].assert_browse_backup("a", ["x","y","z"]) + cluster[1].assert_browse_backup("b", ['0', '1', '2']) + + tx.acknowledge() + tx.commit() + tx.sync() + + for b in cluster: self.assert_simple_commit_outcome(b, tx_queues) + + def assert_tx_cleanup(self, b, tx_queues): + """Verify that there are no transaction artifacts + (exchanges, queues, subscriptions) on b.""" + + self.assertEqual(0, len(b.agent().tx_queues()), msg=b) + self.assertEqual(0, len(self.tx_subscriptions(b)), msg=b) + + # TX exchanges don't show up in management so test for existence by name. + s = b.connect_admin().session() + try: + for q in tx_queues: + try: + s.sender("%s;{node:{type:topic}}"%q) + self.fail("Found tx exchange %s on %s "%(q,b)) + except NotFound: pass + finally: s.connection.close() + + def assert_simple_commit_outcome(self, b, tx_queues): + b.assert_browse_backup("a", [], msg=b) + b.assert_browse_backup("b", ['0', '1', '2', 'x', 'y', 'z'], msg=b) + # Check for expected actions on the store + expect = """<enqueue a x> +<enqueue a y> +<enqueue a z> +<begin tx 1> +<dequeue a x tx=1> +<dequeue a y tx=1> +<dequeue a z tx=1> +<commit tx=1> +""" + self.assertEqual(expect, open_read(b.store_log), msg=b) + self.assert_tx_cleanup(b, tx_queues) + + def test_tx_simple_rollback(self): + cluster = HaCluster(self, 2, test_store=True) + tx = self.tx_simple_setup(cluster[0]) + tx.sync() + tx_queues = cluster[0].agent().tx_queues() + tx.acknowledge() + tx.rollback() + for b in cluster: self.assert_simple_rollback_outcome(b, tx_queues) + + def assert_simple_rollback_outcome(self, b, tx_queues): + b.assert_browse_backup("a", ["x","y","z"], msg=b) + b.assert_browse_backup("b", ['0', '1', '2'], msg=b) + # Check for expected actions on the store + expect = """<enqueue a x> +<enqueue a y> +<enqueue a z> +""" + self.assertEqual(open_read(b.store_log), expect, msg=b) + self.assert_tx_cleanup(b, tx_queues) + + def test_tx_simple_failover(self): + cluster = HaCluster(self, 3, test_store=True) + tx = self.tx_simple_setup(cluster[0]) + tx.sync() + tx_queues = cluster[0].agent().tx_queues() + tx.acknowledge() + cluster.bounce(0) # Should cause roll-back + cluster[0].wait_status("ready") # Restarted. + cluster[1].wait_status("active") # Promoted. + cluster[2].wait_status("ready") # Failed over. + for b in cluster: self.assert_simple_rollback_outcome(b, tx_queues) + + def test_tx_no_backups(self): + """Test the special case of a TX where there are no backups""" + + # Test commit + cluster = HaCluster(self, 1, test_store=True) + tx = self.tx_simple_setup(cluster[0]) + tx.acknowledge() + tx.commit() + tx.sync() + tx_queues = cluster[0].agent().tx_queues() + self.assert_simple_commit_outcome(cluster[0], tx_queues) + + # Test rollback + cluster = HaCluster(self, 1, test_store=True) + tx = self.tx_simple_setup(cluster[0]) + tx.sync() + tx_queues = cluster[0].agent().tx_queues() + tx.acknowledge() + tx.rollback() + tx.sync() + self.assert_simple_rollback_outcome(cluster[0], tx_queues) + + + def test_tx_backup_fail(self): + cluster = HaCluster( + self, 2, test_store=True, s_args=[[],["--test-store-throw=bang"]]) + c = cluster[0].connect() + tx = c.session(transactional=True) + s = tx.sender("q;{create:always,node:{durable:true}}") + for m in ["foo","bang","bar"]: s.send(Message(m, durable=True)) + self.assertRaises(ServerError, tx.commit) + for b in cluster: b.assert_browse_backup("q", []) + self.assertEqual(open_read(cluster[0].store_log), "<begin tx 1>\n<abort tx=1>\n") + self.assertEqual(open_read(cluster[1].store_log), "<begin tx 1>\n<enqueue q foo tx=1>\n<enqueue q bang tx=1>\n<abort tx=1>\n") + + def test_tx_join_leave(self): + """Test cluster members joining/leaving cluster. + Also check that tx-queues are cleaned up at end of transaction.""" + + cluster = HaCluster(self, 3) + + # Leaving + tx = cluster[0].connect().session(transactional=True) + s = tx.sender("q;{create:always}") + s.send("a", sync=True) + self.assertEqual([1,1,1], [len(b.agent().tx_queues()) for b in cluster]) + cluster[1].kill(final=False) + s.send("b") + self.assertRaises(ServerError, tx.commit) + self.assertEqual([[],[]], [b.agent().tx_queues() for b in [cluster[0],cluster[2]]]) + + # Joining + tx = cluster[0].connect().session(transactional=True) + s = tx.sender("q;{create:always}") + s.send("foo") + cluster.restart(1) + tx.commit() + # The new member is not in the tx but receives the results normal replication. + for b in cluster: b.assert_browse_backup("q", ["foo"], msg=b) + if __name__ == "__main__": outdir = "ha_tests.tmp" shutil.rmtree(outdir, True) diff --git a/qpid/cpp/src/tests/interlink_tests.py b/qpid/cpp/src/tests/interlink_tests.py index 129283ac24..608d4ac890 100755 --- a/qpid/cpp/src/tests/interlink_tests.py +++ b/qpid/cpp/src/tests/interlink_tests.py @@ -22,6 +22,7 @@ import os, signal, sys, time, imp, re, subprocess, glob, random, logging, shutil import traceback from qpid.messaging import Message, SessionError, NotFound, ConnectionError, ReceiverError, Connection, Timeout, Disposition, REJECTED, Empty from brokertest import * +from ha_test import HaPort from threading import Thread, Lock, Condition from logging import getLogger, WARN, ERROR, DEBUG, INFO from qpidtoollibs import BrokerAgent, BrokerObject @@ -46,7 +47,8 @@ class AmqpBrokerTest(BrokerTest): def setUp(self): BrokerTest.setUp(self) os.putenv("QPID_LOAD_MODULE", BrokerTest.amqpc_lib) - self.broker = self.amqp_broker() + self.port_holder = HaPort(self) + self.broker = self.amqp_broker(port_holder=self.port_holder) self.default_config = Config(self.broker) self.agent = BrokerAgent(self.broker.connect()) @@ -126,6 +128,9 @@ class AmqpBrokerTest(BrokerTest): def test_translate2(self): self.send_and_receive(send_config=Config(self.broker, version="amqp0-10")) + def test_translate_with_large_routingkey(self): + self.send_and_receive(send_config=Config(self.broker, address="amq.topic/a.%s" % ("x" * 256), version="amqp1.0"), recv_config=Config(self.broker, address="amq.topic/a.*", version="amqp0-10"), wait_for_receiver=True) + def send_and_receive_empty(self, send_config=None, recv_config=None): sconfig = send_config or self.default_config rconfig = recv_config or self.default_config @@ -218,16 +223,22 @@ class AmqpBrokerTest(BrokerTest): assert len(domains) == 1 assert domains[0].name == "BrokerB" - def test_incoming_link(self): + def incoming_link(self, mechanism): brokerB = self.amqp_broker() agentB = BrokerAgent(brokerB.connect()) self.agent.create("queue", "q") agentB.create("queue", "q") - self.agent.create("domain", "BrokerB", {"url":brokerB.host_port(), "sasl_mechanisms":"NONE"}) + self.agent.create("domain", "BrokerB", {"url":brokerB.host_port(), "sasl_mechanisms":mechanism}) self.agent.create("incoming", "Link1", {"domain":"BrokerB","source":"q","target":"q"}) #send to brokerB, receive from brokerA self.send_and_receive(send_config=Config(brokerB)) + def test_incoming_link_anonymous(self): + self.incoming_link("ANONYMOUS") + + def test_incoming_link_nosasl(self): + self.incoming_link("NONE") + def test_outgoing_link(self): brokerB = self.amqp_broker() agentB = BrokerAgent(brokerB.connect()) @@ -246,14 +257,73 @@ class AmqpBrokerTest(BrokerTest): #send to q on broker B through brokerA self.send_and_receive(send_config=Config(self.broker, address="q@BrokerB"), recv_config=Config(brokerB)) + def test_reconnect(self): + receiver_cmd = ["qpid-receive", + "--broker", self.broker.host_port(), + "--address=amq.fanout", + "--connection-options={protocol:amqp1.0, reconnect:True,container_id:receiver}", + "--timeout=10", "--print-content=true", "--print-headers=false" + ] + receiver = self.popen(receiver_cmd, stdout=PIPE) + + sender_cmd = ["qpid-send", + "--broker", self.broker.host_port(), + "--address=amq.fanout", + "--connection-options={protocol:amqp1.0,reconnect:True,container_id:sender}", + "--content-stdin", "--send-eos=1" + ] + sender = self.popen(sender_cmd, stdin=PIPE) + sender._set_cloexec_flag(sender.stdin) #required for older python, see http://bugs.python.org/issue4112 + + + batch1 = ["message-%s" % (i+1) for i in range(10000)] + for m in batch1: + sender.stdin.write(m + "\n") + sender.stdin.flush() + + self.broker.kill() + self.broker = self.amqp_broker(port_holder=self.port_holder) + + batch2 = ["message-%s" % (i+1) for i in range(10000, 20000)] + for m in batch2: + sender.stdin.write(m + "\n") + sender.stdin.flush() + + sender.stdin.close() + + last = None + m = receiver.stdout.readline().rstrip() + while len(m): + last = m + m = receiver.stdout.readline().rstrip() + assert last == "message-20000", (last) + """ Create and return a broker with AMQP 1.0 support """ def amqp_broker(self): assert BrokerTest.amqp_lib, "Cannot locate AMQP 1.0 plug-in" + self.port_holder = HaPort(self) #reserve port args = ["--load-module", BrokerTest.amqp_lib, - "--max-negotiate-time=600000", + "--socket-fd=%s" % self.port_holder.fileno, + "--listen-disable=tcp", "--log-enable=trace+:Protocol", "--log-enable=info+"] - return BrokerTest.broker(self, args) + return BrokerTest.broker(self, args, port=self.port_holder.port) + + def amqp_broker(self, port_holder=None): + assert BrokerTest.amqp_lib, "Cannot locate AMQP 1.0 plug-in" + if port_holder: + args = ["--load-module", BrokerTest.amqp_lib, + "--socket-fd=%s" % port_holder.fileno, + "--listen-disable=tcp", + "--log-enable=trace+:Protocol", + "--log-enable=info+"] + return BrokerTest.broker(self, args, port=port_holder.port) + else: + args = ["--load-module", BrokerTest.amqp_lib, + "--log-enable=trace+:Protocol", + "--log-enable=info+"] + return BrokerTest.broker(self, args) + if __name__ == "__main__": shutil.rmtree("brokertest.tmp", True) diff --git a/qpid/cpp/src/tests/qpid-cluster-lag.py b/qpid/cpp/src/tests/qpid-cluster-lag.py deleted file mode 100755 index 5b24353241..0000000000 --- a/qpid/cpp/src/tests/qpid-cluster-lag.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python - -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -"""%prog [options] broker... -Check for brokers that lag behind other brokers in a cluster.""" - -import os, os.path, sys, socket, time, re -from qpid.messaging import * -from optparse import OptionParser -from threading import Thread - -class Browser(Thread): - def __init__(self, broker, queue, timeout): - Thread.__init__(self) - self.broker = broker - self.queue = queue - self.timeout = timeout - self.error = None - self.time = None - - def run(self): - try: - self.connection = Connection(self.broker) - self.connection.open() - self.session = self.connection.session() - self.receiver = self.session.receiver("%s;{mode:browse}"%self.queue) - self.msg = self.receiver.fetch(timeout=self.timeout) - self.time = time.time() - if (self.msg.content != self.queue): - raise Exception("Wrong message content, expected '%s' found '%s'"% - (self.queue, self.msg.content)) - except Empty: - self.error = "No message on queue %s"%self.queue - except Exception, e: - self.error = "Error: %s"%e - -def main(argv): - op = OptionParser(usage=__doc__) - op.add_option("--timeout", type="float", default=None, metavar="TIMEOUT", - help="Give up after TIMEOUT milliseconds, default never timeout") - (opts, args) = op.parse_args(argv) - if (len(args) <= 1): op.error("No brokers were specified") - brokers = args[1:] - - # Put a message on a uniquely named queue. - queue = "%s:%s:%s"%(os.path.basename(args[0]), socket.gethostname(), os.getpid()) - connection = Connection(brokers[0]) - connection.open() - session = connection.session() - sender = session.sender( - "%s;{create:always,delete:always,node:{durable:False}}"%queue) - sender.send(Message(content=queue)) - start = time.time() - # Browse for the message on each broker - if opts.timeout: opts.timeout - threads = [Browser(b, queue, opts.timeout) for b in brokers] - for t in threads: t.start() - delays=[] - - for t in threads: - t.join() - if t.error: - delay=t.error - else: - delay = t.time-start - delays.append([delay, t.broker]) - print "%s: %s"%(t.broker,delay) - if delays: - delays.sort() - print "lag: %s (%s-%s)"%(delays[-1][0] - delays[0][0], delays[-1][1], delays[0][1]) - # Clean up - sender.close() - session.close() - connection.close() - -if __name__ == "__main__": sys.exit(main(sys.argv)) diff --git a/qpid/cpp/src/tests/qpid-receive.cpp b/qpid/cpp/src/tests/qpid-receive.cpp index 510e9be42c..ab26d3d9b5 100644 --- a/qpid/cpp/src/tests/qpid-receive.cpp +++ b/qpid/cpp/src/tests/qpid-receive.cpp @@ -69,11 +69,12 @@ struct Options : public qpid::Options string readyAddress; uint receiveRate; std::string replyto; + bool noReplies; Options(const std::string& argv0=std::string()) : qpid::Options("Options"), help(false), - url("amqp:tcp:127.0.0.1"), + url("127.0.0.1"), timeout(0), forever(false), messages(0), @@ -91,7 +92,8 @@ struct Options : public qpid::Options reportTotal(false), reportEvery(0), reportHeader(true), - receiveRate(0) + receiveRate(0), + noReplies(false) { addOptions() ("broker,b", qpid::optValue(url, "URL"), "url of broker to connect to") @@ -116,6 +118,7 @@ struct Options : public qpid::Options ("ready-address", qpid::optValue(readyAddress, "ADDRESS"), "send a message to this address when ready to receive") ("receive-rate", qpid::optValue(receiveRate,"N"), "Receive at rate of N messages/second. 0 means receive as fast as possible.") ("reply-to", qpid::optValue(replyto, "REPLY-TO"), "specify reply-to address on response messages") + ("ignore-reply-to", qpid::optValue(noReplies), "Do not send replies even if reply-to is set") ("help", qpid::optValue(help), "print this usage statement"); add(log); } @@ -222,6 +225,7 @@ int main(int argc, char ** argv) if (opts.printHeaders) { if (msg.getSubject().size()) std::cout << "Subject: " << msg.getSubject() << std::endl; if (msg.getReplyTo()) std::cout << "ReplyTo: " << msg.getReplyTo() << std::endl; + if (msg.getMessageId().size()) std::cout << "MessageId: " << msg.getMessageId() << std::endl; if (msg.getCorrelationId().size()) std::cout << "CorrelationId: " << msg.getCorrelationId() << std::endl; if (msg.getUserId().size()) std::cout << "UserId: " << msg.getUserId() << std::endl; if (msg.getTtl().getMilliseconds()) std::cout << "TTL: " << msg.getTtl().getMilliseconds() << std::endl; @@ -231,8 +235,10 @@ int main(int argc, char ** argv) std::cout << "Properties: " << msg.getProperties() << std::endl; std::cout << std::endl; } - if (opts.printContent) - std::cout << msg.getContent() << std::endl;//TODO: handle map or list messages + if (opts.printContent) { + if (!msg.getContentObject().isVoid()) std::cout << msg.getContentObject() << std::endl; + else std::cout << msg.getContent() << std::endl; + } if (opts.messages && count >= opts.messages) done = true; } } @@ -245,7 +251,7 @@ int main(int argc, char ** argv) } else if (opts.ackFrequency && (count % opts.ackFrequency == 0)) { session.acknowledge(); } - if (msg.getReplyTo()) { // Echo message back to reply-to address. + if (msg.getReplyTo() && !opts.noReplies) { // Echo message back to reply-to address. Sender& s = replyTo[msg.getReplyTo().str()]; if (s.isNull()) { s = session.createSender(msg.getReplyTo()); @@ -260,8 +266,6 @@ int main(int argc, char ** argv) int64_t delay = qpid::sys::Duration(qpid::sys::now(), waitTill); if (delay > 0) qpid::sys::usleep(delay/qpid::sys::TIME_USEC); } - // Clear out message properties & content for next iteration. - msg = Message(); // TODO aconway 2010-12-01: should be done by fetch } if (opts.reportTotal) reporter.report(); if (opts.tx) { diff --git a/qpid/cpp/src/tests/qpid-send.cpp b/qpid/cpp/src/tests/qpid-send.cpp index c3bba31e3b..f912b84e8e 100644 --- a/qpid/cpp/src/tests/qpid-send.cpp +++ b/qpid/cpp/src/tests/qpid-send.cpp @@ -96,7 +96,7 @@ struct Options : public qpid::Options Options(const std::string& argv0=std::string()) : qpid::Options("Options"), help(false), - url("amqp:tcp:127.0.0.1"), + url("127.0.0.1"), messages(1), sendEos(0), durable(false), @@ -262,9 +262,8 @@ class MapContentGenerator : public ContentGenerator { public: MapContentGenerator(const Options& opt) : opts(opt) {} virtual bool setContent(Message& msg) { - Variant::Map map; - opts.setEntries(map); - encode(map, msg); + msg.getContentObject() = qpid::types::Variant::Map(); + opts.setEntries(msg.getContentObject().asMap()); return true; } private: @@ -371,6 +370,7 @@ int main(int argc, char ** argv) msg.setReplyTo(Address(opts.replyto)); } if (!opts.userid.empty()) msg.setUserId(opts.userid); + if (!opts.id.empty()) msg.setMessageId(opts.id); if (!opts.correlationid.empty()) msg.setCorrelationId(opts.correlationid); opts.setProperties(msg); uint sent = 0; diff --git a/qpid/cpp/src/tests/qpidd_qmfv2_tests.py b/qpid/cpp/src/tests/qpidd_qmfv2_tests.py index 36fbe4b438..55497ccc03 100755 --- a/qpid/cpp/src/tests/qpidd_qmfv2_tests.py +++ b/qpid/cpp/src/tests/qpidd_qmfv2_tests.py @@ -39,20 +39,25 @@ class ConsoleTest(BrokerTest): def setUp(self): BrokerTest.setUp(self) - args = ["--mgmt-qmf1=no", - "--mgmt-pub-interval=%d" % self.PUB_INTERVAL] + + def _startBroker(self, QMFv1=False ): + self._broker_is_v1 = QMFv1 + if self._broker_is_v1: + args = ["--mgmt-qmf1=yes", "--mgmt-qmf2=no"] + else: + args = ["--mgmt-qmf1=no", "--mgmt-qmf2=yes"] + + args.append("--mgmt-pub-interval=%d" % self.PUB_INTERVAL) self.broker = BrokerTest.broker(self, args) - def _startQmfV2(self, broker, console=None): + + def _myStartQmf(self, broker, console=None): # I manually set up the QMF session here rather than call the startQmf # method from BrokerTest as I can guarantee the console library is used # (assuming BrokerTest's implementation of startQmf could change) self.qmf_session = qmf.console.Session(console) self.qmf_broker = self.qmf_session.addBroker("%s:%s" % (broker.host(), broker.port())) - self.assertEqual(self.qmf_broker.getBrokerAgent().isV2, True, - "Expected broker agent to support QMF V2") - def _create_queue( self, q_name, args={} ): broker = self.qmf_session.getObjects(_class="broker")[0] @@ -60,11 +65,11 @@ class ConsoleTest(BrokerTest): self.assertEqual(result.status, 0, result) - def test_method_call(self): + def _test_method_call(self): """ Verify method calls work, and check the behavior of getObjects() call """ - self._startQmfV2( self.broker ) + self._myStartQmf( self.broker ) self._create_queue( "fleabag", {"auto-delete":True} ) qObj = None @@ -76,12 +81,16 @@ class ConsoleTest(BrokerTest): self.assertNotEqual(qObj, None, "Failed to get queue object") #print qObj - def test_unsolicited_updates(self): + def _test_unsolicited_updates(self): """ Verify that the Console callbacks work """ class Handler(qmf.console.Console): def __init__(self): + self.v1_oids = 0 + self.v1_events = 0 + self.v2_oids = 0 + self.v2_events = 0 self.broker_info = [] self.broker_conn = [] self.newpackage = [] @@ -109,28 +118,38 @@ class ConsoleTest(BrokerTest): def event(self, broker, event): #print "EVENT %s" % event self.events.append(event) - def objectProps(self, broker, record): - #print "ObjProps %s" % record - assert len(record.getProperties()), "objectProps() invoked with no properties?" + if event.isV2: + self.v2_events += 1 + else: + self.v1_events += 1 + + def heartbeat(self, agent, timestamp): + #print "Heartbeat %s" % agent + self.heartbeats.append( (agent, timestamp) ) + + # generic handler for objectProps and objectStats + def _handle_obj_update(self, record): oid = record.getObjectId() + if oid.isV2: + self.v2_oids += 1 + else: + self.v1_oids += 1 + if oid not in self.updates: self.updates[oid] = record else: self.updates[oid].mergeUpdate( record ) + + def objectProps(self, broker, record): + assert len(record.getProperties()), "objectProps() invoked with no properties?" + self._handle_obj_update(record) + def objectStats(self, broker, record): - #print "ObjStats %s" % record assert len(record.getStatistics()), "objectStats() invoked with no properties?" - oid = record.getObjectId() - if oid not in self.updates: - self.updates[oid] = record - else: - self.updates[oid].mergeUpdate( record ) - def heartbeat(self, agent, timestamp): - #print "Heartbeat %s" % agent - self.heartbeats.append( (agent, timestamp) ) + self._handle_obj_update(record) handler = Handler() - self._startQmfV2( self.broker, handler ) + self._myStartQmf( self.broker, handler ) # this should force objectProps, queueDeclare Event callbacks self._create_queue( "fleabag", {"auto-delete":True} ) # this should force objectStats callback @@ -163,7 +182,15 @@ class ConsoleTest(BrokerTest): break assert msgs == 3, "msgDepth statistics not accurate!" - def test_async_method(self): + # verify that the published objects were of the correct QMF version + if self._broker_is_v1: + assert handler.v1_oids and handler.v2_oids == 0, "QMFv2 updates received while in V1-only mode!" + assert handler.v1_events and handler.v2_events == 0, "QMFv2 events received while in V1-only mode!" + else: + assert handler.v2_oids and handler.v1_oids == 0, "QMFv1 updates received while in V2-only mode!" + assert handler.v2_events and handler.v1_events == 0, "QMFv1 events received while in V2-only mode!" + + def _test_async_method(self): class Handler (qmf.console.Console): def __init__(self): self.cv = Condition() @@ -207,12 +234,40 @@ class ConsoleTest(BrokerTest): return "fail (lost=%d, mismatch=%d, spurious=%d)" % (lost, mismatched, spurious) handler = Handler() - self._startQmfV2(self.broker, handler) + self._myStartQmf(self.broker, handler) broker = self.qmf_session.getObjects(_class="broker")[0] handler.request(broker, 20) sleep(1) self.assertEqual(handler.check(), "pass") + def test_method_call(self): + self._startBroker() + self._test_method_call() + + def test_unsolicited_updates(self): + self._startBroker() + self._test_unsolicited_updates() + + def test_async_method(self): + self._startBroker() + self._test_async_method() + + # For now, include "QMFv1 only" tests. Once QMFv1 is deprecated, these can + # be removed + + def test_method_call_v1(self): + self._startBroker(QMFv1=True) + self._test_method_call() + + def test_unsolicited_updates_v1(self): + self._startBroker(QMFv1=True) + self._test_unsolicited_updates() + + def test_async_method_v1(self): + self._startBroker(QMFv1=True) + self._test_async_method() + + if __name__ == "__main__": shutil.rmtree("brokertest.tmp", True) diff --git a/qpid/cpp/src/tests/qpidt b/qpid/cpp/src/tests/qpidt index 5bdfb6eefd..92df9efc8d 100755 --- a/qpid/cpp/src/tests/qpidt +++ b/qpid/cpp/src/tests/qpidt @@ -117,7 +117,7 @@ class Manager: if k == "name": name = v elif v: - if isinstance(v, dict) and v["_object_name"]: + if isinstance(v, dict) and "_object_name" in v: v = v["_object_name"] details += "%s=%s " %(k,v) print "%-25s %s" % (name, details) diff --git a/qpid/cpp/src/tests/queue_flow_limit_tests.py b/qpid/cpp/src/tests/queue_flow_limit_tests.py index c7361a629e..83e31e979b 100644 --- a/qpid/cpp/src/tests/queue_flow_limit_tests.py +++ b/qpid/cpp/src/tests/queue_flow_limit_tests.py @@ -27,6 +27,8 @@ from os import environ, popen class QueueFlowLimitTests(TestBase010): + _timeout = 100 + def __getattr__(self, name): if name == "assertGreater": return lambda a, b: self.failUnless(a > b) @@ -156,7 +158,7 @@ class QueueFlowLimitTests(TestBase010): totalMsgs = 1213 + 797 + 331 # wait until flow control is active - deadline = time() + 10 + deadline = time() + self._timeout while (not self.qmf.getObjects(_objectId=oid)[0].flowStopped) and \ time() < deadline: pass @@ -209,7 +211,7 @@ class QueueFlowLimitTests(TestBase010): totalMsgs = 1699 + 1129 + 881 # wait until flow control is active - deadline = time() + 10 + deadline = time() + self._timeout while (not self.qmf.getObjects(_objectId=oid)[0].flowStopped) and \ time() < deadline: pass @@ -255,7 +257,7 @@ class QueueFlowLimitTests(TestBase010): # fill up the queue, waiting until flow control is active sndr1 = self._start_qpid_send(testq.mgmt.name, count=testq.sendCount, content=testq.content) - deadline = time() + 10 + deadline = time() + self._timeout while (not testq.mgmt.flowStopped) and time() < deadline: testq.mgmt.update() @@ -357,7 +359,7 @@ class QueueFlowLimitTests(TestBase010): sender = BlockedSender(self, "kill-q", count=100) # wait for flow control - deadline = time() + 10 + deadline = time() + self._timeout while (not q.flowStopped) and time() < deadline: q.update() diff --git a/qpid/cpp/src/tests/rsynchosts b/qpid/cpp/src/tests/rsynchosts index 4f19c3b22a..81c9699ac3 100755 --- a/qpid/cpp/src/tests/rsynchosts +++ b/qpid/cpp/src/tests/rsynchosts @@ -27,13 +27,21 @@ abspath() { } usage() { - echo "Usage: $(basename $0) file [file...] + echo "Usage: $(basename $0) [-l user] file [file...] Synchronize the contents of each file or directory to the same absolute path on each host in \$HOSTS. " exit 1 } +while getopts "l:" opt; do + case $opt in + l) RSYNC_USER="$OPTARG@" ;; + *) usage ;; + esac +done +shift `expr $OPTIND - 1` + test "$*" || usage for f in $*; do FILES="$FILES $(abspath $f)" || exit 1; done @@ -42,7 +50,7 @@ OK_FILE=`mktemp` # Will be deleted if anything goes wrong. trap "rm -f $OK_FILE" EXIT for h in $HOSTS; do - rsync -aRO --delete $FILES $h:/ || { echo "rsync to $h failed"; rm -f $OK_FILE; } & + rsync -vaRO --delete $FILES $RSYNC_USER$h:/ || { echo "rsync to $h failed"; rm -f $OK_FILE; } & done wait test -f $OK_FILE diff --git a/qpid/cpp/src/tests/run-unit-tests b/qpid/cpp/src/tests/run-unit-tests deleted file mode 100755 index 5337a3dc22..0000000000 --- a/qpid/cpp/src/tests/run-unit-tests +++ /dev/null @@ -1,48 +0,0 @@ -#!/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. -# - -# -# Library names (without path or .so) and CppUnit test paths can be -# specified on the command line or in env var UNIT_TESTS. For example: -# -# Selected test classes: -# ./run-unit-tests ValueTest ClientChannelTest -# -# Individual test method -# ./run-unit-tests ValueTest :ValueTest::testStringValueEquals -# -# Build and run selected tests: -# make check TESTS=run-unit-tests UNIT_TESTS=ClientChannelTest -# - -for u in $* $UNIT_TESTS ; do - case $u in - :*) TEST_ARGS="$TEST_ARGS $u" ;; # A test path. - *) TEST_ARGS="$TEST_ARGS .libs/$u.so" ;; # A test library. - esac -done -test -z "$TEST_ARGS" && TEST_ARGS=".libs/*Test.so" - -test -z "$srcdir" && srcdir=. - -# libdlclose_noop prevents unloading symbols needed for valgrind output. -export LD_PRELOAD=.libs/libdlclose_noop.so -source $srcdir/run_test DllPlugInTester -c -b $TEST_ARGS diff --git a/qpid/cpp/src/tests/run_cli_tests b/qpid/cpp/src/tests/run_cli_tests index a7f55d58b7..e9590080a1 100755 --- a/qpid/cpp/src/tests/run_cli_tests +++ b/qpid/cpp/src/tests/run_cli_tests @@ -44,8 +44,8 @@ start_brokers() { # look like they're xml related. # if we start supporting xml on windows, it will need something similar # here - if [ -f ../.libs/xml.so ] ; then - xargs="--load-module ../.libs/xml.so" + if [ -f ../xml.so ] ; then + xargs="--load-module ../xml.so" if [ ! -f test.xquery ] ; then create_test_xquery fi diff --git a/qpid/cpp/src/tests/run_federation_tests b/qpid/cpp/src/tests/run_federation_tests index 09219141ef..bf33f96ebd 100755 --- a/qpid/cpp/src/tests/run_federation_tests +++ b/qpid/cpp/src/tests/run_federation_tests @@ -25,7 +25,7 @@ source ./test_env.sh #set -x trap stop_brokers INT TERM QUIT -if [ -f ../.libs/xml.so ] ; then +if [ -f ../xml.so ] ; then MODULES="--load-module xml" # Load the XML exchange and run XML exchange federation tests SKIPTESTS= else diff --git a/qpid/cpp/src/tests/run_msg_group_tests.ps1 b/qpid/cpp/src/tests/run_msg_group_tests.ps1 new file mode 100644 index 0000000000..e9cee0a5a0 --- /dev/null +++ b/qpid/cpp/src/tests/run_msg_group_tests.ps1 @@ -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. +# + +# Simple test of encode/decode of a double in application headers +# TODO: this should be expanded to cover a wider set of types and go +# in both directions + +$srcdir = Split-Path $myInvocation.InvocationName +$PYTHON_DIR = "$srcdir\..\..\..\python" +if (!(Test-Path $PYTHON_DIR -pathType Container)) { + "Skipping msg_group test as python libs not found" + exit 0 +} + +. .\test_env.ps1 + +if (Test-Path qpidd.port) { + set-item -path env:QPID_PORT -value (get-content -path qpidd.port -totalcount 1) +} + +# 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. +. $srcdir\find_prog.ps1 .\msg_group_test.exe +if (!(Test-Path $prog)) { + "Cannot locate msg_group_test.exe" + exit 1 +} + +$QUEUE_NAME="group-queue" +$GROUP_KEY="My-Group-Id" +$BROKER_URL="localhost:$env:QPID_PORT" + +$tests=@("python $QPID_CONFIG_EXEC -b $BROKER_URL add queue $QUEUE_NAME --group-header=${GROUP_KEY} --shared-groups", + "$prog -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 103 --group-size 13 --receivers 2 --senders 3 --capacity 3 --ack-frequency 7 --randomize-group-size --interleave 3", + "$prog -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 103 --group-size 13 --receivers 2 --senders 3 --capacity 7 --ack-frequency 7 --randomize-group-size", + "python $QPID_CONFIG_EXEC -b $BROKER_URL add queue ${QUEUE_NAME}-two --group-header=${GROUP_KEY} --shared-groups", + "$prog -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 103 --group-size 13 --receivers 2 --senders 3 --capacity 7 --ack-frequency 3 --randomize-group-size", + "$prog -b $BROKER_URL -a ${QUEUE_NAME}-two --group-key $GROUP_KEY --messages 103 --group-size 13 --receivers 2 --senders 3 --capacity 3 --ack-frequency 7 --randomize-group-size --interleave 5", + "$prog -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 59 --group-size 5 --receivers 2 --senders 3 --capacity 1 --ack-frequency 3 --randomize-group-size", + "python $QPID_CONFIG_EXEC -b $BROKER_URL del queue ${QUEUE_NAME}-two --force", + "$prog -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 59 --group-size 3 --receivers 2 --senders 3 --capacity 1 --ack-frequency 1 --randomize-group-size", + "$prog -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 211 --group-size 13 --receivers 2 --senders 3 --capacity 47 --ack-frequency 79 --interleave 53", + "$prog -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 10000 --group-size 1 --receivers 0 --senders 1", + "$prog -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 10000 --receivers 5 --senders 0", + "python $QPID_CONFIG_EXEC -b $BROKER_URL del queue $QUEUE_NAME --force") + +foreach ($cmd in $tests) +{ + Invoke-Expression "$cmd" | Write-Output + $ret = $LASTEXITCODE + if ($ret -ne 0) {Write-Host "FAILED message group test. Failed command: $cmd" + break} +} +exit $ret diff --git a/qpid/cpp/src/tests/sasl.mk b/qpid/cpp/src/tests/sasl.mk deleted file mode 100644 index 8c31192635..0000000000 --- a/qpid/cpp/src/tests/sasl.mk +++ /dev/null @@ -1,44 +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. -# - -# Test that are only relevant if SASL is enabled. -if HAVE_SASL - -# Note: sasl_version is not a test -- it is a tool used by tests. -check_PROGRAMS+=sasl_version -sasl_version_SOURCES=sasl_version.cpp -sasl_version_LDADD=$(lib_client) - -TESTS += sasl_fed - sasl_fed_ex_dynamic - sasl_fed_ex_link - sasl_fed_ex_queue - sasl_fed_ex_route - sasl_no_dir - -EXTRA_DIST += sasl_fed \ - sasl_fed_ex \ - sasl_fed_ex_dynamic \ - sasl_fed_ex_link \ - sasl_fed_ex_queue \ - sasl_fed_ex_route \ - sasl_no_dir - - -endif # HAVE_SASL diff --git a/qpid/cpp/src/tests/ssl.mk b/qpid/cpp/src/tests/ssl.mk deleted file mode 100644 index 1544dc5e71..0000000000 --- a/qpid/cpp/src/tests/ssl.mk +++ /dev/null @@ -1,22 +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. -# - -TESTS+=ssl_test -EXTRA_DIST+=ssl_test -CLEAN_LOCAL += test_cert_dir cert.password diff --git a/qpid/cpp/src/tests/swig_python_tests b/qpid/cpp/src/tests/swig_python_tests new file mode 100755 index 0000000000..6f862ffa2d --- /dev/null +++ b/qpid/cpp/src/tests/swig_python_tests @@ -0,0 +1,62 @@ +#!/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 python tests. +source ./test_env.sh +trap stop_broker INT TERM QUIT + +if [[ -a $AMQP_LIB ]] ; then + echo "Found AMQP support: $AMQP_LIB" + MODULES="--load-module $AMQP_LIB" +fi + +fail() { + echo "FAIL swigged python tests: $1"; exit 1; +} +skip() { + echo "SKIPPED swigged python tests: $1"; exit 0; +} + +start_broker() { + QPID_PORT=$($QPIDD_EXEC --daemon --port 0 --interface 127.0.0.1 --no-data-dir $MODULES --auth no) || fail "Could not start broker" +} + +stop_broker() { + $QPIDD_EXEC -q --port $QPID_PORT +} + +test -d $PYTHON_DIR || skip "no python dir" +test -f $PYTHONSWIGMODULE || skip "no swigged python client" + +start_broker +echo "Running swigged python tests using broker on port $QPID_PORT" + +export PYTHONPATH=$PYTHONPATH:$PYTHONPATH_SWIG +$QPID_PYTHON_TEST -m qpid.tests.messaging.message -m qpid_tests.broker_0_10.priority -m qpid_tests.broker_0_10.lvq -m qpid_tests.broker_0_10.new_api -b localhost:$QPID_PORT -I $srcdir/failing-amqp0-10-python-tests || FAILED=1 +if [[ -a $AMQPC_LIB ]] ; then + export QPID_LOAD_MODULE=$AMQPC_LIB + $QPID_PYTHON_TEST --define="protocol_version=amqp1.0" -m qpid_tests.broker_1_0 -m qpid_tests.broker_0_10.new_api -b localhost:$QPID_PORT -I $srcdir/failing-amqp1.0-python-tests || FAILED=1 +fi +stop_broker +if [[ $FAILED -eq 1 ]]; then + fail "" +fi + diff --git a/qpid/cpp/src/tests/test_env.ps1.in b/qpid/cpp/src/tests/test_env.ps1.in index 5fa3a0ac31..12373b5b35 100644 --- a/qpid/cpp/src/tests/test_env.ps1.in +++ b/qpid/cpp/src/tests/test_env.ps1.in @@ -41,7 +41,6 @@ $PYTHON_COMMANDS="$QPID_TOOLS\src\py" $env:PYTHONPATH="$srcdir;$PYTHON_DIR;$PYTHON_COMMANDS;$QPID_TESTS_PY;$QPID_TOOLS_LIBS;$QMF_LIB;$env:PYTHONPATH" $QPID_CONFIG_EXEC="$PYTHON_COMMANDS\qpid-config" $QPID_ROUTE_EXEC="$PYTHON_COMMANDS\qpid-route" -$QPID_CLUSTER_EXEC="$PYTHON_COMMANDS\qpid-cluster" $QPID_HA_TOOL_EXEC="$PYTHON_COMMANDS\qpid-ha-tool" # Executables diff --git a/qpid/cpp/src/tests/test_env.sh.in b/qpid/cpp/src/tests/test_env.sh.in index bafdacf944..486034ca3b 100644 --- a/qpid/cpp/src/tests/test_env.sh.in +++ b/qpid/cpp/src/tests/test_env.sh.in @@ -25,6 +25,8 @@ builddir=`absdir @abs_builddir@` top_srcdir=`absdir @abs_top_srcdir@` top_builddir=`absdir @abs_top_builddir@` moduledir=$top_builddir/src@builddir_lib_suffix@ +pythonswigdir=$top_builddir/bindings/qpid/python/ +pythonswiglibdir=$top_builddir/bindings/qpid/python@builddir_lib_suffix@ testmoduledir=$builddir@builddir_lib_suffix@ export QPID_INSTALL_PREFIX=@prefix@ @@ -44,7 +46,8 @@ export PYTHONPATH=$srcdir:$PYTHON_DIR:$PYTHON_COMMANDS:$QPID_TESTS_PY:$QMF_LIB:$ export QPID_CONFIG_EXEC=$PYTHON_COMMANDS/qpid-config export QPID_ROUTE_EXEC=$PYTHON_COMMANDS/qpid-route export QPID_HA_EXEC=$PYTHON_COMMANDS/qpid-ha - +export PYTHONPATH_SWIG=$pythonswigdir:$pythonswiglibdir +export PYTHONSWIGMODULE=$pythonswigdir/qpid_messaging.py # Executables export QPIDD_EXEC=$top_builddir/src/qpidd @@ -78,5 +81,5 @@ if [ ! -e "$HOME" ]; then fi # Options for boost test framework -export BOOST_TEST_SHOW_PROGRESS=yes -export BOOST_TEST_CATCH_SYSTEM_ERRORS=no +test -z "$BOOST_TEST_SHOW_PROGRESS" && export BOOST_TEST_SHOW_PROGRESS=yes +test -z "$BOOST_TEST_CATCH_SYSTEM_ERRORS" && export BOOST_TEST_CATCH_SYSTEM_ERRORS=no diff --git a/qpid/cpp/src/tests/test_store.cpp b/qpid/cpp/src/tests/test_store.cpp index eac4deda2d..e299161c68 100644 --- a/qpid/cpp/src/tests/test_store.cpp +++ b/qpid/cpp/src/tests/test_store.cpp @@ -40,14 +40,19 @@ #include "qpid/sys/Thread.h" #include "qpid/Plugin.h" #include "qpid/Options.h" +#include "qpid/RefCounted.h" +#include "qpid/Msg.h" #include <boost/cast.hpp> #include <boost/lexical_cast.hpp> #include <memory> +#include <ostream> #include <fstream> +#include <sstream> -using namespace qpid; -using namespace broker; using namespace std; +using namespace boost; +using namespace qpid; +using namespace qpid::broker; using namespace qpid::sys; namespace qpid { @@ -57,11 +62,19 @@ struct TestStoreOptions : public Options { string name; string dump; + string events; + vector<string> throwMsg; // Throw exception if message content matches. TestStoreOptions() : Options("Test Store Options") { addOptions() - ("test-store-name", optValue(name, "NAME"), "Name of test store instance.") - ("test-store-dump", optValue(dump, "FILE"), "File to dump enqueued messages.") + ("test-store-name", optValue(name, "NAME"), + "Name of test store instance.") + ("test-store-dump", optValue(dump, "FILE"), + "File to dump enqueued messages.") + ("test-store-events", optValue(events, "FILE"), + "File to log events, 1 line per event.") + ("test-store-throw", optValue(throwMsg, "CONTENT"), + "Throw exception if message content matches.") ; } }; @@ -82,24 +95,76 @@ class TestStore : public NullMessageStore { TestStore(const TestStoreOptions& opts, Broker& broker_) : options(opts), name(opts.name), broker(broker_) { - QPID_LOG(info, "TestStore name=" << name << " dump=" << options.dump); - if (!options.dump.empty()) + QPID_LOG(info, "TestStore name=" << name + << " dump=" << options.dump + << " events=" << options.events + << " throw messages =" << options.throwMsg.size()); + + if (!options.dump.empty()) dump.reset(new ofstream(options.dump.c_str())); + if (!options.events.empty()) + events.reset(new ofstream(options.events.c_str())); } ~TestStore() { for_each(threads.begin(), threads.end(), boost::bind(&Thread::join, _1)); } - virtual bool isNull() const { return false; } - - void enqueue(TransactionContext* , + // Dummy transaction context. + struct TxContext : public TPCTransactionContext { + static int nextId; + string id; + TxContext() : id(lexical_cast<string>(nextId++)) {} + TxContext(string xid) : id(xid) {} + }; + + static string getId(const TransactionContext& tx) { + const TxContext* tc = dynamic_cast<const TxContext*>(&tx); + assert(tc); + return tc->id; + } + + + bool isNull() const { return false; } + + void log(const string& msg) { + QPID_LOG(info, "test_store: " << msg); + if (events.get()) *events << msg << endl << std::flush; + } + + auto_ptr<TransactionContext> begin() { + auto_ptr<TxContext> tx(new TxContext()); + log(Msg() << "<begin tx " << tx->id << ">"); + return auto_ptr<TransactionContext>(tx); + } + + auto_ptr<TPCTransactionContext> begin(const std::string& xid) { + auto_ptr<TxContext> tx(new TxContext(xid)); + log(Msg() << "<begin tx " << tx->id << ">"); + return auto_ptr<TPCTransactionContext>(tx); + } + + string getContent(const intrusive_ptr<PersistableMessage>& msg) { + intrusive_ptr<broker::Message::Encoding> enc( + dynamic_pointer_cast<broker::Message::Encoding>(msg)); + return enc->getContent(); + } + + void enqueue(TransactionContext* tx, const boost::intrusive_ptr<PersistableMessage>& pmsg, - const PersistableQueue& ) + const PersistableQueue& queue) { - qpid::broker::amqp_0_10::MessageTransfer* msg = dynamic_cast<qpid::broker::amqp_0_10::MessageTransfer*>(pmsg.get()); + QPID_LOG(debug, "TestStore enqueue " << queue.getName()); + qpid::broker::amqp_0_10::MessageTransfer* msg = + dynamic_cast<qpid::broker::amqp_0_10::MessageTransfer*>(pmsg.get()); assert(msg); + ostringstream o; + o << "<enqueue " << queue.getName() << " " << getContent(msg); + if (tx) o << " tx=" << getId(*tx); + o << ">"; + log(o.str()); + // Dump the message if there is a dump file. if (dump.get()) { msg->getFrames().getMethod()->print(*dump); @@ -113,7 +178,11 @@ class TestStore : public NullMessageStore { string data = msg->getFrames().getContent(); size_t i = string::npos; size_t j = string::npos; - if (strncmp(data.c_str(), TEST_STORE_DO.c_str(), strlen(TEST_STORE_DO.c_str())) == 0 + const vector<string>& throwMsg(options.throwMsg); + if (find(throwMsg.begin(), throwMsg.end(), data) != throwMsg.end()) { + throw Exception(QPID_MSG("TestStore " << name << " throwing exception for: " << data)); + } + else if (strncmp(data.c_str(), TEST_STORE_DO.c_str(), strlen(TEST_STORE_DO.c_str())) == 0 && (i = data.find(name+"[")) != string::npos && (j = data.find("]", i)) != string::npos) { @@ -144,6 +213,31 @@ class TestStore : public NullMessageStore { msg->enqueueComplete(); } + void dequeue(TransactionContext* tx, + const boost::intrusive_ptr<PersistableMessage>& msg, + const PersistableQueue& queue) + { + QPID_LOG(debug, "TestStore dequeue " << queue.getName()); + ostringstream o; + o<< "<dequeue " << queue.getName() << " " << getContent(msg); + if (tx) o << " tx=" << getId(*tx); + o << ">"; + log(o.str()); + } + + void prepare(TPCTransactionContext& txn) { + log(Msg() << "<prepare tx=" << getId(txn) << ">"); + } + + void commit(TransactionContext& txn) { + log(Msg() << "<commit tx=" << getId(txn) << ">"); + } + + void abort(TransactionContext& txn) { + log(Msg() << "<abort tx=" << getId(txn) << ">"); + } + + private: static const string TEST_STORE_DO, EXCEPTION, EXIT_PROCESS, ASYNC; TestStoreOptions options; @@ -151,8 +245,11 @@ class TestStore : public NullMessageStore { Broker& broker; vector<Thread> threads; std::auto_ptr<ofstream> dump; + std::auto_ptr<ofstream> events; }; +int TestStore::TxContext::nextId(1); + const string TestStore::TEST_STORE_DO = "TEST_STORE_DO: "; const string TestStore::EXCEPTION = "exception"; const string TestStore::EXIT_PROCESS = "exit_process"; diff --git a/qpid/cpp/src/tests/test_tools.h b/qpid/cpp/src/tests/test_tools.h index de672f938a..7950a36913 100644 --- a/qpid/cpp/src/tests/test_tools.h +++ b/qpid/cpp/src/tests/test_tools.h @@ -23,7 +23,6 @@ #include <limits.h> // Include before boost/test headers. #include <boost/test/test_tools.hpp> #include <boost/assign/list_of.hpp> -#include <boost/assign/list_of.hpp> #include <vector> #include <set> #include <ostream> diff --git a/qpid/cpp/src/tests/testagent.cpp b/qpid/cpp/src/tests/testagent.cpp deleted file mode 100644 index e6010a8e00..0000000000 --- a/qpid/cpp/src/tests/testagent.cpp +++ /dev/null @@ -1,208 +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 <qpid/management/Manageable.h> -#include <qpid/management/ManagementObject.h> -#include <qpid/agent/ManagementAgent.h> -#include <qpid/sys/Mutex.h> -#include <qpid/sys/Time.h> -#include "qmf/org/apache/qpid/agent/example/Parent.h" -#include "qmf/org/apache/qpid/agent/example/Child.h" -#include "qmf/org/apache/qpid/agent/example/ArgsParentCreate_child.h" -#include "qmf/org/apache/qpid/agent/example/EventChildCreated.h" -#include "qmf/org/apache/qpid/agent/example/Package.h" - -#include <signal.h> -#include <cstdlib> -#include <iostream> - -#include <sstream> - -namespace qpid { -namespace tests { - -static bool running = true; - -using std::string; -using qpid::management::ManagementAgent; -using qpid::management::ManagementObject; -using qpid::management::Manageable; -using qpid::management::Args; -using qpid::sys::Mutex; -namespace _qmf = qmf::org::apache::qpid::agent::example; - -class ChildClass; - -//============================================================== -// CoreClass is the operational class that corresponds to the -// "Parent" class in the management schema. -//============================================================== -class CoreClass : public Manageable -{ - string name; - ManagementAgent* agent; - _qmf::Parent* mgmtObject; - std::vector<ChildClass*> children; - Mutex vectorLock; - -public: - - CoreClass(ManagementAgent* agent, string _name); - ~CoreClass() { mgmtObject->resourceDestroy(); } - - ManagementObject* GetManagementObject(void) const - { return mgmtObject; } - - void doLoop(); - status_t ManagementMethod (uint32_t methodId, Args& args, string& text); -}; - -class ChildClass : public Manageable -{ - string name; - _qmf::Child* mgmtObject; - -public: - - ChildClass(ManagementAgent* agent, CoreClass* parent, string name); - ~ChildClass() { mgmtObject->resourceDestroy(); } - - ManagementObject* GetManagementObject(void) const - { return mgmtObject; } - - void doWork() - { - mgmtObject->inc_count(2); - } -}; - -CoreClass::CoreClass(ManagementAgent* _agent, string _name) : name(_name), agent(_agent) -{ - static uint64_t persistId = 0x111222333444555LL; - mgmtObject = new _qmf::Parent(agent, this, name); - - agent->addObject(mgmtObject, persistId++); - mgmtObject->set_state("IDLE"); -} - -void CoreClass::doLoop() -{ - // Periodically bump a counter to provide a changing statistical value - while (running) { - qpid::sys::sleep(1); - mgmtObject->inc_count(); - mgmtObject->set_state("IN_LOOP"); - - { - Mutex::ScopedLock _lock(vectorLock); - - for (std::vector<ChildClass*>::iterator iter = children.begin(); - iter != children.end(); - iter++) { - (*iter)->doWork(); - } - } - } -} - -Manageable::status_t CoreClass::ManagementMethod(uint32_t methodId, Args& args, string& /*text*/) -{ - Mutex::ScopedLock _lock(vectorLock); - - switch (methodId) { - case _qmf::Parent::METHOD_CREATE_CHILD: - _qmf::ArgsParentCreate_child& ioArgs = (_qmf::ArgsParentCreate_child&) args; - - ChildClass *child = new ChildClass(agent, this, ioArgs.i_name); - ioArgs.o_childRef = child->GetManagementObject()->getObjectId(); - - children.push_back(child); - - agent->raiseEvent(_qmf::EventChildCreated(ioArgs.i_name)); - - return STATUS_OK; - } - - return STATUS_NOT_IMPLEMENTED; -} - -ChildClass::ChildClass(ManagementAgent* agent, CoreClass* parent, string name) -{ - mgmtObject = new _qmf::Child(agent, this, parent, name); - - agent->addObject(mgmtObject); -} - - -//============================================================== -// Main program -//============================================================== - -ManagementAgent::Singleton* singleton; - -void shutdown(int) -{ - running = false; -} - -int main_int(int argc, char** argv) -{ - singleton = new ManagementAgent::Singleton(); - const char* host = argc>1 ? argv[1] : "127.0.0.1"; - int port = argc>2 ? atoi(argv[2]) : 5672; - - signal(SIGINT, shutdown); - - // Create the qmf management agent - ManagementAgent* agent = singleton->getInstance(); - - // Register the Qmf_example schema with the agent - _qmf::Package packageInit(agent); - - // Start the agent. It will attempt to make a connection to the - // management broker - agent->init(host, port, 5, false, ".magentdata"); - - // Allocate some core objects - CoreClass core1(agent, "Example Core Object #1"); - CoreClass core2(agent, "Example Core Object #2"); - CoreClass core3(agent, "Example Core Object #3"); - - core1.doLoop(); - - // done, cleanup and exit - delete singleton; - - return 0; -} - -}} // namespace qpid::tests - -int main(int argc, char** argv) -{ - try { - return qpid::tests::main_int(argc, argv); - } catch(std::exception& e) { - std::cerr << "Top Level Exception: " << e.what() << std::endl; - return 1; - } -} - diff --git a/qpid/cpp/src/tests/testagent.mk b/qpid/cpp/src/tests/testagent.mk deleted file mode 100644 index 0492f3e3bb..0000000000 --- a/qpid/cpp/src/tests/testagent.mk +++ /dev/null @@ -1,51 +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. -# - -# Build a simple qmf agent for test purposes. - -TESTAGENT_GEN_SRC= \ - testagent_gen/qmf/org/apache/qpid/agent/example/Parent.h \ - testagent_gen/qmf/org/apache/qpid/agent/example/Child.h \ - testagent_gen/qmf/org/apache/qpid/agent/example/Parent.cpp \ - testagent_gen/qmf/org/apache/qpid/agent/example/Child.cpp \ - testagent_gen/qmf/org/apache/qpid/agent/example/ArgsParentCreate_child.h \ - testagent_gen/qmf/org/apache/qpid/agent/example/EventChildCreated.h \ - testagent_gen/qmf/org/apache/qpid/agent/example/EventChildDestroyed.h \ - testagent_gen/qmf/org/apache/qpid/agent/example/EventChildCreated.cpp \ - testagent_gen/qmf/org/apache/qpid/agent/example/EventChildDestroyed.cpp \ - testagent_gen/qmf/org/apache/qpid/agent/example/Package.h \ - testagent_gen/qmf/org/apache/qpid/agent/example/Package.cpp - -$(TESTAGENT_GEN_SRC): testagent_gen.timestamp -if GENERATE -TESTAGENT_DEPS=../mgen.timestamp -endif # GENERATE -testagent_gen.timestamp: testagent.xml ${TESTAGENT_DEPS} - $(QMF_GEN) -o testagent_gen/qmf $(srcdir)/testagent.xml - touch $@ - -CLEANFILES+=$(TESTAGENT_GEN_SRC) testagent_gen.timestamp - -testagent-testagent.$(OBJEXT): $(TESTAGENT_GEN_SRC) -qpidexectest_PROGRAMS+=testagent -testagent_CXXFLAGS=$(CXXFLAGS) -Itestagent_gen -testagent_SOURCES=testagent.cpp $(TESTAGENT_GEN_SRC) -testagent_LDADD=$(top_builddir)/src/libqmf.la $(top_builddir)/src/libqpidcommon.la $(top_builddir)/src/libqpidtypes.la $(top_builddir)/src/libqpidclient.la - -EXTRA_DIST+=testagent.xml diff --git a/qpid/cpp/src/tests/testagent.xml b/qpid/cpp/src/tests/testagent.xml deleted file mode 100644 index 0b1436f999..0000000000 --- a/qpid/cpp/src/tests/testagent.xml +++ /dev/null @@ -1,64 +0,0 @@ -<schema package="org.apache.qpid.agent.example"> - -<!-- - 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. ---> - - <!-- - =============================================================== - Parent - =============================================================== - --> - <class name="Parent"> - - This class represents a parent object - - <property name="name" type="lstr" access="RC" index="y"/> - - <statistic name="state" type="sstr" desc="Operational state of the link"/> - <statistic name="count" type="count64" unit="tick" desc="Counter that increases monotonically"/> - - <method name="create_child" desc="Create child object"> - <arg name="name" dir="I" type="lstr"/> - <arg name="childRef" dir="O" type="objId"/> - </method> - </class> - - - <!-- - =============================================================== - Child - =============================================================== - --> - <class name="Child"> - <property name="ParentRef" type="objId" references="Parent" access="RC" index="y" parentRef="y"/> - <property name="name" type="lstr" access="RC" index="y"/> - - <statistic name="count" type="count64" unit="tick" desc="Counter that increases monotonically"/> - - <method name="delete"/> - </class> - - <eventArguments> - <arg name="childName" type="lstr"/> - </eventArguments> - - <event name="ChildCreated" args="childName"/> - <event name="ChildDestroyed" args="childName"/> -</schema> - diff --git a/qpid/cpp/src/xml.mk b/qpid/cpp/src/xml.mk deleted file mode 100644 index 9376cfd54a..0000000000 --- a/qpid/cpp/src/xml.mk +++ /dev/null @@ -1,29 +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. -# -dmoduleexec_LTLIBRARIES += xml.la - -xml_la_SOURCES = \ - qpid/xml/XmlExchange.cpp \ - qpid/xml/XmlExchange.h \ - qpid/xml/XmlExchangePlugin.cpp - -xml_la_LIBADD = -lxerces-c -lxqilla libqpidbroker.la -xml_la_CXXFLAGS = $(AM_CXXFLAGS) -D_IN_QPID_BROKER -xml_la_LDFLAGS = $(PLUGINLDFLAGS) - |