From f83677056891e436bf5ba99e79240df2a44528cd Mon Sep 17 00:00:00 2001 From: "Stephen D. Huston" Date: Fri, 21 Oct 2011 14:42:12 +0000 Subject: Merged out from trunk git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-2519@1187375 13f79535-47bb-0310-9956-ffa450edef68 --- cpp/CMakeLists.txt | 1 + cpp/INSTALL | 20 +- cpp/INSTALL-WINDOWS | 11 +- cpp/Makefile.am | 4 + cpp/bindings/qmf/python/Makefile.am | 4 +- cpp/bindings/qmf/ruby/Makefile.am | 4 +- cpp/bindings/qmf/tests/test_base.rb | 3 +- cpp/bindings/qmf2/examples/cpp/Makefile.am | 5 +- .../qmf2/examples/cpp/event_driven_list_agents.cpp | 107 ++ cpp/bindings/qmf2/python/Makefile.am | 4 +- cpp/bindings/qmf2/qmf2.i | 1 + cpp/bindings/qmf2/ruby/Makefile.am | 4 +- cpp/bindings/qpid/CMakeLists.txt | 41 + cpp/bindings/qpid/Makefile.am | 2 +- cpp/bindings/qpid/dotnet/configure-windows.ps1 | 108 +- .../Properties/AssemblyInfo.cs | 16 +- .../Properties/AssemblyInfo.cs | 16 +- .../Properties/AssemblyInfo.cs | 12 +- .../Properties/AssemblyInfo.cs | 2 +- .../csharp.map.receiver/Properties/AssemblyInfo.cs | 16 +- .../csharp.map.sender/Properties/AssemblyInfo.cs | 16 +- .../MyProject/AssemblyInfo.vb | 30 +- .../org.apache.qpid.messaging.sessionreceiver.sln | 6 +- cpp/bindings/qpid/dotnet/src/Address.cpp | 24 +- cpp/bindings/qpid/dotnet/src/Address.h | 1 + cpp/bindings/qpid/dotnet/src/Connection.cpp | 24 +- cpp/bindings/qpid/dotnet/src/Connection.h | 1 + cpp/bindings/qpid/dotnet/src/Duration.h | 12 +- cpp/bindings/qpid/dotnet/src/FailoverUpdates.h | 1 + cpp/bindings/qpid/dotnet/src/Message.cpp | 26 +- cpp/bindings/qpid/dotnet/src/Message.h | 1 + cpp/bindings/qpid/dotnet/src/Receiver.cpp | 25 +- cpp/bindings/qpid/dotnet/src/Receiver.h | 1 + cpp/bindings/qpid/dotnet/src/Sender.cpp | 25 +- cpp/bindings/qpid/dotnet/src/Sender.h | 1 + cpp/bindings/qpid/dotnet/src/Session.cpp | 51 +- cpp/bindings/qpid/dotnet/src/Session.h | 3 + .../test/messaging.test/Properties/AssemblyInfo.cs | 16 +- cpp/bindings/qpid/examples/perl/client.pl | 8 +- cpp/bindings/qpid/examples/perl/drain.pl | 12 +- cpp/bindings/qpid/examples/perl/hello_world.pl | 10 +- cpp/bindings/qpid/examples/perl/hello_xml.pl | 6 +- cpp/bindings/qpid/examples/perl/map_receiver.pl | 8 +- cpp/bindings/qpid/examples/perl/map_sender.pl | 8 +- cpp/bindings/qpid/examples/perl/server.pl | 6 +- cpp/bindings/qpid/examples/perl/spout.pl | 10 +- cpp/bindings/qpid/perl/CMakeLists.txt | 38 + cpp/bindings/qpid/perl/Makefile.am | 22 +- cpp/bindings/qpid/perl/perl.i | 2 +- cpp/bindings/qpid/python/CMakeLists.txt | 45 + cpp/bindings/qpid/python/Makefile.am | 6 +- cpp/bindings/qpid/python/python.i | 338 +++- cpp/bindings/qpid/qpid.i | 3 + cpp/bindings/qpid/ruby/.gitignore | 2 + cpp/bindings/qpid/ruby/CMakeLists.txt | 63 + cpp/bindings/qpid/ruby/LICENSE | 234 +++ cpp/bindings/qpid/ruby/Makefile.am | 6 +- cpp/bindings/qpid/ruby/README.rdoc | 45 + cpp/bindings/qpid/ruby/Rakefile | 130 ++ cpp/bindings/qpid/ruby/TODO | 7 + cpp/bindings/qpid/ruby/examples/client.rb | 50 + cpp/bindings/qpid/ruby/examples/drain.rb | 111 ++ cpp/bindings/qpid/ruby/examples/hello_world.rb | 49 + cpp/bindings/qpid/ruby/examples/map_receiver.rb | 63 + cpp/bindings/qpid/ruby/examples/map_sender.rb | 52 + cpp/bindings/qpid/ruby/examples/server.rb | 51 + cpp/bindings/qpid/ruby/examples/spout.rb | 126 ++ cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb | 73 + cpp/bindings/qpid/ruby/lib/qpid.rb | 29 + cpp/bindings/qpid/ruby/lib/qpid/address.rb | 125 ++ cpp/bindings/qpid/ruby/lib/qpid/connection.rb | 134 ++ cpp/bindings/qpid/ruby/lib/qpid/duration.rb | 63 + cpp/bindings/qpid/ruby/lib/qpid/encoding.rb | 56 + cpp/bindings/qpid/ruby/lib/qpid/errors.rb | 30 + cpp/bindings/qpid/ruby/lib/qpid/message.rb | 157 ++ cpp/bindings/qpid/ruby/lib/qpid/receiver.rb | 102 ++ cpp/bindings/qpid/ruby/lib/qpid/sender.rb | 82 + cpp/bindings/qpid/ruby/lib/qpid/session.rb | 186 ++ cpp/bindings/qpid/ruby/lib/qpid/version.rb | 31 + cpp/bindings/qpid/ruby/test/lib/setup.rb | 29 + cpp/bindings/qpid/ruby/test/test_address.rb | 39 + cpp/bindings/qpid/ruby/test/test_connection.rb | 257 +++ cpp/bindings/qpid/ruby/test/test_encoding.rb | 146 ++ cpp/bindings/qpid/ruby/test/test_message.rb | 353 ++++ cpp/bindings/qpid/ruby/test/test_receiver.rb | 238 +++ cpp/bindings/qpid/ruby/test/test_sender.rb | 183 ++ cpp/bindings/qpid/ruby/test/test_session.rb | 445 +++++ cpp/bindings/qpid/ruby/test/ts_bindings.rb | 30 + cpp/bindings/swig_python_typemaps.i | 56 + cpp/bindings/swig_ruby_typemaps.i | 2 +- cpp/bld-winsdk.ps1 | 3 - cpp/configure.ac | 21 +- cpp/design_docs/hot-standby-design.txt | 239 +++ cpp/design_docs/new-cluster-design.txt | 302 ++-- cpp/design_docs/new-cluster-plan.txt | 563 ++---- cpp/docs/api/developer.doxygen.in | 2 +- cpp/docs/api/doxygen_mainpage.h | 41 +- cpp/docs/api/footer.html | 2 +- cpp/docs/api/user.doxygen.in | 2 +- cpp/docs/man/Makefile.am | 23 +- cpp/docs/man/qpidd.1 | 247 +++ cpp/docs/man/qpidd.x | 2 + cpp/etc/Makefile.am | 23 - cpp/etc/qpidd.conf | 2 +- cpp/etc/sasl2/qpidd.conf | 5 +- cpp/examples/CMakeLists.txt | 13 +- cpp/examples/Makefile.am | 16 +- cpp/examples/README.verify | 42 - cpp/examples/direct/CMakeLists.txt | 22 - cpp/examples/direct/Makefile.am | 47 - cpp/examples/direct/declare_queues.cpp | 85 - cpp/examples/direct/direct_declare_queues.vcproj | 394 ---- cpp/examples/direct/direct_direct_producer.vcproj | 394 ---- cpp/examples/direct/direct_listener.vcproj | 394 ---- cpp/examples/direct/direct_producer.cpp | 109 -- cpp/examples/direct/listener.cpp | 109 -- cpp/examples/direct/verify | 23 - cpp/examples/direct/verify.in | 15 - cpp/examples/examples.sln | 24 + cpp/examples/failover/CMakeLists.txt | 22 - cpp/examples/failover/Makefile.am | 47 - cpp/examples/failover/declare_queues.cpp | 61 - .../failover/failover_declare_queues.vcproj | 394 ---- .../failover/failover_replaying_sender.vcproj | 394 ---- .../failover/failover_resuming_receiver.vcproj | 394 ---- cpp/examples/failover/replaying_sender.cpp | 97 - cpp/examples/failover/resuming_receiver.cpp | 127 -- cpp/examples/fanout/CMakeLists.txt | 21 - cpp/examples/fanout/Makefile.am | 42 - cpp/examples/fanout/fanout_fanout_producer.vcproj | 394 ---- cpp/examples/fanout/fanout_listener.vcproj | 394 ---- cpp/examples/fanout/fanout_producer.cpp | 105 -- cpp/examples/fanout/listener.cpp | 125 -- cpp/examples/fanout/verify | 25 - cpp/examples/fanout/verify.in | 43 - cpp/examples/messaging/drain.cpp | 4 +- cpp/examples/messaging/server.cpp | 4 +- cpp/examples/messaging/spout.cpp | 2 +- cpp/examples/old-examples.sln | 147 -- cpp/examples/old_api/CMakeLists.txt | 25 + cpp/examples/old_api/Makefile.am | 48 + cpp/examples/old_api/README.verify | 42 + cpp/examples/old_api/direct/CMakeLists.txt | 22 + cpp/examples/old_api/direct/Makefile.am | 47 + cpp/examples/old_api/direct/declare_queues.cpp | 85 + .../old_api/direct/direct_declare_queues.vcproj | 394 ++++ .../old_api/direct/direct_direct_producer.vcproj | 394 ++++ cpp/examples/old_api/direct/direct_listener.vcproj | 394 ++++ cpp/examples/old_api/direct/direct_producer.cpp | 109 ++ cpp/examples/old_api/direct/listener.cpp | 109 ++ cpp/examples/old_api/direct/verify | 23 + cpp/examples/old_api/direct/verify.in | 15 + cpp/examples/old_api/failover/CMakeLists.txt | 22 + cpp/examples/old_api/failover/Makefile.am | 47 + cpp/examples/old_api/failover/declare_queues.cpp | 61 + .../failover/failover_declare_queues.vcproj | 394 ++++ .../failover/failover_replaying_sender.vcproj | 394 ++++ .../failover/failover_resuming_receiver.vcproj | 394 ++++ cpp/examples/old_api/failover/replaying_sender.cpp | 97 + .../old_api/failover/resuming_receiver.cpp | 127 ++ cpp/examples/old_api/fanout/CMakeLists.txt | 21 + cpp/examples/old_api/fanout/Makefile.am | 42 + .../old_api/fanout/fanout_fanout_producer.vcproj | 394 ++++ cpp/examples/old_api/fanout/fanout_listener.vcproj | 394 ++++ cpp/examples/old_api/fanout/fanout_producer.cpp | 105 ++ cpp/examples/old_api/fanout/listener.cpp | 125 ++ cpp/examples/old_api/fanout/verify | 25 + cpp/examples/old_api/fanout/verify.in | 43 + cpp/examples/old_api/old-examples.sln | 123 ++ cpp/examples/old_api/pub-sub/CMakeLists.txt | 21 + cpp/examples/old_api/pub-sub/Makefile.am | 43 + .../old_api/pub-sub/pub-sub_topic_listener.vcproj | 394 ++++ .../old_api/pub-sub/pub-sub_topic_publisher.vcproj | 394 ++++ cpp/examples/old_api/pub-sub/topic_listener.cpp | 173 ++ cpp/examples/old_api/pub-sub/topic_publisher.cpp | 129 ++ cpp/examples/old_api/pub-sub/verify | 23 + cpp/examples/old_api/pub-sub/verify.in | 59 + .../old_api/request-response/CMakeLists.txt | 21 + cpp/examples/old_api/request-response/Makefile.am | 43 + cpp/examples/old_api/request-response/client.cpp | 163 ++ .../request-response_client.vcproj | 394 ++++ .../request-response_server.vcproj | 394 ++++ cpp/examples/old_api/request-response/server.cpp | 161 ++ cpp/examples/old_api/request-response/verify | 24 + cpp/examples/old_api/request-response/verify.in | 19 + cpp/examples/old_api/tradedemo/CMakeLists.txt | 22 + cpp/examples/old_api/tradedemo/Makefile.am | 46 + cpp/examples/old_api/tradedemo/declare_queues.cpp | 98 + cpp/examples/old_api/tradedemo/topic_listener.cpp | 183 ++ cpp/examples/old_api/tradedemo/topic_publisher.cpp | 271 +++ .../tradedemo/tradedemo_declare_queues.vcproj | 394 ++++ .../tradedemo/tradedemo_topic_listener.vcproj | 394 ++++ .../tradedemo/tradedemo_topic_publisher.vcproj | 394 ++++ cpp/examples/old_api/verify | 121 ++ cpp/examples/old_api/verify_all | 46 + cpp/examples/old_api/xml-exchange/CMakeLists.txt | 24 + cpp/examples/old_api/xml-exchange/Makefile.am | 49 + cpp/examples/old_api/xml-exchange/README.txt | 53 + .../old_api/xml-exchange/declare_queues.cpp | 98 + cpp/examples/old_api/xml-exchange/listener.cpp | 107 ++ cpp/examples/old_api/xml-exchange/xml_producer.cpp | 113 ++ cpp/examples/pub-sub/CMakeLists.txt | 21 - cpp/examples/pub-sub/Makefile.am | 43 - cpp/examples/pub-sub/pub-sub_topic_listener.vcproj | 394 ---- .../pub-sub/pub-sub_topic_publisher.vcproj | 394 ---- cpp/examples/pub-sub/topic_listener.cpp | 173 -- cpp/examples/pub-sub/topic_publisher.cpp | 129 -- cpp/examples/pub-sub/verify | 23 - cpp/examples/pub-sub/verify.in | 59 - cpp/examples/qmf-console/ping.cpp | 4 +- cpp/examples/qmf-console/printevents.cpp | 4 +- cpp/examples/request-response/CMakeLists.txt | 21 - cpp/examples/request-response/Makefile.am | 43 - cpp/examples/request-response/client.cpp | 163 -- .../request-response_client.vcproj | 394 ---- .../request-response_server.vcproj | 394 ---- cpp/examples/request-response/server.cpp | 161 -- cpp/examples/request-response/verify | 24 - cpp/examples/request-response/verify.in | 19 - cpp/examples/tradedemo/CMakeLists.txt | 22 - cpp/examples/tradedemo/Makefile.am | 46 - cpp/examples/tradedemo/declare_queues.cpp | 98 - cpp/examples/tradedemo/topic_listener.cpp | 183 -- cpp/examples/tradedemo/topic_publisher.cpp | 271 --- .../tradedemo/tradedemo_declare_queues.vcproj | 394 ---- .../tradedemo/tradedemo_topic_listener.vcproj | 394 ---- .../tradedemo/tradedemo_topic_publisher.vcproj | 394 ---- cpp/examples/verify | 121 -- cpp/examples/verify_all | 46 - cpp/examples/xml-exchange/CMakeLists.txt | 24 - cpp/examples/xml-exchange/Makefile.am | 49 - cpp/examples/xml-exchange/README.txt | 53 - cpp/examples/xml-exchange/declare_queues.cpp | 98 - cpp/examples/xml-exchange/listener.cpp | 107 -- cpp/examples/xml-exchange/xml_producer.cpp | 113 -- cpp/include/qmf/Agent.h | 2 +- cpp/include/qmf/AgentEvent.h | 2 +- cpp/include/qmf/AgentSession.h | 48 +- cpp/include/qmf/ConsoleEvent.h | 2 +- cpp/include/qmf/ConsoleSession.h | 55 +- cpp/include/qmf/Data.h | 2 +- cpp/include/qmf/DataAddr.h | 5 +- cpp/include/qmf/Handle.h | 10 +- cpp/include/qmf/ImportExport.h | 16 +- cpp/include/qmf/Query.h | 4 +- cpp/include/qmf/Schema.h | 2 +- cpp/include/qmf/SchemaId.h | 2 +- cpp/include/qmf/SchemaMethod.h | 2 +- cpp/include/qmf/SchemaProperty.h | 2 +- cpp/include/qmf/Subscription.h | 4 +- cpp/include/qmf/engine/QmfEngineImportExport.h | 9 + cpp/include/qmf/exceptions.h | 8 +- cpp/include/qmf/posix/EventNotifier.h | 63 + cpp/include/qpid/Address.h | 2 +- cpp/include/qpid/CommonImportExport.h | 14 +- cpp/include/qpid/Exception.h | 12 +- cpp/include/qpid/ImportExport.h | 71 + cpp/include/qpid/Msg.h | 1 + cpp/include/qpid/Options.h | 88 - cpp/include/qpid/Url.h | 2 +- cpp/include/qpid/agent/ManagementAgent.h | 4 +- cpp/include/qpid/agent/QmfAgentImportExport.h | 16 +- cpp/include/qpid/amqp_0_10/Codecs.h | 20 +- cpp/include/qpid/client/ClientImportExport.h | 14 +- cpp/include/qpid/client/Completion.h | 2 +- cpp/include/qpid/client/Connection.h | 10 +- cpp/include/qpid/client/ConnectionSettings.h | 2 +- cpp/include/qpid/client/FailoverListener.h | 2 +- cpp/include/qpid/client/FailoverManager.h | 2 +- cpp/include/qpid/client/Future.h | 2 +- cpp/include/qpid/client/FutureResult.h | 2 +- cpp/include/qpid/client/Handle.h | 10 +- cpp/include/qpid/client/LocalQueue.h | 2 +- cpp/include/qpid/client/Message.h | 2 +- cpp/include/qpid/client/MessageListener.h | 2 +- cpp/include/qpid/client/MessageReplayTracker.h | 2 +- cpp/include/qpid/client/QueueOptions.h | 2 +- cpp/include/qpid/client/SessionBase_0_10.h | 2 +- cpp/include/qpid/client/Subscription.h | 8 +- cpp/include/qpid/client/SubscriptionManager.h | 2 +- cpp/include/qpid/console/Agent.h | 14 +- cpp/include/qpid/console/Broker.h | 16 +- cpp/include/qpid/console/ClassKey.h | 30 +- cpp/include/qpid/console/ConsoleImportExport.h | 14 +- cpp/include/qpid/console/ObjectId.h | 8 +- cpp/include/qpid/framing/Array.h | 26 +- cpp/include/qpid/framing/Buffer.h | 16 +- cpp/include/qpid/framing/FieldTable.h | 6 +- cpp/include/qpid/framing/FieldValue.h | 21 +- cpp/include/qpid/framing/List.h | 25 +- cpp/include/qpid/framing/ProtocolVersion.h | 12 +- cpp/include/qpid/framing/SequenceNumber.h | 2 +- cpp/include/qpid/framing/SequenceSet.h | 2 +- cpp/include/qpid/framing/StructHelper.h | 2 +- cpp/include/qpid/framing/Uuid.h | 10 +- cpp/include/qpid/log/Logger.h | 6 +- cpp/include/qpid/log/Options.h | 2 +- cpp/include/qpid/management/ManagementObject.h | 18 +- cpp/include/qpid/messaging/Address.h | 2 +- cpp/include/qpid/messaging/Connection.h | 30 +- cpp/include/qpid/messaging/Duration.h | 8 +- cpp/include/qpid/messaging/FailoverUpdates.h | 2 +- cpp/include/qpid/messaging/Handle.h | 10 +- cpp/include/qpid/messaging/ImportExport.h | 14 +- cpp/include/qpid/messaging/Message.h | 101 +- cpp/include/qpid/messaging/Receiver.h | 2 +- cpp/include/qpid/messaging/Sender.h | 2 +- cpp/include/qpid/messaging/Session.h | 51 +- cpp/include/qpid/messaging/exceptions.h | 98 +- cpp/include/qpid/sys/ExceptionHolder.h | 13 +- cpp/include/qpid/sys/IntegerTypes.h | 2 +- cpp/include/qpid/sys/Runnable.h | 2 +- cpp/include/qpid/sys/Thread.h | 6 +- cpp/include/qpid/sys/Time.h | 5 +- cpp/include/qpid/sys/windows/IntegerTypes.h | 6 +- cpp/include/qpid/types/Exception.h | 2 +- cpp/include/qpid/types/ImportExport.h | 14 +- cpp/include/qpid/types/Uuid.h | 2 +- cpp/include/qpid/types/Variant.h | 6 +- cpp/managementgen/Makefile.am | 12 +- cpp/managementgen/qmfgen/schema.py | 4 +- cpp/rubygen/0-10/specification.rb | 2 +- cpp/rubygen/MethodBodyDefaultVisitor.rb | 2 +- cpp/rubygen/amqpgen.rb | 6 +- cpp/rubygen/cppgen.rb | 3 + .../framing.0-10/MethodBodyDefaultVisitor.rb | 2 +- cpp/rubygen/framing.0-10/OperationsInvoker.rb | 2 +- cpp/rubygen/framing.0-10/Proxy.rb | 4 +- cpp/rubygen/framing.0-10/Session.rb | 4 +- cpp/rubygen/framing.0-10/structs.rb | 2 +- cpp/src/CMakeLists.txt | 126 +- cpp/src/CMakeWinVersions.cmake | 12 +- cpp/src/Makefile.am | 55 +- cpp/src/acl.mk | 4 +- cpp/src/cluster.mk | 6 +- cpp/src/posix/QpiddBroker.cpp | 12 +- cpp/src/qmf.mk | 9 +- cpp/src/qmf/Agent.cpp | 29 +- cpp/src/qmf/AgentImpl.h | 1 - cpp/src/qmf/AgentSession.cpp | 229 +-- cpp/src/qmf/AgentSessionImpl.h | 175 ++ cpp/src/qmf/ConsoleSession.cpp | 125 +- cpp/src/qmf/ConsoleSessionImpl.h | 22 + cpp/src/qmf/DataAddr.cpp | 6 +- cpp/src/qmf/DataAddrImpl.h | 4 +- cpp/src/qmf/EventNotifierImpl.cpp | 56 + cpp/src/qmf/EventNotifierImpl.h | 48 + cpp/src/qmf/PosixEventNotifier.cpp | 65 + cpp/src/qmf/PosixEventNotifierImpl.cpp | 112 ++ cpp/src/qmf/PosixEventNotifierImpl.h | 61 + cpp/src/qmf/PrivateImplRef.h | 2 +- cpp/src/qmf/engine/ResilientConnection.cpp | 6 +- cpp/src/qmf/engine/SchemaImpl.cpp | 11 +- cpp/src/qmf/engine/SchemaImpl.h | 7 +- cpp/src/qpid/Address.cpp | 8 +- cpp/src/qpid/BufferRef.h | 70 + cpp/src/qpid/DisableExceptionLogging.h | 39 + cpp/src/qpid/Exception.cpp | 16 +- cpp/src/qpid/Modules.cpp | 3 +- cpp/src/qpid/Options.cpp | 269 --- cpp/src/qpid/RefCounted.h | 6 +- cpp/src/qpid/RefCountedBuffer.cpp | 29 +- cpp/src/qpid/RefCountedBuffer.h | 61 +- cpp/src/qpid/Sasl.h | 4 +- cpp/src/qpid/SaslFactory.cpp | 28 +- cpp/src/qpid/Url.cpp | 23 +- cpp/src/qpid/acl/Acl.cpp | 5 +- cpp/src/qpid/acl/AclPlugin.cpp | 2 +- cpp/src/qpid/agent/ManagementAgentImpl.cpp | 361 ++-- cpp/src/qpid/agent/ManagementAgentImpl.h | 4 +- cpp/src/qpid/amqp_0_10/Codecs.cpp | 6 +- cpp/src/qpid/amqp_0_10/SessionHandler.cpp | 8 +- cpp/src/qpid/amqp_0_10/SessionHandler.h | 6 +- cpp/src/qpid/broker/AsyncCompletion.h | 201 +++ cpp/src/qpid/broker/Bridge.cpp | 6 + cpp/src/qpid/broker/Bridge.h | 2 + cpp/src/qpid/broker/Broker.cpp | 566 +++++- cpp/src/qpid/broker/Broker.h | 107 +- cpp/src/qpid/broker/BrokerImportExport.h | 23 +- cpp/src/qpid/broker/Connection.cpp | 57 +- cpp/src/qpid/broker/Connection.h | 9 +- cpp/src/qpid/broker/ConnectionHandler.cpp | 78 +- cpp/src/qpid/broker/ConnectionHandler.h | 6 +- cpp/src/qpid/broker/ConnectionState.h | 9 +- cpp/src/qpid/broker/Consumer.h | 21 +- cpp/src/qpid/broker/Daemon.cpp | 5 +- cpp/src/qpid/broker/DeliverableMessage.h | 2 +- cpp/src/qpid/broker/DeliveryRecord.cpp | 28 +- cpp/src/qpid/broker/DeliveryRecord.h | 4 +- cpp/src/qpid/broker/DirectExchange.cpp | 14 +- cpp/src/qpid/broker/DtxAck.cpp | 4 + cpp/src/qpid/broker/DtxAck.h | 35 +- cpp/src/qpid/broker/DtxBuffer.cpp | 22 +- cpp/src/qpid/broker/DtxBuffer.h | 53 +- cpp/src/qpid/broker/DtxManager.cpp | 40 +- cpp/src/qpid/broker/DtxManager.h | 26 +- cpp/src/qpid/broker/DtxTimeout.cpp | 2 +- cpp/src/qpid/broker/DtxTimeout.h | 10 +- cpp/src/qpid/broker/DtxWorkRecord.cpp | 40 +- cpp/src/qpid/broker/DtxWorkRecord.h | 14 +- cpp/src/qpid/broker/Exchange.cpp | 83 +- cpp/src/qpid/broker/Exchange.h | 48 +- cpp/src/qpid/broker/ExchangeRegistry.cpp | 11 +- cpp/src/qpid/broker/ExpiryPolicy.cpp | 10 +- cpp/src/qpid/broker/ExpiryPolicy.h | 14 +- cpp/src/qpid/broker/Fairshare.cpp | 76 +- cpp/src/qpid/broker/Fairshare.h | 6 +- cpp/src/qpid/broker/FanOutExchange.cpp | 11 +- cpp/src/qpid/broker/FifoDistributor.cpp | 58 + cpp/src/qpid/broker/FifoDistributor.h | 58 + cpp/src/qpid/broker/HeadersExchange.cpp | 20 +- cpp/src/qpid/broker/IncompleteMessageList.cpp | 85 - cpp/src/qpid/broker/IncompleteMessageList.h | 58 - cpp/src/qpid/broker/LegacyLVQ.cpp | 6 +- cpp/src/qpid/broker/Link.cpp | 65 +- cpp/src/qpid/broker/Link.h | 10 +- cpp/src/qpid/broker/LinkRegistry.cpp | 6 +- cpp/src/qpid/broker/Message.cpp | 172 +- cpp/src/qpid/broker/Message.h | 78 +- cpp/src/qpid/broker/MessageBuilder.h | 2 +- cpp/src/qpid/broker/MessageDistributor.h | 76 + cpp/src/qpid/broker/MessageGroupManager.cpp | 411 +++++ cpp/src/qpid/broker/MessageGroupManager.h | 107 ++ cpp/src/qpid/broker/Messages.h | 4 +- cpp/src/qpid/broker/NullMessageStore.cpp | 4 + cpp/src/qpid/broker/NullMessageStore.h | 4 +- cpp/src/qpid/broker/PersistableMessage.cpp | 26 +- cpp/src/qpid/broker/PersistableMessage.h | 29 +- cpp/src/qpid/broker/Queue.cpp | 727 +++++--- cpp/src/qpid/broker/Queue.h | 131 +- cpp/src/qpid/broker/QueueCleaner.cpp | 18 +- cpp/src/qpid/broker/QueueCleaner.h | 14 +- cpp/src/qpid/broker/QueueEvents.cpp | 4 + cpp/src/qpid/broker/QueueFlowLimit.cpp | 410 +++++ cpp/src/qpid/broker/QueueFlowLimit.h | 132 ++ cpp/src/qpid/broker/QueueListeners.cpp | 36 +- cpp/src/qpid/broker/QueueListeners.h | 4 +- cpp/src/qpid/broker/QueueObserver.h | 42 +- cpp/src/qpid/broker/QueuePolicy.cpp | 23 +- cpp/src/qpid/broker/QueuePolicy.h | 3 +- cpp/src/qpid/broker/QueueRegistry.cpp | 20 +- cpp/src/qpid/broker/QueueRegistry.h | 7 +- cpp/src/qpid/broker/RateTracker.cpp | 51 - cpp/src/qpid/broker/RateTracker.h | 57 - cpp/src/qpid/broker/RecoveredDequeue.cpp | 1 - cpp/src/qpid/broker/RecoveredEnqueue.cpp | 1 - cpp/src/qpid/broker/RecoveryManagerImpl.cpp | 3 +- cpp/src/qpid/broker/SaslAuthenticator.cpp | 66 +- cpp/src/qpid/broker/SaslAuthenticator.h | 2 +- cpp/src/qpid/broker/SemanticState.cpp | 171 +- cpp/src/qpid/broker/SemanticState.h | 45 +- cpp/src/qpid/broker/SessionAdapter.cpp | 292 ++- cpp/src/qpid/broker/SessionAdapter.h | 1 + cpp/src/qpid/broker/SessionContext.h | 1 + cpp/src/qpid/broker/SessionHandler.cpp | 5 - cpp/src/qpid/broker/SessionState.cpp | 245 ++- cpp/src/qpid/broker/SessionState.h | 119 +- cpp/src/qpid/broker/StatefulQueueObserver.h | 63 + cpp/src/qpid/broker/ThresholdAlerts.cpp | 68 +- cpp/src/qpid/broker/ThresholdAlerts.h | 7 +- cpp/src/qpid/broker/TopicExchange.cpp | 84 +- cpp/src/qpid/broker/TopicExchange.h | 29 +- cpp/src/qpid/broker/TxBuffer.cpp | 2 +- cpp/src/qpid/broker/TxPublish.cpp | 9 +- cpp/src/qpid/broker/TxPublish.h | 91 +- cpp/src/qpid/broker/windows/BrokerDefaults.cpp | 6 + cpp/src/qpid/broker/windows/SaslAuthenticator.cpp | 32 +- cpp/src/qpid/broker/windows/SslProtocolFactory.cpp | 53 +- cpp/src/qpid/client/ConnectionHandler.cpp | 64 +- cpp/src/qpid/client/ConnectionImpl.cpp | 12 +- cpp/src/qpid/client/Connector.h | 2 +- cpp/src/qpid/client/RdmaConnector.cpp | 6 +- cpp/src/qpid/client/SessionImpl.cpp | 1 + cpp/src/qpid/client/SslConnector.cpp | 6 +- cpp/src/qpid/client/TCPConnector.cpp | 6 +- cpp/src/qpid/client/TCPConnector.h | 2 +- cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp | 42 +- cpp/src/qpid/client/amqp0_10/AcceptTracker.h | 5 +- cpp/src/qpid/client/amqp0_10/AddressResolution.cpp | 60 +- cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp | 179 +- cpp/src/qpid/client/amqp0_10/ConnectionImpl.h | 2 + cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp | 10 +- cpp/src/qpid/client/amqp0_10/IncomingMessages.h | 2 +- cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp | 4 +- cpp/src/qpid/client/amqp0_10/SenderImpl.cpp | 3 +- cpp/src/qpid/client/amqp0_10/SessionImpl.cpp | 56 +- cpp/src/qpid/client/amqp0_10/SessionImpl.h | 11 +- cpp/src/qpid/client/amqp0_10/SimpleUrlParser.cpp | 79 - cpp/src/qpid/client/amqp0_10/SimpleUrlParser.h | 42 - cpp/src/qpid/client/windows/SaslFactory.cpp | 16 +- cpp/src/qpid/client/windows/SslConnector.cpp | 4 +- cpp/src/qpid/cluster/Cluster.cpp | 169 +- cpp/src/qpid/cluster/Cluster.h | 56 +- cpp/src/qpid/cluster/ClusterMap.cpp | 5 - cpp/src/qpid/cluster/ClusterPlugin.cpp | 1 + cpp/src/qpid/cluster/ClusterSettings.h | 3 +- cpp/src/qpid/cluster/ClusterTimer.cpp | 4 + cpp/src/qpid/cluster/Connection.cpp | 235 ++- cpp/src/qpid/cluster/Connection.h | 55 +- cpp/src/qpid/cluster/Decoder.h | 2 +- cpp/src/qpid/cluster/ErrorCheck.h | 2 +- cpp/src/qpid/cluster/Event.cpp | 5 +- cpp/src/qpid/cluster/Event.h | 28 +- cpp/src/qpid/cluster/EventFrame.h | 6 +- cpp/src/qpid/cluster/ExpiryPolicy.cpp | 95 +- cpp/src/qpid/cluster/ExpiryPolicy.h | 42 +- cpp/src/qpid/cluster/FailoverExchange.cpp | 26 +- cpp/src/qpid/cluster/FailoverExchange.h | 10 +- cpp/src/qpid/cluster/Multicaster.cpp | 3 +- cpp/src/qpid/cluster/OutputInterceptor.cpp | 39 +- cpp/src/qpid/cluster/OutputInterceptor.h | 10 +- cpp/src/qpid/cluster/SecureConnectionFactory.cpp | 8 +- cpp/src/qpid/cluster/UpdateClient.cpp | 223 ++- cpp/src/qpid/cluster/UpdateClient.h | 32 +- cpp/src/qpid/cluster/UpdateDataExchange.cpp | 10 +- cpp/src/qpid/cluster/UpdateDataExchange.h | 2 - cpp/src/qpid/cluster/UpdateExchange.cpp | 27 +- cpp/src/qpid/cluster/UpdateReceiver.h | 14 + cpp/src/qpid/cluster/types.h | 1 + cpp/src/qpid/console/SessionManager.cpp | 3 +- cpp/src/qpid/framing/AMQBody.h | 2 +- cpp/src/qpid/framing/AMQContentBody.h | 12 +- cpp/src/qpid/framing/AMQFrame.cpp | 5 + cpp/src/qpid/framing/AMQFrame.h | 7 +- cpp/src/qpid/framing/AMQHeaderBody.h | 14 +- cpp/src/qpid/framing/AMQHeartbeatBody.h | 2 +- cpp/src/qpid/framing/FieldTable.cpp | 6 +- cpp/src/qpid/framing/List.cpp | 6 + cpp/src/qpid/framing/MethodBodyFactory.h | 1 + cpp/src/qpid/framing/SendContent.h | 2 +- cpp/src/qpid/framing/TransferContent.h | 2 +- cpp/src/qpid/framing/Uuid.cpp | 4 +- cpp/src/qpid/log/Logger.cpp | 21 +- cpp/src/qpid/log/Options.cpp | 4 + cpp/src/qpid/log/Statement.cpp | 5 +- cpp/src/qpid/log/posix/SinkOptions.cpp | 2 +- cpp/src/qpid/log/windows/SinkOptions.cpp | 4 +- cpp/src/qpid/log/windows/SinkOptions.h | 2 +- cpp/src/qpid/management/ManagementAgent.cpp | 228 +-- cpp/src/qpid/management/ManagementAgent.h | 13 +- cpp/src/qpid/messaging/AddressParser.cpp | 5 +- cpp/src/qpid/messaging/Duration.cpp | 10 + cpp/src/qpid/messaging/Message.cpp | 7 +- cpp/src/qpid/messaging/Session.cpp | 3 +- cpp/src/qpid/messaging/SessionImpl.h | 2 +- .../qpid/replication/ReplicatingEventListener.cpp | 7 +- cpp/src/qpid/replication/ReplicationExchange.cpp | 9 +- cpp/src/qpid/store/StorageProvider.h | 2 +- cpp/src/qpid/sys/AggregateOutput.h | 2 +- cpp/src/qpid/sys/AsynchIO.h | 4 +- cpp/src/qpid/sys/AsynchIOHandler.h | 2 +- cpp/src/qpid/sys/AtomicValue.h | 7 +- cpp/src/qpid/sys/AtomicValue_gcc.h | 11 +- cpp/src/qpid/sys/ClusterSafe.cpp | 12 +- cpp/src/qpid/sys/ClusterSafe.h | 21 +- cpp/src/qpid/sys/CopyOnWriteArray.h | 6 + cpp/src/qpid/sys/PollableQueue.h | 21 +- cpp/src/qpid/sys/Poller.h | 2 +- cpp/src/qpid/sys/ProtocolFactory.h | 3 +- cpp/src/qpid/sys/RdmaIOPlugin.cpp | 24 +- cpp/src/qpid/sys/Socket.h | 34 +- cpp/src/qpid/sys/SocketAddress.h | 10 +- cpp/src/qpid/sys/SslPlugin.cpp | 154 +- cpp/src/qpid/sys/StateMonitor.h | 14 +- cpp/src/qpid/sys/TCPIOPlugin.cpp | 105 +- cpp/src/qpid/sys/Timer.cpp | 22 +- cpp/src/qpid/sys/Timer.h | 8 +- cpp/src/qpid/sys/TimerWarnings.cpp | 16 +- cpp/src/qpid/sys/alloca.h | 25 +- cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.cpp | 3 +- cpp/src/qpid/sys/epoll/EpollPoller.cpp | 7 +- cpp/src/qpid/sys/posix/AsynchIO.cpp | 36 +- cpp/src/qpid/sys/posix/LockFile.cpp | 3 +- cpp/src/qpid/sys/posix/Socket.cpp | 171 +- cpp/src/qpid/sys/posix/SocketAddress.cpp | 80 +- cpp/src/qpid/sys/posix/Thread.cpp | 3 +- cpp/src/qpid/sys/posix/Time.cpp | 7 + cpp/src/qpid/sys/rdma/RdmaIO.cpp | 14 +- cpp/src/qpid/sys/rdma/rdma_wrap.cpp | 15 +- cpp/src/qpid/sys/rdma/rdma_wrap.h | 10 +- cpp/src/qpid/sys/ssl/SslHandler.h | 2 +- cpp/src/qpid/sys/ssl/SslIo.cpp | 22 +- cpp/src/qpid/sys/ssl/SslIo.h | 18 +- cpp/src/qpid/sys/ssl/SslSocket.cpp | 163 +- cpp/src/qpid/sys/ssl/SslSocket.h | 46 +- cpp/src/qpid/sys/windows/AsynchIO.cpp | 71 +- cpp/src/qpid/sys/windows/AsynchIoResult.h | 6 +- cpp/src/qpid/sys/windows/IocpPoller.cpp | 6 +- cpp/src/qpid/sys/windows/Shlib.cpp | 3 +- cpp/src/qpid/sys/windows/Socket.cpp | 188 +- cpp/src/qpid/sys/windows/SocketAddress.cpp | 120 +- cpp/src/qpid/sys/windows/SslAsynchIO.h | 3 - cpp/src/qpid/sys/windows/StrError.cpp | 7 +- cpp/src/qpid/sys/windows/Thread.cpp | 285 ++- cpp/src/qpid/sys/windows/Time.cpp | 36 + cpp/src/qpid/sys/windows/mingw32_compat.h | 39 + cpp/src/qpid/sys/windows/uuid.cpp | 6 +- cpp/src/qpid/types/Uuid.cpp | 19 +- cpp/src/qpid/types/Variant.cpp | 35 +- cpp/src/replication.mk | 6 +- cpp/src/ssl.mk | 6 +- cpp/src/tests/.valgrind.supp | 74 - cpp/src/tests/Address.cpp | 11 + cpp/src/tests/BrokerFixture.h | 32 +- cpp/src/tests/BrokerMgmtAgent.cpp | 3 +- cpp/src/tests/BrokerOptions.cpp | 79 + cpp/src/tests/CMakeLists.txt | 18 +- cpp/src/tests/ClientSessionTest.cpp | 33 +- cpp/src/tests/ExchangeTest.cpp | 2 +- cpp/src/tests/ForkedBroker.cpp | 3 +- cpp/src/tests/IncompleteMessageList.cpp | 134 -- cpp/src/tests/Makefile.am | 47 +- cpp/src/tests/MessageReplayTracker.cpp | 4 +- cpp/src/tests/MessagingFixture.h | 117 ++ cpp/src/tests/MessagingSessionTests.cpp | 228 +++ cpp/src/tests/Qmf2.cpp | 104 +- cpp/src/tests/QueueEvents.cpp | 4 +- cpp/src/tests/QueueFlowLimitTest.cpp | 463 +++++ cpp/src/tests/QueuePolicyTest.cpp | 21 +- cpp/src/tests/QueueTest.cpp | 444 ++++- cpp/src/tests/ReplicationTest.cpp | 2 +- cpp/src/tests/SessionState.cpp | 8 +- cpp/src/tests/SocketProxy.h | 181 -- cpp/src/tests/TimerTest.cpp | 4 +- cpp/src/tests/TxPublishTest.cpp | 7 +- cpp/src/tests/Url.cpp | 26 + cpp/src/tests/Variant.cpp | 58 + cpp/src/tests/XmlClientSessionTest.cpp | 2 +- cpp/src/tests/acl.py | 219 ++- cpp/src/tests/allhosts | 4 +- cpp/src/tests/brokertest.py | 312 ++-- cpp/src/tests/cli_tests.py | 24 +- cpp/src/tests/cluster_python_tests_failing.txt | 28 - cpp/src/tests/cluster_test_logs.py | 16 +- cpp/src/tests/cluster_tests.py | 1033 ++++++++++- cpp/src/tests/exception_test.cpp | 14 +- cpp/src/tests/federated_topic_test | 27 +- cpp/src/tests/federation.py | 398 +++- cpp/src/tests/federation_sys.py | 1900 ++++++++++++++++++++ cpp/src/tests/ipv6_test | 150 ++ cpp/src/tests/msg_group_test.cpp | 618 +++++++ cpp/src/tests/python_tests | 2 +- cpp/src/tests/qpid-cluster-benchmark | 47 +- cpp/src/tests/qpid-cpp-benchmark | 71 +- cpp/src/tests/qpid-ctrl | 5 +- cpp/src/tests/qpid-perftest.cpp | 22 +- cpp/src/tests/qpid-receive.cpp | 9 +- cpp/src/tests/qpid-send.cpp | 104 +- cpp/src/tests/qrsh.cpp | 169 -- cpp/src/tests/qrsh_run.cpp | 321 ---- cpp/src/tests/qrsh_server.cpp | 1068 ----------- cpp/src/tests/qrsh_utils/10_all | 30 - cpp/src/tests/qrsh_utils/1_remote_run | 26 - cpp/src/tests/qrsh_utils/2_forever | 26 - cpp/src/tests/qrsh_utils/3_kill_it | 27 - cpp/src/tests/qrsh_utils/4_wait_for_it | 26 - cpp/src/tests/qrsh_utils/5_exited | 64 - cpp/src/tests/qrsh_utils/6_get | 29 - cpp/src/tests/qrsh_utils/7_get_output | 44 - cpp/src/tests/qrsh_utils/8_any | 43 - cpp/src/tests/qrsh_utils/9_alias | 38 - cpp/src/tests/qrsh_utils/qrsh_example_command.cpp | 52 - cpp/src/tests/qrsh_utils/qrsh_forever.cpp | 50 - cpp/src/tests/qrsh_utils/qsh_doc.txt | 309 ---- cpp/src/tests/queue_flow_limit_tests.py | 371 ++++ cpp/src/tests/replication_test | 2 +- cpp/src/tests/run_acl_tests | 2 +- cpp/src/tests/run_cli_tests | 5 +- cpp/src/tests/run_federation_sys_tests | 97 + cpp/src/tests/run_federation_tests | 4 +- cpp/src/tests/run_header_test | 2 +- cpp/src/tests/run_long_federation_sys_tests | 24 + cpp/src/tests/run_msg_group_tests | 66 + cpp/src/tests/run_msg_group_tests_soak | 60 + cpp/src/tests/run_queue_flow_limit_tests | 57 + cpp/src/tests/run_store_tests.ps1 | 2 +- cpp/src/tests/run_test | 2 +- cpp/src/tests/sasl.mk | 16 +- cpp/src/tests/sasl_fed | 2 +- cpp/src/tests/sasl_fed_ex | 306 +++- cpp/src/tests/sasl_fed_ex_dynamic | 27 + cpp/src/tests/sasl_fed_ex_dynamic_cluster | 28 + cpp/src/tests/sasl_fed_ex_link | 27 + cpp/src/tests/sasl_fed_ex_link_cluster | 28 + cpp/src/tests/sasl_fed_ex_queue | 27 + cpp/src/tests/sasl_fed_ex_queue_cluster | 28 + cpp/src/tests/sasl_fed_ex_route | 27 + cpp/src/tests/sasl_fed_ex_route_cluster | 28 + cpp/src/tests/sasl_no_dir | 218 +++ cpp/src/tests/sasl_test_setup.sh | 1 + cpp/src/tests/sender.cpp | 2 +- cpp/src/tests/ssl_test | 36 +- cpp/src/tests/windows/DisableWin32ErrorWindows.cpp | 4 + cpp/src/windows/QpiddBroker.cpp | 4 +- cpp/src/windows/resources/template-resource.rc | 2 +- cpp/src/xml.mk | 2 +- cpp/xml/cluster.xml | 74 +- 697 files changed, 31727 insertions(+), 17926 deletions(-) create mode 100644 cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp create mode 100644 cpp/bindings/qpid/CMakeLists.txt create mode 100644 cpp/bindings/qpid/perl/CMakeLists.txt create mode 100644 cpp/bindings/qpid/python/CMakeLists.txt create mode 100644 cpp/bindings/qpid/ruby/.gitignore create mode 100644 cpp/bindings/qpid/ruby/CMakeLists.txt create mode 100644 cpp/bindings/qpid/ruby/LICENSE create mode 100644 cpp/bindings/qpid/ruby/README.rdoc create mode 100644 cpp/bindings/qpid/ruby/Rakefile create mode 100644 cpp/bindings/qpid/ruby/TODO create mode 100644 cpp/bindings/qpid/ruby/examples/client.rb create mode 100644 cpp/bindings/qpid/ruby/examples/drain.rb create mode 100644 cpp/bindings/qpid/ruby/examples/hello_world.rb create mode 100644 cpp/bindings/qpid/ruby/examples/map_receiver.rb create mode 100644 cpp/bindings/qpid/ruby/examples/map_sender.rb create mode 100644 cpp/bindings/qpid/ruby/examples/server.rb create mode 100644 cpp/bindings/qpid/ruby/examples/spout.rb create mode 100644 cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/address.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/connection.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/duration.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/encoding.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/errors.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/message.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/receiver.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/sender.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/session.rb create mode 100644 cpp/bindings/qpid/ruby/lib/qpid/version.rb create mode 100644 cpp/bindings/qpid/ruby/test/lib/setup.rb create mode 100644 cpp/bindings/qpid/ruby/test/test_address.rb create mode 100644 cpp/bindings/qpid/ruby/test/test_connection.rb create mode 100644 cpp/bindings/qpid/ruby/test/test_encoding.rb create mode 100644 cpp/bindings/qpid/ruby/test/test_message.rb create mode 100644 cpp/bindings/qpid/ruby/test/test_receiver.rb create mode 100644 cpp/bindings/qpid/ruby/test/test_sender.rb create mode 100644 cpp/bindings/qpid/ruby/test/test_session.rb create mode 100644 cpp/bindings/qpid/ruby/test/ts_bindings.rb create mode 100644 cpp/design_docs/hot-standby-design.txt create mode 100644 cpp/docs/man/qpidd.1 delete mode 100644 cpp/examples/README.verify delete mode 100644 cpp/examples/direct/CMakeLists.txt delete mode 100644 cpp/examples/direct/Makefile.am delete mode 100644 cpp/examples/direct/declare_queues.cpp delete mode 100644 cpp/examples/direct/direct_declare_queues.vcproj delete mode 100644 cpp/examples/direct/direct_direct_producer.vcproj delete mode 100644 cpp/examples/direct/direct_listener.vcproj delete mode 100644 cpp/examples/direct/direct_producer.cpp delete mode 100644 cpp/examples/direct/listener.cpp delete mode 100644 cpp/examples/direct/verify delete mode 100644 cpp/examples/direct/verify.in delete mode 100644 cpp/examples/failover/CMakeLists.txt delete mode 100644 cpp/examples/failover/Makefile.am delete mode 100644 cpp/examples/failover/declare_queues.cpp delete mode 100644 cpp/examples/failover/failover_declare_queues.vcproj delete mode 100644 cpp/examples/failover/failover_replaying_sender.vcproj delete mode 100644 cpp/examples/failover/failover_resuming_receiver.vcproj delete mode 100644 cpp/examples/failover/replaying_sender.cpp delete mode 100644 cpp/examples/failover/resuming_receiver.cpp delete mode 100644 cpp/examples/fanout/CMakeLists.txt delete mode 100644 cpp/examples/fanout/Makefile.am delete mode 100644 cpp/examples/fanout/fanout_fanout_producer.vcproj delete mode 100644 cpp/examples/fanout/fanout_listener.vcproj delete mode 100644 cpp/examples/fanout/fanout_producer.cpp delete mode 100644 cpp/examples/fanout/listener.cpp delete mode 100644 cpp/examples/fanout/verify delete mode 100644 cpp/examples/fanout/verify.in delete mode 100644 cpp/examples/old-examples.sln create mode 100644 cpp/examples/old_api/CMakeLists.txt create mode 100644 cpp/examples/old_api/Makefile.am create mode 100644 cpp/examples/old_api/README.verify create mode 100644 cpp/examples/old_api/direct/CMakeLists.txt create mode 100644 cpp/examples/old_api/direct/Makefile.am create mode 100644 cpp/examples/old_api/direct/declare_queues.cpp create mode 100644 cpp/examples/old_api/direct/direct_declare_queues.vcproj create mode 100644 cpp/examples/old_api/direct/direct_direct_producer.vcproj create mode 100644 cpp/examples/old_api/direct/direct_listener.vcproj create mode 100644 cpp/examples/old_api/direct/direct_producer.cpp create mode 100644 cpp/examples/old_api/direct/listener.cpp create mode 100644 cpp/examples/old_api/direct/verify create mode 100644 cpp/examples/old_api/direct/verify.in create mode 100644 cpp/examples/old_api/failover/CMakeLists.txt create mode 100644 cpp/examples/old_api/failover/Makefile.am create mode 100644 cpp/examples/old_api/failover/declare_queues.cpp create mode 100644 cpp/examples/old_api/failover/failover_declare_queues.vcproj create mode 100644 cpp/examples/old_api/failover/failover_replaying_sender.vcproj create mode 100644 cpp/examples/old_api/failover/failover_resuming_receiver.vcproj create mode 100644 cpp/examples/old_api/failover/replaying_sender.cpp create mode 100644 cpp/examples/old_api/failover/resuming_receiver.cpp create mode 100644 cpp/examples/old_api/fanout/CMakeLists.txt create mode 100644 cpp/examples/old_api/fanout/Makefile.am create mode 100644 cpp/examples/old_api/fanout/fanout_fanout_producer.vcproj create mode 100644 cpp/examples/old_api/fanout/fanout_listener.vcproj create mode 100644 cpp/examples/old_api/fanout/fanout_producer.cpp create mode 100644 cpp/examples/old_api/fanout/listener.cpp create mode 100644 cpp/examples/old_api/fanout/verify create mode 100644 cpp/examples/old_api/fanout/verify.in create mode 100644 cpp/examples/old_api/old-examples.sln create mode 100644 cpp/examples/old_api/pub-sub/CMakeLists.txt create mode 100644 cpp/examples/old_api/pub-sub/Makefile.am create mode 100644 cpp/examples/old_api/pub-sub/pub-sub_topic_listener.vcproj create mode 100644 cpp/examples/old_api/pub-sub/pub-sub_topic_publisher.vcproj create mode 100644 cpp/examples/old_api/pub-sub/topic_listener.cpp create mode 100644 cpp/examples/old_api/pub-sub/topic_publisher.cpp create mode 100644 cpp/examples/old_api/pub-sub/verify create mode 100644 cpp/examples/old_api/pub-sub/verify.in create mode 100644 cpp/examples/old_api/request-response/CMakeLists.txt create mode 100644 cpp/examples/old_api/request-response/Makefile.am create mode 100644 cpp/examples/old_api/request-response/client.cpp create mode 100644 cpp/examples/old_api/request-response/request-response_client.vcproj create mode 100644 cpp/examples/old_api/request-response/request-response_server.vcproj create mode 100644 cpp/examples/old_api/request-response/server.cpp create mode 100644 cpp/examples/old_api/request-response/verify create mode 100644 cpp/examples/old_api/request-response/verify.in create mode 100644 cpp/examples/old_api/tradedemo/CMakeLists.txt create mode 100644 cpp/examples/old_api/tradedemo/Makefile.am create mode 100644 cpp/examples/old_api/tradedemo/declare_queues.cpp create mode 100644 cpp/examples/old_api/tradedemo/topic_listener.cpp create mode 100644 cpp/examples/old_api/tradedemo/topic_publisher.cpp create mode 100644 cpp/examples/old_api/tradedemo/tradedemo_declare_queues.vcproj create mode 100644 cpp/examples/old_api/tradedemo/tradedemo_topic_listener.vcproj create mode 100644 cpp/examples/old_api/tradedemo/tradedemo_topic_publisher.vcproj create mode 100755 cpp/examples/old_api/verify create mode 100755 cpp/examples/old_api/verify_all create mode 100644 cpp/examples/old_api/xml-exchange/CMakeLists.txt create mode 100644 cpp/examples/old_api/xml-exchange/Makefile.am create mode 100644 cpp/examples/old_api/xml-exchange/README.txt create mode 100644 cpp/examples/old_api/xml-exchange/declare_queues.cpp create mode 100644 cpp/examples/old_api/xml-exchange/listener.cpp create mode 100644 cpp/examples/old_api/xml-exchange/xml_producer.cpp delete mode 100644 cpp/examples/pub-sub/CMakeLists.txt delete mode 100644 cpp/examples/pub-sub/Makefile.am delete mode 100644 cpp/examples/pub-sub/pub-sub_topic_listener.vcproj delete mode 100644 cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj delete mode 100644 cpp/examples/pub-sub/topic_listener.cpp delete mode 100644 cpp/examples/pub-sub/topic_publisher.cpp delete mode 100644 cpp/examples/pub-sub/verify delete mode 100644 cpp/examples/pub-sub/verify.in delete mode 100644 cpp/examples/request-response/CMakeLists.txt delete mode 100644 cpp/examples/request-response/Makefile.am delete mode 100644 cpp/examples/request-response/client.cpp delete mode 100644 cpp/examples/request-response/request-response_client.vcproj delete mode 100644 cpp/examples/request-response/request-response_server.vcproj delete mode 100644 cpp/examples/request-response/server.cpp delete mode 100644 cpp/examples/request-response/verify delete mode 100644 cpp/examples/request-response/verify.in delete mode 100644 cpp/examples/tradedemo/CMakeLists.txt delete mode 100644 cpp/examples/tradedemo/Makefile.am delete mode 100644 cpp/examples/tradedemo/declare_queues.cpp delete mode 100644 cpp/examples/tradedemo/topic_listener.cpp delete mode 100644 cpp/examples/tradedemo/topic_publisher.cpp delete mode 100644 cpp/examples/tradedemo/tradedemo_declare_queues.vcproj delete mode 100644 cpp/examples/tradedemo/tradedemo_topic_listener.vcproj delete mode 100644 cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj delete mode 100755 cpp/examples/verify delete mode 100755 cpp/examples/verify_all delete mode 100644 cpp/examples/xml-exchange/CMakeLists.txt delete mode 100644 cpp/examples/xml-exchange/Makefile.am delete mode 100644 cpp/examples/xml-exchange/README.txt delete mode 100644 cpp/examples/xml-exchange/declare_queues.cpp delete mode 100644 cpp/examples/xml-exchange/listener.cpp delete mode 100644 cpp/examples/xml-exchange/xml_producer.cpp create mode 100644 cpp/include/qmf/posix/EventNotifier.h create mode 100644 cpp/include/qpid/ImportExport.h create mode 100644 cpp/src/qmf/AgentSessionImpl.h create mode 100644 cpp/src/qmf/EventNotifierImpl.cpp create mode 100644 cpp/src/qmf/EventNotifierImpl.h create mode 100644 cpp/src/qmf/PosixEventNotifier.cpp create mode 100644 cpp/src/qmf/PosixEventNotifierImpl.cpp create mode 100644 cpp/src/qmf/PosixEventNotifierImpl.h create mode 100644 cpp/src/qpid/BufferRef.h create mode 100644 cpp/src/qpid/DisableExceptionLogging.h create mode 100644 cpp/src/qpid/broker/AsyncCompletion.h create mode 100644 cpp/src/qpid/broker/FifoDistributor.cpp create mode 100644 cpp/src/qpid/broker/FifoDistributor.h delete mode 100644 cpp/src/qpid/broker/IncompleteMessageList.cpp delete mode 100644 cpp/src/qpid/broker/IncompleteMessageList.h create mode 100644 cpp/src/qpid/broker/MessageDistributor.h create mode 100644 cpp/src/qpid/broker/MessageGroupManager.cpp create mode 100644 cpp/src/qpid/broker/MessageGroupManager.h create mode 100644 cpp/src/qpid/broker/QueueFlowLimit.cpp create mode 100644 cpp/src/qpid/broker/QueueFlowLimit.h delete mode 100644 cpp/src/qpid/broker/RateTracker.cpp delete mode 100644 cpp/src/qpid/broker/RateTracker.h create mode 100644 cpp/src/qpid/broker/StatefulQueueObserver.h delete mode 100644 cpp/src/qpid/client/amqp0_10/SimpleUrlParser.cpp delete mode 100644 cpp/src/qpid/client/amqp0_10/SimpleUrlParser.h mode change 100755 => 100644 cpp/src/qpid/sys/windows/Socket.cpp create mode 100644 cpp/src/qpid/sys/windows/mingw32_compat.h create mode 100644 cpp/src/tests/BrokerOptions.cpp delete mode 100644 cpp/src/tests/IncompleteMessageList.cpp create mode 100644 cpp/src/tests/QueueFlowLimitTest.cpp delete mode 100644 cpp/src/tests/SocketProxy.h create mode 100755 cpp/src/tests/federation_sys.py create mode 100755 cpp/src/tests/ipv6_test create mode 100644 cpp/src/tests/msg_group_test.cpp delete mode 100644 cpp/src/tests/qrsh.cpp delete mode 100644 cpp/src/tests/qrsh_run.cpp delete mode 100644 cpp/src/tests/qrsh_server.cpp delete mode 100755 cpp/src/tests/qrsh_utils/10_all delete mode 100755 cpp/src/tests/qrsh_utils/1_remote_run delete mode 100755 cpp/src/tests/qrsh_utils/2_forever delete mode 100755 cpp/src/tests/qrsh_utils/3_kill_it delete mode 100755 cpp/src/tests/qrsh_utils/4_wait_for_it delete mode 100755 cpp/src/tests/qrsh_utils/5_exited delete mode 100755 cpp/src/tests/qrsh_utils/6_get delete mode 100755 cpp/src/tests/qrsh_utils/7_get_output delete mode 100755 cpp/src/tests/qrsh_utils/8_any delete mode 100755 cpp/src/tests/qrsh_utils/9_alias delete mode 100644 cpp/src/tests/qrsh_utils/qrsh_example_command.cpp delete mode 100644 cpp/src/tests/qrsh_utils/qrsh_forever.cpp delete mode 100644 cpp/src/tests/qrsh_utils/qsh_doc.txt create mode 100644 cpp/src/tests/queue_flow_limit_tests.py create mode 100755 cpp/src/tests/run_federation_sys_tests create mode 100644 cpp/src/tests/run_long_federation_sys_tests create mode 100755 cpp/src/tests/run_msg_group_tests create mode 100755 cpp/src/tests/run_msg_group_tests_soak create mode 100755 cpp/src/tests/run_queue_flow_limit_tests create mode 100755 cpp/src/tests/sasl_fed_ex_dynamic create mode 100755 cpp/src/tests/sasl_fed_ex_dynamic_cluster create mode 100755 cpp/src/tests/sasl_fed_ex_link create mode 100755 cpp/src/tests/sasl_fed_ex_link_cluster create mode 100755 cpp/src/tests/sasl_fed_ex_queue create mode 100755 cpp/src/tests/sasl_fed_ex_queue_cluster create mode 100755 cpp/src/tests/sasl_fed_ex_route create mode 100755 cpp/src/tests/sasl_fed_ex_route_cluster create mode 100755 cpp/src/tests/sasl_no_dir (limited to 'cpp') diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 5c37ecfc97..17411e90a4 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -80,6 +80,7 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY "qpidc-${qpidc_version}") add_subdirectory(managementgen) add_subdirectory(etc) add_subdirectory(src) +add_subdirectory(bindings/qpid) add_subdirectory(docs/api) # add_subdirectory(docs/man) add_subdirectory(examples) diff --git a/cpp/INSTALL b/cpp/INSTALL index 6483d7de4e..dbd41c7cc1 100644 --- a/cpp/INSTALL +++ b/cpp/INSTALL @@ -47,9 +47,9 @@ Redhat Linux 3, will almost certainly require some packages to be upgraded. ==================== The following libraries and header files must be installed to build a source distribution: - * boost (1.35)(*) - * e2fsprogs (1.39) - * pkgconfig (0.21) + * boost (1.35)(*) + * libuuid (2.19) + * pkgconfig (0.21) (*) earlier versions of boost e.g. 1.33 also work and there is a patch to get 1.32 working in the svn tree though that is only recommended as @@ -96,12 +96,12 @@ the following must also be installed: * python-devel * swig (1.3.35) -UUID problems: -In some later Linux releases (such as Fedora 12), the uuid/uuid.h file has been -moved from e2fsprogs-devel into libuuid-devel. If you are using a newer Linux -release and run into a problem during configure in which uuid.h cannot be found, -look for and install the libuuid-devel package. - +UUID problems: +In some earlier Linux releases (such as Fedora 11), the uuid/uuid.h +file is located in the e2fsprogs-devel package instead of +libuuid-devel. If you are using an older Linux release and run into a +problem during configure in which uuid.h cannot be found, install the +e2fsprogs-devel package. 2.2. How to Install =================== @@ -112,7 +112,7 @@ look for and install the libuuid-devel package. On linux most packages can be installed using your distribution's package management tool. For example on Fedora: - # yum install boost-devel e2fsprogs-devel pkgconfig gcc-c++ make autoconf automake ruby libtool help2man doxygen graphviz + # yum install boost-devel libuuid-devel pkgconfig gcc-c++ make autoconf automake ruby libtool help2man doxygen graphviz The optional clustering packages changed name in Fedora 10. On Fedora 9 or earlier: # yum install openais-devel cman-devel diff --git a/cpp/INSTALL-WINDOWS b/cpp/INSTALL-WINDOWS index 964d644a7a..75fa69079e 100644 --- a/cpp/INSTALL-WINDOWS +++ b/cpp/INSTALL-WINDOWS @@ -64,7 +64,7 @@ manually installed to non-standard locations. For example: It is also necessary to set BOOST_ROOT to refer to the base of your Boost installation. The Visual Studio projects refer to it. For example: - # set BOOST_ROOT=C:\Program Files\boost\boost_1_35_0 + # set BOOST_ROOT="C:\Program Files\boost\boost_1_35_0" 3. Building from a Source Distribution @@ -75,7 +75,7 @@ Visual Studio solution file which is generated by CMake. From a command prompt: # cd qpid\cpp - # cmake -i + # cmake -i -G "Visual Studio 9 2008" . Output from CMake includes .h files in the include directory, .vcproj files for executables and dlls, and the qpid-cpp.sln solution file. @@ -120,7 +120,12 @@ files that are part of the build. Configure again. Repeat until all the Cache Values are gray. - Click the OK button to generate the project/make files. -Now follow instruction for building from a source distribution in step (3). +Open the qpid-cpp.sln solution located in the build directory, select Debug +or Release, and build. You can build both Release and Debug from the same +project. + +If you build all the projects you can then "Build" the RUN_TESTS project. +This will run the test suite against the Qpid version just built. 5. Tests diff --git a/cpp/Makefile.am b/cpp/Makefile.am index 01b8507454..9f4b8e2082 100644 --- a/cpp/Makefile.am +++ b/cpp/Makefile.am @@ -33,3 +33,7 @@ SUBDIRS = managementgen etc src docs/api docs/man examples bindings/qmf bindings # Update libtool, if needed. libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status --recheck + +check-long: all + $(MAKE) -C src/tests check-long + \ No newline at end of file diff --git a/cpp/bindings/qmf/python/Makefile.am b/cpp/bindings/qmf/python/Makefile.am index 421590f189..8abad32959 100644 --- a/cpp/bindings/qmf/python/Makefile.am +++ b/cpp/bindings/qmf/python/Makefile.am @@ -30,11 +30,13 @@ BUILT_SOURCES = $(generated_file_list) SWIG_FLAGS = -w362,401 $(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmfengine.i - swig -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o qmfengine.cpp $(srcdir)/python.i + $(SWIG) -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o qmfengine.cpp $(srcdir)/python.i pylibdir = $(PYTHON_LIB) lib_LTLIBRARIES = _qmfengine.la +qenginedir = $(pyexecdir) +qengine_PYTHON = qmfengine.py qmf.py #_qmfengine_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)" #_qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".so" diff --git a/cpp/bindings/qmf/ruby/Makefile.am b/cpp/bindings/qmf/ruby/Makefile.am index cfb3a33870..de8c4d10d5 100644 --- a/cpp/bindings/qmf/ruby/Makefile.am +++ b/cpp/bindings/qmf/ruby/Makefile.am @@ -35,9 +35,9 @@ qmfengine.cpp: $(srcdir)/ruby.i $(srcdir)/../qmfengine.i rubylibarchdir = $(RUBY_LIB_ARCH) rubylibarch_LTLIBRARIES = qmfengine.la -qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)" +qmfengine_la_LDFLAGS = -avoid-version -module -shared -shrext ".$(RUBY_DLEXT)" qmfengine_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfengine.la -qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) +qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) -fno-strict-aliasing nodist_qmfengine_la_SOURCES = qmfengine.cpp CLEANFILES = qmfengine.cpp diff --git a/cpp/bindings/qmf/tests/test_base.rb b/cpp/bindings/qmf/tests/test_base.rb index 3e4337a9c0..7d4609097c 100644 --- a/cpp/bindings/qmf/tests/test_base.rb +++ b/cpp/bindings/qmf/tests/test_base.rb @@ -24,6 +24,7 @@ require 'socket' class ConsoleTestBase < Qmf::ConsoleHandler def initialize + sleep(2) @settings = Qmf::ConnectionSettings.new @settings.host = ARGV[0] if ARGV.size > 0 @settings.port = ARGV[1].to_i if ARGV.size > 1 @@ -67,7 +68,7 @@ class ConsoleTestBase < Qmf::ConsoleHandler def assert(condition, in_text=nil) text = " (#{in_text})" if in_text - raise "Assertion failed: #{left} != #{right}#{text}" unless condition + raise "Assertion failed: #{condition} #{text}" unless condition end def fail(text) diff --git a/cpp/bindings/qmf2/examples/cpp/Makefile.am b/cpp/bindings/qmf2/examples/cpp/Makefile.am index 84207d43c4..062fbd0a85 100644 --- a/cpp/bindings/qmf2/examples/cpp/Makefile.am +++ b/cpp/bindings/qmf2/examples/cpp/Makefile.am @@ -21,7 +21,7 @@ INCLUDE = -I$(top_srcdir)/include AM_CPPFLAGS = $(INCLUDE) -noinst_PROGRAMS=agent list_agents print_events +noinst_PROGRAMS=agent event_driven_list_agents list_agents print_events agent_SOURCES=agent.cpp agent_LDADD=$(top_builddir)/src/libqmf2.la @@ -29,5 +29,8 @@ agent_LDADD=$(top_builddir)/src/libqmf2.la list_agents_SOURCES=list_agents.cpp list_agents_LDADD=$(top_builddir)/src/libqmf2.la +event_driven_list_agents_SOURCES=event_driven_list_agents.cpp +event_driven_list_agents_LDADD=$(top_builddir)/src/libqmf2.la + print_events_SOURCES=print_events.cpp print_events_LDADD=$(top_builddir)/src/libqmf2.la diff --git a/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp b/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp new file mode 100644 index 0000000000..c288aa6bdd --- /dev/null +++ b/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp @@ -0,0 +1,107 @@ +/* + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include "qmf/posix/EventNotifier.h" + +#include +#include + +using namespace std; +using namespace qmf; +using qpid::types::Variant; +using qpid::messaging::Duration; + +int main(int argc, char** argv) +{ + string url("localhost"); + string connectionOptions; + string sessionOptions; + + if (argc > 1) + url = argv[1]; + if (argc > 2) + connectionOptions = argv[2]; + if (argc > 3) + sessionOptions = argv[3]; + + qpid::messaging::Connection connection(url, connectionOptions); + connection.open(); + + ConsoleSession session(connection, sessionOptions); + session.open(); + session.setAgentFilter(""); + + posix::EventNotifier notifier(session); + + int fd(notifier.getHandle()); + time_t lastUpdate; + bool ftl = false; + + time(&lastUpdate); + + while (true) { + fd_set rfds; + struct timeval tv; + int nfds, retval; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + nfds = fd + 1; + tv.tv_sec = 10; + tv.tv_usec = 0; + + retval = select(nfds, &rfds, NULL, NULL, &tv); + + if (retval > 0 && FD_ISSET(fd, &rfds)) { + ConsoleEvent event; + while (session.nextEvent(event, Duration::IMMEDIATE)) { + string eventType = ""; + switch(event.getType()) { + case CONSOLE_AGENT_ADD: eventType = "Added"; break; + case CONSOLE_AGENT_DEL: eventType = "Deleted"; break; + case CONSOLE_AGENT_RESTART: eventType = "Restarted"; break; + case CONSOLE_AGENT_SCHEMA_UPDATE: eventType = "Schema Updated"; break; + case CONSOLE_AGENT_SCHEMA_RESPONSE: eventType = "Schema Response"; break; + case CONSOLE_EVENT: eventType = "Event"; break; + case CONSOLE_QUERY_RESPONSE: eventType = "Query Response"; break; + case CONSOLE_METHOD_RESPONSE: eventType = "Method Response"; break; + case CONSOLE_EXCEPTION: eventType = "Exception"; break; + case CONSOLE_SUBSCRIBE_ADD: eventType = "Subscription Added"; break; + case CONSOLE_SUBSCRIBE_UPDATE: eventType = "Subscription Updated"; break; + case CONSOLE_SUBSCRIBE_DEL: eventType = "Subscription Deleted" ; break; + case CONSOLE_THREAD_FAILED: eventType = "Thread Failure"; break; + default: eventType = "[UNDEFINED]"; + } + cout << "Agent " << eventType << ": " << event.getAgent().getName() << endl; + } + } else { + cout << "No message received within waiting period." << endl; + } + } +} + diff --git a/cpp/bindings/qmf2/python/Makefile.am b/cpp/bindings/qmf2/python/Makefile.am index 7adc62eddb..3dc04e832f 100644 --- a/cpp/bindings/qmf2/python/Makefile.am +++ b/cpp/bindings/qmf2/python/Makefile.am @@ -30,12 +30,12 @@ BUILT_SOURCES = $(generated_file_list) SWIG_FLAGS = -w362,401 $(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmf2.i $(srcdir)/../../swig_python_typemaps.i - swig -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/python.i + $(SWIG) -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/python.i pylibdir = $(PYTHON_LIB) lib_LTLIBRARIES = _cqmf2.la -cqpiddir = $(pythondir) +cqpiddir = $(pyexecdir) cqpid_PYTHON = qmf2.py cqmf2.py _cqmf2_la_LDFLAGS = -avoid-version -module -shared diff --git a/cpp/bindings/qmf2/qmf2.i b/cpp/bindings/qmf2/qmf2.i index a09a95168f..0f573fe3e6 100644 --- a/cpp/bindings/qmf2/qmf2.i +++ b/cpp/bindings/qmf2/qmf2.i @@ -37,6 +37,7 @@ %} +%include %include %include diff --git a/cpp/bindings/qmf2/ruby/Makefile.am b/cpp/bindings/qmf2/ruby/Makefile.am index ae840f87c6..97bbc6f385 100644 --- a/cpp/bindings/qmf2/ruby/Makefile.am +++ b/cpp/bindings/qmf2/ruby/Makefile.am @@ -34,9 +34,9 @@ rubylibarchdir = $(RUBY_LIB_ARCH) rubylibarch_LTLIBRARIES = cqmf2.la dist_rubylib_DATA = qmf2.rb -cqmf2_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)" +cqmf2_la_LDFLAGS = -avoid-version -module -shared -shrext ".$(RUBY_DLEXT)" cqmf2_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqmf2 $(top_builddir)/src/libqmf2.la -cqmf2_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) +cqmf2_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) -fno-strict-aliasing nodist_cqmf2_la_SOURCES = cqmf2.cpp CLEANFILES = cqmf2.cpp diff --git a/cpp/bindings/qpid/CMakeLists.txt b/cpp/bindings/qpid/CMakeLists.txt new file mode 100644 index 0000000000..7c9f76f991 --- /dev/null +++ b/cpp/bindings/qpid/CMakeLists.txt @@ -0,0 +1,41 @@ +# +# 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(FindSWIG) +include(UseSWIG) +include(FindRuby) +include(FindPythonLibs) +include(FindPerlLibs) + +if (SWIG_FOUND) + set(CMAKE_SWIG_FLAGS "-w361,362,401,467,503") + + if (PYTHONLIBS_FOUND) + add_subdirectory(python) + endif (PYTHONLIBS_FOUND) + + if (RUBY_FOUND) + add_subdirectory(ruby) + endif (RUBY_FOUND) + + if (PERLLIBS_FOUND) + add_subdirectory(perl) + endif (PERLLIBS_FOUND) +endif (SWIG_FOUND) diff --git a/cpp/bindings/qpid/Makefile.am b/cpp/bindings/qpid/Makefile.am index ca9eda0c73..31bce5d1d5 100644 --- a/cpp/bindings/qpid/Makefile.am +++ b/cpp/bindings/qpid/Makefile.am @@ -21,7 +21,7 @@ SUBDIRS = dotnet if HAVE_SWIG -EXTRA_DIST = qpid.i +EXTRA_DIST = CMakeLists.txt qpid.i if HAVE_RUBY_DEVEL SUBDIRS += ruby diff --git a/cpp/bindings/qpid/dotnet/configure-windows.ps1 b/cpp/bindings/qpid/dotnet/configure-windows.ps1 index 34395911b9..23fc742e07 100644 --- a/cpp/bindings/qpid/dotnet/configure-windows.ps1 +++ b/cpp/bindings/qpid/dotnet/configure-windows.ps1 @@ -24,29 +24,32 @@ # This script configures a qpid\cpp developer build environment under Windows # to enable working with cpp\bindings\qpid\dotnet binding source code. # +# * Supports multiple versions of Visual Studio (VS2008, VS2010) as CMake +# generator. +# # * Supports 32-bit and/or 64-bit development platforms. # # * User chooses in-source or out-of-source build directories. # # - 'In-source' builds happen when CMake is run from directory qpid\cpp. -# Hundreds of CMake-generated output files are placed in qpid\cpp\src. +# Hundreds of CMake-generated output files are placed in qpid\cpp\src. # These files go right on top of files that are part of the source tree # in qpid\cpp\src. -# In-source builds support only one platform. +# In-source builds support only one platform. # Choose only a 32-bit or a 64-bit platform but not both. # # - Out-of-source builds happen when the user chooses another directory # under qpid in which to run CMake. Out-of-source builds are required -# in order to build both x86 and x64 targets using the same source tree. +# in order to build both x86 and x64 targets using the same source tree. # For each build platform (32-bit x86 or Win32, or 64-bit x64) the user -# specifies a build directory and a specific version of Boost. +# specifies a build directory and a specific version of Boost. # Many platform/Boost-version directories may reside side by side. # # * User chooses to run CMake or not. # # - When a new build directory is created then the user is given the -# option of running CMake in that directory. Running CMake is a -# necessary step as CMake creates important source, solution, and +# option of running CMake in that directory. Running CMake is a +# necessary step as CMake creates important source, solution, and # project files. # # - If a directory "looks like" is has already had CMake run in it @@ -63,7 +66,7 @@ # 3. CMake 2.8 (or later) must be installed. The cmake\bin directory # must be in the user's path. # 4. Boost library specifications may or may not be in the user's path. -# The script author recommeds not to have Boost in the path and only +# The script author recommeds not to have Boost in the path and only # allow the Boost path to be specified by generated command procedures. # 5. Visual Studio build environment must be installed. # @@ -90,7 +93,7 @@ # In this example the build dirs are new. The script will prompt # asking if CMake is to run in the build directories. User chooses Yes. # -# Now this script runs CMake twice, once each with the 32-bit and 64-bit +# Now this script runs CMake twice, once each with the 32-bit and 64-bit # generators. # * This step creates qpid-cpp.sln and related project files. # C:\svn\qpid\build32\qpid-cpp.sln @@ -107,7 +110,7 @@ # C:\svn\qpid\build64\setenv-messaging-x64-64bit.bat # # Next the user compiles solution qpid\build32\qpid-cpp.sln. -# +# # Using the generated scripts: # # Case 1. Run an executable in 32-bit mode. @@ -142,6 +145,11 @@ $global:txtPath = '$env:PATH' $global:txtQR = '$env:QPID_BUILD_ROOT' $global:txtWH = 'Write-Host' +############################# +# Visual Studio version selection dialog items and choice +# +[array]$global:VsVersionCmakeChoiceList = "Visual Studio 10", "Visual Studio 9 2008" +$global:cmakeGenerator = '' ############################# # Select-Folder @@ -168,7 +176,7 @@ function AskYesOrNo ($Question="No question?", $Title="No Title?") [Windows.Forms.MessageBoxIcon]::Question) $result = $dlg -eq [Windows.Forms.DialogResult]::Yes - + $result } @@ -188,7 +196,7 @@ function SanityCheckBoostPath ($path=0) $toTest = ('include', 'lib') foreach ($pattern in $toTest) { - $target = Join-Path $path $pattern + $target = Join-Path $path $pattern if (!(Test-Path -path $target)) { $result = $false } @@ -196,7 +204,7 @@ function SanityCheckBoostPath ($path=0) } else { $result = $false } - + if (! $result) { Write-Host "The path ""$displayPath"" does not appear to be a Boost root path." } @@ -219,7 +227,7 @@ function SanityCheckBuildPath ($path=0) $toTest = ('CMakeFiles', 'docs', 'etc', 'examples', 'include', 'managementgen', 'src') foreach ($pattern in $toTest) { - $target = Join-Path $path $pattern + $target = Join-Path $path $pattern if (!(Test-Path -path $target)) { $result = $false } @@ -313,7 +321,7 @@ function WriteDotnetBindingEnvSetupBat $out = @("@ECHO OFF REM -REM Call this command procedure from a command prompt to set up a $vsPlatform ($nBits-bit) +REM Call this command procedure from a command prompt to set up a $vsPlatform ($nBits-bit) REM $slnName environment REM REM > call $outfileName @@ -329,6 +337,56 @@ ECHO Environment set for $slnName $vsPlatform $nBits-bit development. $out | Out-File "$buildRoot\$outfileName" -encoding ASCII } +############################# +# Return the SelectedItem from the dropdown list and close the form. +# +function Return-DropDown { + if ($DropDown.SelectedItem -ne $null) { + $global:cmakeGenerator = $DropDown.SelectedItem.ToString() + $Form.Close() + Write-Host "Selected generator: $global:cmakeGenerator" + } +} + +############################# +# Create the CMake generator form and launch it +# +function SelectCMakeGenerator { + + $Form = New-Object System.Windows.Forms.Form + + $Form.width = 350 + $Form.height = 150 + $Form.Text = ”Select CMake Generator” + + $DropDown = new-object System.Windows.Forms.ComboBox + $DropDown.Location = new-object System.Drawing.Size(120,10) + $DropDown.Size = new-object System.Drawing.Size(150,30) + + ForEach ($Item in $global:VsVersionCmakeChoiceList) { + $DropDown.Items.Add($Item) + } + $DropDown.SelectedIndex = 0 + + $Form.Controls.Add($DropDown) + + $DropDownLabel = new-object System.Windows.Forms.Label + $DropDownLabel.Location = new-object System.Drawing.Size(10,10) + $DropDownLabel.size = new-object System.Drawing.Size(100,20) + $DropDownLabel.Text = "CMake generators" + $Form.Controls.Add($DropDownLabel) + + $Button = new-object System.Windows.Forms.Button + $Button.Location = new-object System.Drawing.Size(120,50) + $Button.Size = new-object System.Drawing.Size(120,20) + $Button.Text = "Select a generator" + $Button.Add_Click({Return-DropDown}) + $form.Controls.Add($Button) + + $Form.Add_Shown({$Form.Activate()}) + $Form.ShowDialog() +} + ############################# # Main @@ -341,6 +399,12 @@ ECHO Environment set for $slnName $vsPlatform $nBits-bit development. [string] $cppDir = Resolve-Path (Join-Path $curDir "..\..\..") [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null +[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null + +############################# +# User dialog to select a version of Visual Studio as CMake generator +# +SelectCMakeGenerator ############################# # User dialog to get optional 32-bit boost and build paths @@ -412,7 +476,7 @@ if ($make32) { $env:BOOST_ROOT = "$boost32" cd "$build32" Write-Host "Running 32-bit CMake in $build32 ..." - CMake -G "Visual Studio 9 2008" "-DCMAKE_INSTALL_PREFIX=install_x86" $cppDir + CMake -G "$global:cmakeGenerator" "-DCMAKE_INSTALL_PREFIX=install_x86" $cppDir } else { Write-Host "Skipped 32-bit CMake." } @@ -424,7 +488,7 @@ if ($make64) { $env:BOOST_ROOT = "$boost64" cd "$build64" Write-Host "Running 64-bit CMake in $build64" - CMake -G "Visual Studio 9 2008 Win64" "-DCMAKE_INSTALL_PREFIX=install_x64" $cppDir + CMake -G "$global:cmakeGenerator Win64" "-DCMAKE_INSTALL_PREFIX=install_x64" $cppDir } else { Write-Host "Skipped 64-bit CMake." } @@ -437,7 +501,7 @@ if ($make64) { if ($defined32) { Write-Host "Writing 32-bit scripts..." - + ########### # Powershell script to launch org.apache.qpid.messaging.sln # @@ -448,8 +512,8 @@ if ($defined32) { -vsPlatform "x86" ` -nBits "32" ` -outfileName "start-devenv-messaging-x86-32bit.ps1" - - + + ########### # Batch script (that you doubleclick) to launch powershell script # that launches org.apache.qpid.messaging.sln. @@ -482,7 +546,7 @@ if ($defined32) { if ($defined64) { Write-Host "Writing 64-bit scripts..." - + ########### # Powershell script to launch org.apache.qpid.messaging.sln # @@ -493,8 +557,8 @@ if ($defined64) { -vsPlatform "x64" ` -nBits "64" ` -outfileName "start-devenv-messaging-x64-64bit.ps1" - - + + ########### # Batch script (that you doubleclick) to launch powershell script # that launches org.apache.qpid.messaging.sln. diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.direct.receiver/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.direct.receiver/Properties/AssemblyInfo.cs index abe35cf053..6976be5d02 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.direct.receiver/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.direct.receiver/Properties/AssemblyInfo.cs @@ -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 @@ -23,7 +23,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("csharp.direct.receiver")] @@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("csharp.direct.receiver")] -[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyCopyright("Copyright 2011")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.direct.sender/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.direct.sender/Properties/AssemblyInfo.cs index 18502a0666..12368def8e 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.direct.sender/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.direct.sender/Properties/AssemblyInfo.cs @@ -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 @@ -23,7 +23,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("csharp.direct.sender")] @@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("csharp.direct.sender")] -[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyCopyright("Copyright 2011")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/Properties/AssemblyInfo.cs index a87f92ccdf..459130ec6c 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/Properties/AssemblyInfo.cs @@ -20,7 +20,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("csharp.map.callback.receiver")] @@ -28,12 +28,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("csharp.map.callback.receiver")] -[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyCopyright("Copyright 2011")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -43,11 +43,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.sender/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.sender/Properties/AssemblyInfo.cs index e633f76673..2be4011f19 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.sender/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.sender/Properties/AssemblyInfo.cs @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("csharp.map.callback.sender")] -[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyCopyright("Copyright 2010")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.map.receiver/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.map.receiver/Properties/AssemblyInfo.cs index 694d6b9ce1..f11ce8c220 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.map.receiver/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.map.receiver/Properties/AssemblyInfo.cs @@ -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 @@ -23,7 +23,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("csharp.map.receiver")] @@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("csharp.map.receiver")] -[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyCopyright("Copyright 2011")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.map.sender/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.map.sender/Properties/AssemblyInfo.cs index ea29ac2417..ee09057f18 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.map.sender/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.map.sender/Properties/AssemblyInfo.cs @@ -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 @@ -23,7 +23,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("csharp.map.sender")] @@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("csharp.map.sender")] -[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyCopyright("Copyright 2011")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/cpp/bindings/qpid/dotnet/examples/visualbasic.example.client/MyProject/AssemblyInfo.vb b/cpp/bindings/qpid/dotnet/examples/visualbasic.example.client/MyProject/AssemblyInfo.vb index d0727fe9fa..469d6ed5cf 100644 --- a/cpp/bindings/qpid/dotnet/examples/visualbasic.example.client/MyProject/AssemblyInfo.vb +++ b/cpp/bindings/qpid/dotnet/examples/visualbasic.example.client/MyProject/AssemblyInfo.vb @@ -6,9 +6,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,34 +21,34 @@ Imports System Imports System.Reflection Imports System.Runtime.InteropServices -' General Information about an assembly is controlled through the following +' General Information about an assembly is controlled through the following ' set of attributes. Change these attribute values to modify the information ' associated with an assembly. ' Review the values of the assembly attributes - - - - - - + + + + + + 'The following GUID is for the ID of the typelib if this project is exposed to COM - + ' Version information for an assembly consists of the following four values: ' ' Major Version -' Minor Version +' Minor Version ' Build Number ' Revision ' -' You can specify all the values or you can default the Build and Revision Numbers +' You can specify all the values or you can default the Build and Revision Numbers ' by using the '*' as shown below: -' +' - - + + diff --git a/cpp/bindings/qpid/dotnet/org.apache.qpid.messaging.sessionreceiver.sln b/cpp/bindings/qpid/dotnet/org.apache.qpid.messaging.sessionreceiver.sln index 90e98a4bbe..edf8af4808 100644 --- a/cpp/bindings/qpid/dotnet/org.apache.qpid.messaging.sessionreceiver.sln +++ b/cpp/bindings/qpid/dotnet/org.apache.qpid.messaging.sessionreceiver.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 -# +# # 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 @@ -8,9 +8,9 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY diff --git a/cpp/bindings/qpid/dotnet/src/Address.cpp b/cpp/bindings/qpid/dotnet/src/Address.cpp index b688d973ed..79a8021d9a 100644 --- a/cpp/bindings/qpid/dotnet/src/Address.cpp +++ b/cpp/bindings/qpid/dotnet/src/Address.cpp @@ -141,7 +141,7 @@ namespace Messaging { } } - // copy constructor + // Copy constructor look-alike (C#) Address::Address(const Address ^ address) { System::Exception ^ newException = nullptr; @@ -163,6 +163,28 @@ namespace Messaging { } } + // Copy constructor implicitly dereferenced (C++) + Address::Address(const Address % address) + { + System::Exception ^ newException = nullptr; + + try + { + addressp = new ::qpid::messaging::Address( + *(const_cast
(address).NativeAddress)); + } + catch (const ::qpid::types::Exception & error) + { + String ^ errmsg = gcnew String(error.what()); + newException = gcnew QpidException(errmsg); + } + + if (newException != nullptr) + { + throw newException; + } + } + // unmanaged clone Address::Address(const ::qpid::messaging::Address & addrp) { diff --git a/cpp/bindings/qpid/dotnet/src/Address.h b/cpp/bindings/qpid/dotnet/src/Address.h index e5a00d8f11..8bbc207d4e 100644 --- a/cpp/bindings/qpid/dotnet/src/Address.h +++ b/cpp/bindings/qpid/dotnet/src/Address.h @@ -64,6 +64,7 @@ namespace Messaging { // copy constructor Address(const Address ^ address); + Address(const Address % address); // unmanaged clone Address(const ::qpid::messaging::Address & addrp); diff --git a/cpp/bindings/qpid/dotnet/src/Connection.cpp b/cpp/bindings/qpid/dotnet/src/Connection.cpp index 69ace7db52..12c0e29f74 100644 --- a/cpp/bindings/qpid/dotnet/src/Connection.cpp +++ b/cpp/bindings/qpid/dotnet/src/Connection.cpp @@ -114,7 +114,7 @@ namespace Messaging { } - // Copy constructor + // Copy constructor look-alike (C#) Connection::Connection(const Connection ^ connection) { System::Exception ^ newException = nullptr; @@ -136,6 +136,28 @@ namespace Messaging { } } + // Copy constructor implicitly dereferenced (C++) + Connection::Connection(const Connection % connection) + { + System::Exception ^ newException = nullptr; + + try + { + connectionp = new ::qpid::messaging::Connection( + *(const_cast(connection).NativeConnection)); + } + catch (const ::qpid::types::Exception & error) + { + String ^ errmsg = gcnew String(error.what()); + newException = gcnew QpidException(errmsg); + } + + if (newException != nullptr) + { + throw newException; + } + } + // Destructor Connection::~Connection() diff --git a/cpp/bindings/qpid/dotnet/src/Connection.h b/cpp/bindings/qpid/dotnet/src/Connection.h index f9b62d4a08..0788f5d225 100644 --- a/cpp/bindings/qpid/dotnet/src/Connection.h +++ b/cpp/bindings/qpid/dotnet/src/Connection.h @@ -56,6 +56,7 @@ namespace Messaging { // copy constructor Connection(const Connection ^ connection); + Connection(const Connection % connection); // unmanaged clone // not defined diff --git a/cpp/bindings/qpid/dotnet/src/Duration.h b/cpp/bindings/qpid/dotnet/src/Duration.h index 213c338a59..d4239fae88 100644 --- a/cpp/bindings/qpid/dotnet/src/Duration.h +++ b/cpp/bindings/qpid/dotnet/src/Duration.h @@ -81,7 +81,17 @@ namespace Messaging { Duration ^ result = gcnew Duration(multiplier * dur->Milliseconds); return result; } - }; + + static bool operator == (Duration ^ a, Duration ^ b) + { + return a->Milliseconds == b->Milliseconds; + } + + static bool operator != (Duration ^ a, Duration ^ b) + { + return a->Milliseconds != b->Milliseconds; + } +}; public ref class DurationConstants sealed { diff --git a/cpp/bindings/qpid/dotnet/src/FailoverUpdates.h b/cpp/bindings/qpid/dotnet/src/FailoverUpdates.h index 1dd92b8688..d82e276fc8 100644 --- a/cpp/bindings/qpid/dotnet/src/FailoverUpdates.h +++ b/cpp/bindings/qpid/dotnet/src/FailoverUpdates.h @@ -54,6 +54,7 @@ namespace Messaging { // copy constructor FailoverUpdates(const FailoverUpdates ^ failoverUpdates) {} + FailoverUpdates(const FailoverUpdates % failoverUpdates) {} // assignment operator FailoverUpdates % operator=(const FailoverUpdates % rhs) diff --git a/cpp/bindings/qpid/dotnet/src/Message.cpp b/cpp/bindings/qpid/dotnet/src/Message.cpp index fe7825134d..e5dbf845b3 100644 --- a/cpp/bindings/qpid/dotnet/src/Message.cpp +++ b/cpp/bindings/qpid/dotnet/src/Message.cpp @@ -235,7 +235,7 @@ namespace Messaging { } } - // Copy constructor + // Copy constructor look-alike (C#) Message::Message(const Message ^ message) { System::Exception ^ newException = nullptr; @@ -257,7 +257,29 @@ namespace Messaging { } } - // Property + // Copy constructor implicitly dereferenced (C++) + Message::Message(const Message % message) + { + System::Exception ^ newException = nullptr; + + try + { + messagep = new ::qpid::messaging::Message( + *(const_cast(message).NativeMessage)); + } + catch (const ::qpid::types::Exception & error) + { + String ^ errmsg = gcnew String(error.what()); + newException = gcnew QpidException(errmsg); + } + + if (newException != nullptr) + { + throw newException; + } + } + + // Property void Message::SetProperty(System::String ^ name, System::Object ^ value) { System::Exception ^ newException = nullptr; diff --git a/cpp/bindings/qpid/dotnet/src/Message.h b/cpp/bindings/qpid/dotnet/src/Message.h index b92cc4200b..ac7f285fe5 100644 --- a/cpp/bindings/qpid/dotnet/src/Message.h +++ b/cpp/bindings/qpid/dotnet/src/Message.h @@ -71,6 +71,7 @@ namespace Messaging { // Copy constructor Message(const Message ^ message); + Message(const Message % message); // unmanaged clone Message(const ::qpid::messaging::Message & msgp); diff --git a/cpp/bindings/qpid/dotnet/src/Receiver.cpp b/cpp/bindings/qpid/dotnet/src/Receiver.cpp index 3c0d79b393..8aa77effbd 100644 --- a/cpp/bindings/qpid/dotnet/src/Receiver.cpp +++ b/cpp/bindings/qpid/dotnet/src/Receiver.cpp @@ -89,7 +89,7 @@ namespace Messaging { } - // Copy constructor + // Copy constructor look-alike (C#) Receiver::Receiver(const Receiver ^ receiver) : parentSession(receiver->parentSession) { @@ -112,6 +112,29 @@ namespace Messaging { } } + // Copy constructor implicitly dereferenced (C++) + Receiver::Receiver(const Receiver % receiver) : + parentSession(receiver.parentSession) + { + System::Exception ^ newException = nullptr; + + try + { + receiverp = new ::qpid::messaging::Receiver( + *(const_cast(receiver).NativeReceiver)); + } + catch (const ::qpid::types::Exception & error) + { + String ^ errmsg = gcnew String(error.what()); + newException = gcnew QpidException(errmsg); + } + + if (newException != nullptr) + { + throw newException; + } + } + // // Get(message) diff --git a/cpp/bindings/qpid/dotnet/src/Receiver.h b/cpp/bindings/qpid/dotnet/src/Receiver.h index e9912a61dd..8ddcc9ac01 100644 --- a/cpp/bindings/qpid/dotnet/src/Receiver.h +++ b/cpp/bindings/qpid/dotnet/src/Receiver.h @@ -65,6 +65,7 @@ namespace Messaging { // copy constructor Receiver(const Receiver ^ receiver); + Receiver(const Receiver % receiver); // unmanaged clone // undefined diff --git a/cpp/bindings/qpid/dotnet/src/Sender.cpp b/cpp/bindings/qpid/dotnet/src/Sender.cpp index 584075ef5f..3225f1a6e1 100644 --- a/cpp/bindings/qpid/dotnet/src/Sender.cpp +++ b/cpp/bindings/qpid/dotnet/src/Sender.cpp @@ -84,7 +84,7 @@ namespace Messaging { } - // Copy constructor + // Copy constructor look-alike (C#) Sender::Sender(const Sender ^ sender) : parentSession(sender->parentSession) { @@ -107,6 +107,29 @@ namespace Messaging { } } + // Copy constructor implicitly dereferenced (C++) + Sender::Sender(const Sender % sender) + : parentSession(sender.parentSession) + { + System::Exception ^ newException = nullptr; + + try + { + senderp = new ::qpid::messaging::Sender( + *(const_cast(sender).NativeSender)); + } + catch (const ::qpid::types::Exception & error) + { + String ^ errmsg = gcnew String(error.what()); + newException = gcnew QpidException(errmsg); + } + + if (newException != nullptr) + { + throw newException; + } + } + // // Send(msg) diff --git a/cpp/bindings/qpid/dotnet/src/Sender.h b/cpp/bindings/qpid/dotnet/src/Sender.h index 0e90a9f4a4..4054e87316 100644 --- a/cpp/bindings/qpid/dotnet/src/Sender.h +++ b/cpp/bindings/qpid/dotnet/src/Sender.h @@ -62,6 +62,7 @@ namespace Messaging { // copy constructor Sender(const Sender ^ sender); + Sender(const Sender % sender); ~Sender(); !Sender(); diff --git a/cpp/bindings/qpid/dotnet/src/Session.cpp b/cpp/bindings/qpid/dotnet/src/Session.cpp index 880331c588..0e918769a3 100644 --- a/cpp/bindings/qpid/dotnet/src/Session.cpp +++ b/cpp/bindings/qpid/dotnet/src/Session.cpp @@ -89,7 +89,7 @@ namespace Messaging { } - // Copy constructor + // Copy constructor look-alike (C#) Session::Session(const Session ^ session) : parentConnectionp(session->parentConnectionp) { @@ -113,6 +113,30 @@ namespace Messaging { } } + // Copy constructor implicitly dereferenced (C++) + Session::Session(const Session % session) + : parentConnectionp(session.parentConnectionp) + { + System::Exception ^ newException = nullptr; + + try + { + sessionp = new ::qpid::messaging::Session( + *(const_cast(session).NativeSession)); + + } + catch (const ::qpid::types::Exception & error) + { + String ^ errmsg = gcnew String(error.what()); + newException = gcnew QpidException(errmsg); + } + + if (newException != nullptr) + { + throw newException; + } + } + void Session::Close() { @@ -224,6 +248,31 @@ namespace Messaging { } } + void Session::AcknowledgeUpTo(Message ^ message) + { + AcknowledgeUpTo(message, false); + } + + void Session::AcknowledgeUpTo(Message ^ message, bool sync) + { + System::Exception ^ newException = nullptr; + + try + { + sessionp->acknowledgeUpTo(*(message->NativeMessage), sync); + } + catch (const ::qpid::types::Exception & error) + { + String ^ errmsg = gcnew String(error.what()); + newException = gcnew QpidException(errmsg); + } + + if (newException != nullptr) + { + throw newException; + } + } + void Session::Reject(Message ^ message) { System::Exception ^ newException = nullptr; diff --git a/cpp/bindings/qpid/dotnet/src/Session.h b/cpp/bindings/qpid/dotnet/src/Session.h index 7eaad8a0a5..4b98a37f18 100644 --- a/cpp/bindings/qpid/dotnet/src/Session.h +++ b/cpp/bindings/qpid/dotnet/src/Session.h @@ -69,6 +69,7 @@ namespace Messaging { // copy constructor Session(const Session ^ session); + Session(const Session % session); ~Session(); !Session(); @@ -103,6 +104,8 @@ namespace Messaging { void Acknowledge(bool sync); void Acknowledge(Message ^ message); void Acknowledge(Message ^ message, bool sync); + void AcknowledgeUpTo(Message ^ message); + void AcknowledgeUpTo(Message ^ message, bool sync); void Reject(Message ^); void Release(Message ^); void Sync(); diff --git a/cpp/bindings/qpid/dotnet/test/messaging.test/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/test/messaging.test/Properties/AssemblyInfo.cs index cf50e88200..81a89ce393 100644 --- a/cpp/bindings/qpid/dotnet/test/messaging.test/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/test/messaging.test/Properties/AssemblyInfo.cs @@ -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 @@ -23,7 +23,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("messaging.test")] @@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("messaging.test")] -[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyCopyright("Copyright 2011")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/cpp/bindings/qpid/examples/perl/client.pl b/cpp/bindings/qpid/examples/perl/client.pl index 93eec88e07..19d9d3f14f 100644 --- a/cpp/bindings/qpid/examples/perl/client.pl +++ b/cpp/bindings/qpid/examples/perl/client.pl @@ -20,13 +20,13 @@ use strict; use warnings; -use cqpid; +use cqpid_perl; my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; -my $connection = new cqpid::Connection($url, $connectionOptions); +my $connection = new cqpid_perl::Connection($url, $connectionOptions); eval { $connection->open(); @@ -35,7 +35,7 @@ my $session = $connection->createSession(); my $sender = $session->createSender("service_queue"); #create temp queue & receiver... -my $responseQueue = new cqpid::Address("#response-queue; {create:always, delete:always}"); +my $responseQueue = new cqpid_perl::Address("#response-queue; {create:always, delete:always}"); my $receiver = $session->createReceiver($responseQueue); #Now send some messages... @@ -47,7 +47,7 @@ my @s = ( "And the mome raths outgrabe." ); -my $request = new cqpid::Message(); +my $request = new cqpid_perl::Message(); $request->setReplyTo($responseQueue); for (my $i=0; $i<4; $i++) { $request->setContent($s[$i]); diff --git a/cpp/bindings/qpid/examples/perl/drain.pl b/cpp/bindings/qpid/examples/perl/drain.pl index 8010b7c95b..60ac0c50ed 100644 --- a/cpp/bindings/qpid/examples/perl/drain.pl +++ b/cpp/bindings/qpid/examples/perl/drain.pl @@ -20,7 +20,7 @@ use strict; use warnings; -use cqpid; +use cqpid_perl; use Getopt::Long; my $url = "127.0.0.1"; @@ -47,11 +47,11 @@ if ($#ARGV ge 0) { } sub getTimeout { - return ($forever) ? $cqpid::Duration::FOREVER : new cqpid::Duration($timeout*1000); + return ($forever) ? $cqpid_perl::Duration::FOREVER : new cqpid_perl::Duration($timeout*1000); } -my $connection = new cqpid::Connection($url, $connectionOptions); +my $connection = new cqpid_perl::Connection($url, $connectionOptions); eval { $connection->open(); @@ -59,13 +59,13 @@ eval { my $receiver = $session->createReceiver($address); my $timeout = getTimeout(); - my $message = new cqpid::Message(); + my $message = new cqpid_perl::Message(); my $i = 0; while($receiver->fetch($message, $timeout)) { print "Message(properties=" . $message->getProperties() . ",content='"; if ($message->getContentType() eq "amqp/map") { - my $content = cqpid::decodeMap($message); + my $content = cqpid_perl::decodeMap($message); map{ print "\n$_ => $content->{$_}"; } keys %{$content}; } else { @@ -77,7 +77,7 @@ eval { if ($replyto->getName()) { print "Replying to " . $message->getReplyTo()->str() . "...\n"; my $sender = $session->createSender($replyto); - my $response = new cqpid::Message("received by the server."); + my $response = new cqpid_perl::Message("received by the server."); $sender->send($response); } $session->acknowledge(); diff --git a/cpp/bindings/qpid/examples/perl/hello_world.pl b/cpp/bindings/qpid/examples/perl/hello_world.pl index cf2f05f8b7..a96b98a002 100644 --- a/cpp/bindings/qpid/examples/perl/hello_world.pl +++ b/cpp/bindings/qpid/examples/perl/hello_world.pl @@ -21,13 +21,13 @@ use strict; use warnings; use Data::Dumper; -use cqpid; +use cqpid_perl; my $broker = ( @ARGV > 0 ) ? $ARGV[0] : "localhost:5672"; my $address = ( @ARGV > 1 ) ? $ARGV[0] : "amq.topic"; my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[1] : ""; -my $connection = new cqpid::Connection($broker, $connectionOptions); +my $connection = new cqpid_perl::Connection($broker, $connectionOptions); eval { $connection->open(); @@ -36,12 +36,12 @@ eval { my $receiver = $session->createReceiver($address); my $sender = $session->createSender($address); - $sender->send(new cqpid::Message("Hello world!")); + $sender->send(new cqpid_perl::Message("Hello world!")); - #my $duration = new cqpid::Duration(1000); + #my $duration = new cqpid_perl::Duration(1000); #print ">>>" . $duration->getMilliseconds() . "\n"; - my $message = $receiver->fetch($cqpid::Duration::SECOND); + my $message = $receiver->fetch($cqpid_perl::Duration::SECOND); #$message->setDurable(1); #print "Durable: " . $message->getDurable() . "\n"; diff --git a/cpp/bindings/qpid/examples/perl/hello_xml.pl b/cpp/bindings/qpid/examples/perl/hello_xml.pl index c48a5225c2..cebf2ceee6 100644 --- a/cpp/bindings/qpid/examples/perl/hello_xml.pl +++ b/cpp/bindings/qpid/examples/perl/hello_xml.pl @@ -20,7 +20,7 @@ use strict; use warnings; -use cqpid; +use cqpid_perl; my $broker = ( @ARGV > 0 ) ? $ARGV[0] : "localhost:5672"; my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; @@ -44,7 +44,7 @@ x-bindings: [{ exchange: xml-exchange, key: weather, arguments: { xquery:" $quer END -my $connection = new cqpid::Connection($broker, $connectionOptions); +my $connection = new cqpid_perl::Connection($broker, $connectionOptions); eval { $connection->open(); @@ -52,7 +52,7 @@ eval { my $receiver = $session->createReceiver($address); - my $message = new cqpid::Message(); + my $message = new cqpid_perl::Message(); my $content = < diff --git a/cpp/bindings/qpid/examples/perl/map_receiver.pl b/cpp/bindings/qpid/examples/perl/map_receiver.pl index e3e8a201dd..2e2611e38f 100644 --- a/cpp/bindings/qpid/examples/perl/map_receiver.pl +++ b/cpp/bindings/qpid/examples/perl/map_receiver.pl @@ -21,21 +21,21 @@ use strict; use warnings; use Data::Dumper; -use cqpid; +use cqpid_perl; my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; my $address = ( @ARGV > 1 ) ? $ARGV[0] : "message_queue; {create: always}"; my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[1] : ""; -my $connection = new cqpid::Connection($url, $connectionOptions); +my $connection = new cqpid_perl::Connection($url, $connectionOptions); eval { $connection->open(); my $session = $connection->createSession(); my $receiver = $session->createReceiver($address); - my $content = cqpid::decodeMap($receiver->fetch()); - #my $content = cqpid::decodeList($receiver->fetch()); + my $content = cqpid_perl::decodeMap($receiver->fetch()); + #my $content = cqpid_perl::decodeList($receiver->fetch()); print Dumper($content); diff --git a/cpp/bindings/qpid/examples/perl/map_sender.pl b/cpp/bindings/qpid/examples/perl/map_sender.pl index 095acce0ab..4107cd48b9 100644 --- a/cpp/bindings/qpid/examples/perl/map_sender.pl +++ b/cpp/bindings/qpid/examples/perl/map_sender.pl @@ -21,13 +21,13 @@ use strict; use warnings; use Data::Dumper; -use cqpid; +use cqpid_perl; my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; my $address = ( @ARGV > 1 ) ? $ARGV[1] : "message_queue; {create: always}"; my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[2] : ""; -my $connection = new cqpid::Connection($url, $connectionOptions); +my $connection = new cqpid_perl::Connection($url, $connectionOptions); eval { $connection->open(); @@ -35,13 +35,13 @@ eval { my $session = $connection->createSession(); my $sender = $session->createSender($address); - my $message = new cqpid::Message(); + my $message = new cqpid_perl::Message(); my $content = { id => 987654321, name => "Widget", percent => sprintf("%.2f", 0.99), colours => [ qw (red green white) ], }; - cqpid::encode($content, $message); + cqpid_perl::encode($content, $message); $sender->send($message, 1); $connection->close(); diff --git a/cpp/bindings/qpid/examples/perl/server.pl b/cpp/bindings/qpid/examples/perl/server.pl index 0c64f15c66..b14da565b9 100644 --- a/cpp/bindings/qpid/examples/perl/server.pl +++ b/cpp/bindings/qpid/examples/perl/server.pl @@ -20,13 +20,13 @@ use strict; use warnings; -use cqpid; +use cqpid_perl; my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; -my $connection = new cqpid::Connection($url, $connectionOptions); +my $connection = new cqpid_perl::Connection($url, $connectionOptions); eval { $connection->open(); @@ -41,7 +41,7 @@ eval { my $sender = $session->createSender($address); my $s = $request->getContent(); $s = uc($s); - my $response = new cqpid::Message($s); + my $response = new cqpid_perl::Message($s); $sender->send($response); print "Processed request: " . $request->getContent() . " -> " . $response->getContent() . "\n"; $session->acknowledge(); diff --git a/cpp/bindings/qpid/examples/perl/spout.pl b/cpp/bindings/qpid/examples/perl/spout.pl index 50773a4fe2..7365e732bf 100644 --- a/cpp/bindings/qpid/examples/perl/spout.pl +++ b/cpp/bindings/qpid/examples/perl/spout.pl @@ -20,7 +20,7 @@ use strict; use warnings; -use cqpid; +use cqpid_perl; use Getopt::Long; use Time::Local; @@ -77,19 +77,19 @@ sub setProperties { } } -my $connection = new cqpid::Connection($url, $connectionOptions); +my $connection = new cqpid_perl::Connection($url, $connectionOptions); eval { $connection->open(); my $session = $connection->createSession(); my $sender = $session->createSender($address); - my $message = new cqpid::Message(); + my $message = new cqpid_perl::Message(); setProperties($message) if (@properties); if (@entries) { my $content = {}; setEntries($content); - cqpid::encode($content, $message); + cqpid_perl::encode($content, $message); } elsif ($content) { $message->setContent($content); @@ -98,7 +98,7 @@ eval { my $receiver; if ($replyto) { - my $responseQueue = new cqpid::Address($replyto); + my $responseQueue = new cqpid_perl::Address($replyto); $receiver = $session->createReceiver($responseQueue); $message->setReplyTo($responseQueue); } diff --git a/cpp/bindings/qpid/perl/CMakeLists.txt b/cpp/bindings/qpid/perl/CMakeLists.txt new file mode 100644 index 0000000000..6edaf284b1 --- /dev/null +++ b/cpp/bindings/qpid/perl/CMakeLists.txt @@ -0,0 +1,38 @@ +# +# 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. +# + +##------------------------------------------------------ +## Use Swig to generate a literal binding to the C++ API +##------------------------------------------------------ +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/perl.i PROPERTIES CPLUSPLUS ON) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/perl.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") + +swig_add_module(cqpid_perl perl ${CMAKE_CURRENT_SOURCE_DIR}/perl.i) +swig_link_libraries(cqpid_perl qpidmessaging qpidtypes qmf2 ${PERL_LIBRARY}) + +set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -I${PERL_INCLUDE_PATH} -I${qpid-cpp_SOURCE_DIR}/include") + +##---------------------------------- +## Install the complete Perl binding +##---------------------------------- +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcqpid_perl.so + ${CMAKE_CURRENT_BINARY_DIR}/cqpid_perl.pm + DESTINATION ${PERL_VENDORARCH} + COMPONENT ${QPID_COMPONENT_CLIENT} + ) diff --git a/cpp/bindings/qpid/perl/Makefile.am b/cpp/bindings/qpid/perl/Makefile.am index 982d493ba0..da082896e8 100644 --- a/cpp/bindings/qpid/perl/Makefile.am +++ b/cpp/bindings/qpid/perl/Makefile.am @@ -21,22 +21,22 @@ if HAVE_PERL_DEVEL INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -I$(PERL_INC) -EXTRA_DIST = perl.i -BUILT_SOURCES = cqpid.cpp +EXTRA_DIST = CMakeLists.txt perl.i +BUILT_SOURCES = cqpid_perl.cpp SWIG_FLAGS = -w362,401 -cqpid.cpp: $(srcdir)/perl.i $(srcdir)/../qpid.i $(srcdir)/../../swig_perl_typemaps.i - $(SWIG) -perl -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqpid.cpp $(srcdir)/perl.i +cqpid_perl.cpp: $(srcdir)/perl.i $(srcdir)/../qpid.i $(srcdir)/../../swig_perl_typemaps.i + $(SWIG) -perl -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqpid_perl.cpp $(srcdir)/perl.i -lib_LTLIBRARIES = cqpid.la -cqpid_PERL = cqpid.pm +lib_LTLIBRARIES = libcqpid_perl.la +cqpid_perl_PERL = cqpid_perl.pm -cqpid_la_LDFLAGS = -avoid-version -module -shared -cqpid_la_LIBADD = -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \ +libcqpid_perl_la_LDFLAGS = -avoid-version -shared +libcqpid_perl_la_LIBADD = -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \ $(top_builddir)/src/libqpidmessaging.la $(top_builddir)/src/libqpidtypes.la -cqpid_la_CXXFLAGS = $(INCLUDES) -nodist_cqpid_la_SOURCES = cqpid.cpp +libcqpid_perl_la_CXXFLAGS = $(INCLUDES) -fno-strict-aliasing +nodist_libcqpid_perl_la_SOURCES = cqpid_perl.cpp -CLEANFILES = cqpid.cpp cqpid.pm +CLEANFILES = cqpid_perl.cpp cqpid_perl.pm endif # HAVE_PERL_DEVEL diff --git a/cpp/bindings/qpid/perl/perl.i b/cpp/bindings/qpid/perl/perl.i index b7ae0568b6..38ac91761f 100644 --- a/cpp/bindings/qpid/perl/perl.i +++ b/cpp/bindings/qpid/perl/perl.i @@ -17,7 +17,7 @@ * under the License. */ -%module cqpid +%module cqpid_perl %include "std_string.i" %include "../../swig_perl_typemaps.i" diff --git a/cpp/bindings/qpid/python/CMakeLists.txt b/cpp/bindings/qpid/python/CMakeLists.txt new file mode 100644 index 0000000000..5e4649cd7c --- /dev/null +++ b/cpp/bindings/qpid/python/CMakeLists.txt @@ -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. +# + +##------------------------------------------------------ +## Use Swig to generate a literal binding to the C++ API +##------------------------------------------------------ +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES CPLUSPLUS ON) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") + +swig_add_module(cqpid python ${CMAKE_CURRENT_SOURCE_DIR}/python.i) +swig_link_libraries(cqpid qpidmessaging qpidtypes qmf2 ${PYTHON_LIBRARIES}) + +set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -I${PYTHON_INCLUDE_PATH} -I${qpid-cpp_SOURCE_DIR}/include") + +##------------------------------------ +## Install the complete Python binding +##------------------------------------ +execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE) +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cqpid.py + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cqpid.py + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cqpid.py + ${CMAKE_CURRENT_BINARY_DIR}/cqpid.pyc + ${CMAKE_CURRENT_BINARY_DIR}/cqpid.pyo + ${CMAKE_CURRENT_BINARY_DIR}/_cqpid.so + DESTINATION ${PYTHON_SITE_PACKAGES} + COMPONENT ${QPID_COMPONENT_CLIENT} + ) diff --git a/cpp/bindings/qpid/python/Makefile.am b/cpp/bindings/qpid/python/Makefile.am index 7fa4106be0..dd25f34829 100644 --- a/cpp/bindings/qpid/python/Makefile.am +++ b/cpp/bindings/qpid/python/Makefile.am @@ -25,17 +25,17 @@ generated_file_list = \ cqpid.cpp \ cqpid.py -EXTRA_DIST = python.i +EXTRA_DIST = CMakeLists.txt python.i BUILT_SOURCES = $(generated_file_list) SWIG_FLAGS = -w362,401 $(generated_file_list): $(srcdir)/python.i $(srcdir)/../qpid.i $(srcdir)/../../swig_python_typemaps.i - swig -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o cqpid.cpp $(srcdir)/python.i + $(SWIG) -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o cqpid.cpp $(srcdir)/python.i pylibdir = $(PYTHON_LIB) lib_LTLIBRARIES = _cqpid.la -cqpiddir = $(pythondir) +cqpiddir = $(pyexecdir) cqpid_PYTHON = cqpid.py _cqpid_la_LDFLAGS = -avoid-version -module -shared diff --git a/cpp/bindings/qpid/python/python.i b/cpp/bindings/qpid/python/python.i index bf61cb10b7..9d45bf54ee 100644 --- a/cpp/bindings/qpid/python/python.i +++ b/cpp/bindings/qpid/python/python.i @@ -21,21 +21,357 @@ %include "std_string.i" %include "../../swig_python_typemaps.i" +/* Needed for get/setPriority methods. Surprising SWIG 1.3.40 doesn't + * convert uint8_t by default. */ +%apply unsigned char { uint8_t }; + + +/* + * Exceptions + * + * The convention below is that exceptions in _cqpid.so have the same + * names as in the C++ library. They get renamed to their Python + * equivalents when brought into the Python wrapping + */ +%{ +static PyObject* pNoMessageAvailable; +static PyObject* pTargetCapacityExceeded; +static PyObject* pNotFound; +static PyObject* pTransportFailure; +%} + +%init %{ + pNoMessageAvailable = PyErr_NewException( + "_cqpid.NoMessageAvailable", NULL, NULL); + Py_INCREF(pNoMessageAvailable); + PyModule_AddObject(m, "NoMessageAvailable", pNoMessageAvailable); + + pTargetCapacityExceeded = PyErr_NewException( + "_cqpid.TargetCapacityExceeded", NULL, NULL); + Py_INCREF(pTargetCapacityExceeded); + PyModule_AddObject(m, "TargetCapacityExceeded", pTargetCapacityExceeded); + + pNotFound = PyErr_NewException( + "_cqpid.NotFound", NULL, NULL); + Py_INCREF(pNotFound); + PyModule_AddObject(m, "NotFound", pNotFound); + + pTransportFailure = PyErr_NewException( + "_cqpid.TransportFailure", NULL, NULL); + Py_INCREF(pTransportFailure); + PyModule_AddObject(m, "TransportFailure", pTransportFailure); +%} + +%pythoncode %{ + Empty = _cqpid.NoMessageAvailable + TargetCapacityExceeded = _cqpid.TargetCapacityExceeded + NotFound = _cqpid.NotFound + ConnectError = _cqpid.TransportFailure +%} + /* Define the general-purpose exception handling */ %exception { + PyObject * pExceptionType = NULL; std::string error; Py_BEGIN_ALLOW_THREADS; try { $action + } catch (qpid::messaging::NoMessageAvailable & ex) { + pExceptionType = pNoMessageAvailable; + error = ex.what(); + } catch (qpid::messaging::TargetCapacityExceeded & ex) { + pExceptionType = pTargetCapacityExceeded; + error = ex.what(); + } catch (qpid::messaging::NotFound & ex) { + pExceptionType = pNotFound; + error = ex.what(); + } catch (qpid::messaging::TransportFailure & ex) { + pExceptionType = pTransportFailure; + error = ex.what(); } catch (qpid::types::Exception& ex) { + pExceptionType = PyExc_RuntimeError; error = ex.what(); } Py_END_ALLOW_THREADS; if (!error.empty()) { - PyErr_SetString(PyExc_RuntimeError, error.c_str()); + PyErr_SetString(pExceptionType, error.c_str()); return NULL; } } + +/* This only renames the non-const version (I believe). Then again, I + * don't even know why there is a non-const version of the method. */ +%rename(opened) qpid::messaging::Connection::isOpen(); +%rename(receiver) qpid::messaging::Session::createReceiver; +%rename(sender) qpid::messaging::Session::createSender; +%rename(_acknowledge_all) qpid::messaging::Session::acknowledge(bool); +%rename(_acknowledge_msg) qpid::messaging::Session::acknowledge( + Message &, bool); + +%rename(_fetch) qpid::messaging::Receiver::fetch; +%rename(unsettled) qpid::messaging::Receiver::getUnsettled; +%rename(available) qpid::messaging::Receiver::getAvailable; + +%rename(unsettled) qpid::messaging::Sender::getUnsettled; +%rename(available) qpid::messaging::Sender::getAvailable; +%rename(_send) qpid::messaging::Sender::send; + +%rename(_getReplyTo) qpid::messaging::Message::getReplyTo; +%rename(_setReplyTo) qpid::messaging::Message::setReplyTo; +%rename(_getTtl) qpid::messaging::Message::getTtl; +%rename(_setTtl) qpid::messaging::Message::setTtl; + + %include "../qpid.i" +%extend qpid::messaging::Connection { + %pythoncode %{ + # Handle the different options by converting underscores to hyphens. + # Also, the sasl_mechanisms option in Python has no direct + # equivalent in C++, so we will translate them to sasl_mechanism + # when possible. + def __init__(self, url=None, **options): + args = [url] if url else [] + if options : + if "sasl_mechanisms" in options : + if ' ' in options.get("sasl_mechanisms",'') : + raise Exception( + "C++ Connection objects are unable to handle " + "multiple sasl-mechanisms") + options["sasl_mechanism"] = options.pop("sasl_mechanisms") + args.append(options) + this = _cqpid.new_Connection(*args) + try: self.this.append(this) + except: self.this = this + %} + + /* Return a pre-existing session with the given name, if one + * exists, otherwise return a new one. (Note that if a + * pre-existing session exists, the transactional argument is + * ignored, and the returned session might not satisfy the desired + * setting. */ + qpid::messaging::Session _session(const std::string & name, + bool transactional) { + if (!name.empty()) { + try { + return self->getSession(name); + } + catch (const qpid::messaging::KeyError &) { + } + } + if (transactional) { + return self->createTransactionalSession(name); + } + else { + return self->createSession(name); + } + } + + %pythoncode %{ + def session(self, name=None, transactional=False) : + if name is None : + name = '' + return self._session(name, transactional) + %} + + %pythoncode %{ + @staticmethod + def establish(url=None, **options) : + conn = Connection(url, **options) + conn.open() + return conn + %} +} + +%extend qpid::messaging::Session { + %pythoncode %{ + def acknowledge(self, message=None, disposition=None, sync=True) : + if disposition : + raise Exception("SWIG does not support dispositions yet. Use " + "Session.reject and Session.release instead") + if message : + self._acknowledge_msg(message, sync) + else : + self._acknowledge_all(sync) + + __swig_getmethods__["connection"] = getConnection + if _newclass: connection = _swig_property(getConnection) + %} +} + + +%extend qpid::messaging::Receiver { + %pythoncode %{ + __swig_getmethods__["capacity"] = getCapacity + __swig_setmethods__["capacity"] = setCapacity + if _newclass: capacity = _swig_property(getCapacity, setCapacity) + + __swig_getmethods__["session"] = getSession + if _newclass: session = _swig_property(getSession) + %} + + %pythoncode %{ + def fetch(self, timeout=None) : + if timeout is None : + return self._fetch() + else : + # Python API uses timeouts in seconds, + # but C++ API uses milliseconds + return self._fetch(Duration(int(1000*timeout))) + %} +} + +%extend qpid::messaging::Sender { + %pythoncode %{ + def send(self, object, sync=True) : + if isinstance(object, Message): + message = object + else: + message = Message(object) + return self._send(message, sync) + + __swig_getmethods__["capacity"] = getCapacity + __swig_setmethods__["capacity"] = setCapacity + if _newclass: capacity = _swig_property(getCapacity, setCapacity) + + __swig_getmethods__["session"] = getSession + if _newclass: session = _swig_property(getSession) + %} +} + + +%extend qpid::messaging::Message { + %pythoncode %{ + # UNSPECIFIED was module level before, but I do not + # know how to insert python code at the top of the module. + # (A bare "%pythoncode" inserts at the end. + UNSPECIFIED=object() + def __init__(self, content=None, content_type=UNSPECIFIED, id=None, + subject=None, user_id=None, reply_to=None, + correlation_id=None, durable=None, priority=None, + ttl=None, properties=None): + this = _cqpid.new_Message('') + try: self.this.append(this) + except: self.this = this + if content : + self.content = content + if content_type != UNSPECIFIED : + self.content_type = content_type + if id is not None : + self.id = id + if subject is not None : + self.subject = subject + if user_id is not None : + self.user_id = user_id + if reply_to is not None : + self.reply_to = reply_to + if correlation_id is not None : + self.correlation_id = correlation_id + if durable is not None : + self.durable = durable + if priority is not None : + self.priority = priority + if ttl is not None : + self.ttl = ttl + if properties is not None : + # Can't set properties via (inst).getProperties, because + # the typemaps make a copy of the underlying properties. + # Instead, set via setProperty for the time-being + for k, v in properties.iteritems() : + self.setProperty(k, v) + + def _get_content(self) : + if self.content_type == "amqp/list" : + return decodeList(self) + if self.content_type == "amqp/map" : + return decodeMap(self) + return self.getContent() + def _set_content(self, content) : + if isinstance(content, basestring) : + self.setContent(content) + elif isinstance(content, list) or isinstance(content, dict) : + encode(content, self) + else : + # Not a type we can handle. Try setting it anyway, + # although this will probably lead to a swig error + self.setContent(content) + __swig_getmethods__["content"] = _get_content + __swig_setmethods__["content"] = _set_content + if _newclass: content = _swig_property(_get_content, _set_content) + + __swig_getmethods__["content_type"] = getContentType + __swig_setmethods__["content_type"] = setContentType + if _newclass: content_type = _swig_property(getContentType, + setContentType) + + __swig_getmethods__["id"] = getMessageId + __swig_setmethods__["id"] = setMessageId + if _newclass: id = _swig_property(getMessageId, setMessageId) + + __swig_getmethods__["subject"] = getSubject + __swig_setmethods__["subject"] = setSubject + if _newclass: subject = _swig_property(getSubject, setSubject) + + __swig_getmethods__["priority"] = getPriority + __swig_setmethods__["priority"] = setPriority + if _newclass: priority = _swig_property(getPriority, setPriority) + + def getTtl(self) : + return self._getTtl().getMilliseconds()/1000.0 + def setTtl(self, duration) : + self._setTtl(Duration(int(1000*duration))) + __swig_getmethods__["ttl"] = getTtl + __swig_setmethods__["ttl"] = setTtl + if _newclass: ttl = _swig_property(getTtl, setTtl) + + __swig_getmethods__["user_id"] = getUserId + __swig_setmethods__["user_id"] = setUserId + if _newclass: user_id = _swig_property(getUserId, setUserId) + + __swig_getmethods__["correlation_id"] = getCorrelationId + __swig_setmethods__["correlation_id"] = setCorrelationId + if _newclass: correlation_id = _swig_property(getCorrelationId, + setCorrelationId) + + __swig_getmethods__["redelivered"] = getRedelivered + __swig_setmethods__["redelivered"] = setRedelivered + if _newclass: redelivered = _swig_property(getRedelivered, + setRedelivered) + + __swig_getmethods__["durable"] = getDurable + __swig_setmethods__["durable"] = setDurable + if _newclass: durable = _swig_property(getDurable, setDurable) + + __swig_getmethods__["properties"] = getProperties + if _newclass: properties = _swig_property(getProperties) + + def getReplyTo(self) : + return self._getReplyTo().str() + def setReplyTo(self, address_str) : + self._setReplyTo(Address(address_str)) + __swig_getmethods__["reply_to"] = getReplyTo + __swig_setmethods__["reply_to"] = setReplyTo + if _newclass: reply_to = _swig_property(getReplyTo, setReplyTo) + + def __repr__(self): + args = [] + for name in ["id", "subject", "user_id", "reply_to", + "correlation_id", "priority", "ttl", + "durable", "redelivered", "properties", + "content_type"] : + value = getattr(self, name) + if value : args.append("%s=%r" % (name, value)) + if self.content is not None: + if args: + args.append("content=%r" % self.content) + else: + args.append(repr(self.content)) + return "Message(%s)" % ", ".join(args) + %} +} + +%pythoncode %{ +# Bring into module scope +UNSPECIFIED = Message.UNSPECIFIED +%} diff --git a/cpp/bindings/qpid/qpid.i b/cpp/bindings/qpid/qpid.i index e60ce1ce7c..352bafa3c8 100644 --- a/cpp/bindings/qpid/qpid.i +++ b/cpp/bindings/qpid/qpid.i @@ -27,6 +27,7 @@ #include #include #include +#include // // Wrapper functions for map-decode and list-decode. This allows us to avoid @@ -48,6 +49,7 @@ qpid::types::Variant::List& decodeList(const qpid::messaging::Message& msg) { %} +%include %include %include %include @@ -56,6 +58,7 @@ qpid::types::Variant::List& decodeList(const qpid::messaging::Message& msg) { %include %include %include +%include qpid::types::Variant::Map& decodeMap(const qpid::messaging::Message&); qpid::types::Variant::List& decodeList(const qpid::messaging::Message&); diff --git a/cpp/bindings/qpid/ruby/.gitignore b/cpp/bindings/qpid/ruby/.gitignore new file mode 100644 index 0000000000..ab78513491 --- /dev/null +++ b/cpp/bindings/qpid/ruby/.gitignore @@ -0,0 +1,2 @@ +pkg +html diff --git a/cpp/bindings/qpid/ruby/CMakeLists.txt b/cpp/bindings/qpid/ruby/CMakeLists.txt new file mode 100644 index 0000000000..25258cfc6a --- /dev/null +++ b/cpp/bindings/qpid/ruby/CMakeLists.txt @@ -0,0 +1,63 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +##-------------------------------------------------- +## Properties used for generating the Ruby bindings. +##-------------------------------------------------- +set(GEM_BINDINGS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/cqpid) +set(GEM_BINDINGS_SOURCE_FILE ${GEM_BINDINGS_SOURCE_DIR}/cqpid.cpp) +set(GEM_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) +set(GEM_OUTPUT_FILE ${GEM_OUTPUT_PATH}/pkg/qpid-${qpidc_version}.0.gem) + + +##------------------------------------------------------ +## Use Swig to generate a literal binding to the C++ API +##------------------------------------------------------ +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES CPLUSPLUS ON) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") + +swig_add_module(cqpid ruby ${CMAKE_CURRENT_SOURCE_DIR}/ruby.i) +swig_link_libraries(cqpid qpidmessaging qpidtypes qmf2 ${RUBY_LIBRARY}) + +set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -I${RUBY_INCLUDE_DIR} -I${qpid-cpp_SOURCE_DIR}/include") + +##---------------------------------- +## Install the complete Ruby binding +##---------------------------------- +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcqpid.so + RENAME cqpid.so + DESTINATION ${RUBY_SITEARCH_DIR} + COMPONENT ${QPID_COMPONENT_CLIENT} + ) + +add_custom_command(OUTPUT ${GEM_BINDINGS_SOURCE_FILE} + COMMAND cp ${swig_generated_file_fullname} ${GEM_BINDINGS_SOURCE_FILE} + DEPENDS ${swig_generated_file_fullname} + ) + +add_custom_command(OUTPUT ${GEM_OUTPUT_FILE} + COMMAND OUTPUT_DIR=${GEM_OUTPUT_PATH} rake clean clobber package + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${swig_generated_file_fullname} ${GEM_BINDINGS_SOURCE_FILE} + ) + +add_custom_target(gemfile + DEPENDS ${GEM_OUTPUT_FILE} + ) + diff --git a/cpp/bindings/qpid/ruby/LICENSE b/cpp/bindings/qpid/ruby/LICENSE new file mode 100644 index 0000000000..cff2a5e25d --- /dev/null +++ b/cpp/bindings/qpid/ruby/LICENSE @@ -0,0 +1,234 @@ +========================================================================= +== Apache License == +========================================================================= + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + +========================================================================= +== Boost License == +========================================================================= + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/cpp/bindings/qpid/ruby/Makefile.am b/cpp/bindings/qpid/ruby/Makefile.am index 67a3615362..a2a5dd76bd 100644 --- a/cpp/bindings/qpid/ruby/Makefile.am +++ b/cpp/bindings/qpid/ruby/Makefile.am @@ -21,7 +21,7 @@ if HAVE_RUBY_DEVEL INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -EXTRA_DIST = ruby.i +EXTRA_DIST = CMakeLists.txt ruby.i BUILT_SOURCES = cqpid.cpp SWIG_FLAGS = -w362,401 @@ -33,10 +33,10 @@ cqpid.cpp: $(srcdir)/ruby.i $(srcdir)/../qpid.i $(srcdir)/../../swig_ruby_typema rubylibarchdir = $(RUBY_LIB_ARCH) rubylibarch_LTLIBRARIES = cqpid.la -cqpid_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)" +cqpid_la_LDFLAGS = -avoid-version -module -shared -shrext ".$(RUBY_DLEXT)" cqpid_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \ $(top_builddir)/src/libqpidmessaging.la $(top_builddir)/src/libqpidtypes.la -cqpid_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) +cqpid_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) -fno-strict-aliasing nodist_cqpid_la_SOURCES = cqpid.cpp CLEANFILES = cqpid.cpp diff --git a/cpp/bindings/qpid/ruby/README.rdoc b/cpp/bindings/qpid/ruby/README.rdoc new file mode 100644 index 0000000000..0ae7e5cbed --- /dev/null +++ b/cpp/bindings/qpid/ruby/README.rdoc @@ -0,0 +1,45 @@ += Qpid - Open Source AMQP Messaging + +Qpid is an cross-platform enterprise messaging system. + +Version :: 0.10.0.alpha.0 + += Links + +Documents :: http://qpid.apache.org/ + += Installation + +You can install Qpid with the following command. + + $ gem install qpid + +== Building The Native Code + +The Qpid gem requires that you have available the Qpid libraries and +development header files. To install them, please see: + +http://cwiki.apache.org/qpid/developer-pages.html + +If you are building the gem within the Qpid development environment +itself, you can specify the location of the Qpid headers and +libraries with: + +$ ruby extconfig.rb --with-qpid-lib=[path to libqpidclient.so, etc.] +$ make + +== Examples + +Take a look at the integration tests for examples on how to leverage +the messaging capabilities of Qpid in your Ruby applications. + +== License + +Licensed to the Apache Software Foundation (ASF) under one or more +contributor licensing agreements. + +Author:: Darryl L. Pierce (mailto:dpierce@redhat.com) +Copyright:: Copyright (c) 2011, Red Hat, Inc. +Homepage:: http://qpid.apache.org +License:: Apache License 2.0 - http://www.apache.org/licenses/LICENSE-2.0.html + diff --git a/cpp/bindings/qpid/ruby/Rakefile b/cpp/bindings/qpid/ruby/Rakefile new file mode 100644 index 0000000000..07cfff9844 --- /dev/null +++ b/cpp/bindings/qpid/ruby/Rakefile @@ -0,0 +1,130 @@ +# Rakefile for Qpid -*- ruby -*- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +task :noop + +# look for a root directory for out-of-tree builds + +OUTPUT_DIR=ENV["OUTPUT_DIR"] || "." + +require "rubygems" +require "rubygems/package_task" + +require "rake/clean" +require "rake/extensiontask" +require "rake/rdoctask" +require "rake/testtask" + +CLOBBER.include("pkg") + +load "./lib/qpid/version.rb" + +#------------- +# Gem Details. +#------------- + +NAME = "qpid" +# VERSION = Qpid::VERSION +AUTHOR = "Darryl L. Pierce" +EMAIL = "dpierce@redhat.com" +HOMEPAGE = "http://qpid.apache.org" +SUMMARY = "Qpid is an enterprise messaging framework." + +desc "Default: run all tests." +task :default => :"test:all" + +#--------------- +# Testing tasks. +#--------------- + +desc "Run all tests (alias for test:all)." +task :test => :"test:all" + +namespace :test do + desc "Run all tests (default)." + task :all => [:units, :integrations] + + desc "Run unit tests." + Rake::TestTask.new(:units) do |t| + t.libs << "." + t.pattern = "test/test*.rb" + t.verbose = true + end + + desc "Run integration tests." + Rake::TestTask.new(:integrations) do |t| + t.libs << "." + t.pattern = "test/integration/*.rb" + t.verbose = true + end + +end + +#--------------------- +# Documentation tasks. +#--------------------- + +Rake::RDocTask.new(:rdoc => "rdoc", + :clobber_rdoc => "rdoc:clean", + :rerdoc => "rdoc:force") do |rd| + rd.main = "README.rdoc" + rd.options << "--all" + rd.rdoc_files.include("README.rdoc", "lib/**/*.rb") +end + +#----------------- +# Package the gem. +#----------------- + +spec = Gem::Specification.new do |s| + s.name = NAME + s.version = Qpid::VERSION + s.platform = Gem::Platform::RUBY + s.extra_rdoc_files = ["README.rdoc"] + s.summary = SUMMARY + s.description = s.summary + s.author = AUTHOR + s.email = EMAIL + s.homepage = HOMEPAGE + + s.extensions = FileList["ext/**/extconf.rb"] + + s.require_path = "lib" + # DEPRECATED s.autorequire = NAME + s.files = FileList["LICENSE", + "README.rdoc", + "Rakefile", + "TODO", + "lib/**/*.rb", + "test/**/*.rb", + "examples/**/*.rb", + "ext/**/*"] +end + +Gem::PackageTask.new(spec) do |pkg| + pkg.package_dir = "#{OUTPUT_DIR}/pkg" +end + +#------------------ +# Build native code +#------------------ + +Rake::ExtensionTask.new("cqpid", spec) + diff --git a/cpp/bindings/qpid/ruby/TODO b/cpp/bindings/qpid/ruby/TODO new file mode 100644 index 0000000000..454aac9200 --- /dev/null +++ b/cpp/bindings/qpid/ruby/TODO @@ -0,0 +1,7 @@ +TODO Items +----------------------------------------------------------------------------- + +Version 0.11.0: + * Deliver the Ruby bindings as a gem. + * Rework the blocking tasks to not bring the main thread to a halt. + diff --git a/cpp/bindings/qpid/ruby/examples/client.rb b/cpp/bindings/qpid/ruby/examples/client.rb new file mode 100644 index 0000000000..f42f25cfc9 --- /dev/null +++ b/cpp/bindings/qpid/ruby/examples/client.rb @@ -0,0 +1,50 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'qpid' + +if __FILE__ == $0 + broker = ARGV[1] || "amqp:tcp:localhost:5672" + options = ARGV[2] || "" + + connection = Qpid::Messaging::Connection.new broker, options + connection.open + session = connection.create_session + sender = session.create_sender "service_queue" + response_queue = Qpid::Messaging::Address.new("#response-queue", "", + :create => :always, + :delete => :always) + receiver = session.create_receiver response_queue + + ["Twas brillig, and the slithy toves", + "Did gire and gymble in the wabe.", + "All mimsy were the borogroves,", + "And the mome raths outgrabe."].each do |line| + request = Qpid::Messaging::Message.new :content => line + request.reply_to = response_queue + sender.send request + response = receiver.fetch + puts "#{request.content} -> #{response.content}" + end + + connection.close +end + diff --git a/cpp/bindings/qpid/ruby/examples/drain.rb b/cpp/bindings/qpid/ruby/examples/drain.rb new file mode 100644 index 0000000000..a6cf35e189 --- /dev/null +++ b/cpp/bindings/qpid/ruby/examples/drain.rb @@ -0,0 +1,111 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'qpid' +require 'optparse' + +options = { + :broker => "localhost", + :timeout => Qpid::Messaging::Duration::IMMEDIATE, + :count => 1, + :forever => false, + :connection_options => "" +} + +opts = OptionParser.new do |opts| + opts.banner = "Usage: drain.rb [OPTIONS] ADDRESS" + + opts.separator "" + opts.separator "Drains messages from the specified address" + opts.separator "" + + opts.on("-h", "--help", + "show this message") do + puts opts + exit + end + + opts.on("-b", "--broker VALUE", + "url of broker to connect to") do |broker| + options[:broker] = broker + end + + opts.on("-t", "--timeout VALUE", Integer, + "timeout in seconds to wait before exiting") do |timeout| + options[:timeout] = Qpid::Messaging::Duration.new timeout * 1000 + end + + opts.on("-f", "--forever", + "ignore timeout and wait forever") do + options[:forever] = true + end + + opts.on("--connection-options VALUE", + "connection options string in the form {name1:value,name2:value2}") do |conopts| + options[:connection_options] = conopts + end + + opts.on("-c", "--count VALUE", Integer, + "number of messages to read before exiting") do |count| + options[:count] = count + end +end + +opts.parse!(ARGV) + +options[:address] = ARGV[0] || "" + +connection = Qpid::Messaging::Connection.new options[:broker], options[:connection_options] +connection.open + +def render_map map + print "{" + map.keys.sort.each_with_index {|key,index| print "#{index > 0 ? ', ' : ''}#{key}:#{map[key]}"} + print "}" +end + +begin + session = connection.create_session + receiver = session.create_receiver options[:address] + done = false + count = 0 + options[:timeout] = Qpid::Messaging::Duration::FOREVER if options[:forever] + + while !done && (count < options[:count]) + message = receiver.fetch(options[:timeout]) + print "Message(properties=" + render_map message.properties + print ", content=" + if message.content_type == "amqp/map" + print "'#{render_map message.content}')" + else + print "'#{message.content}'" + end + print ")\n" + session.acknowledge message + count += 1 + end +rescue Exception => error + puts "Exception: #{error.to_s}" +end + +connection.close + diff --git a/cpp/bindings/qpid/ruby/examples/hello_world.rb b/cpp/bindings/qpid/ruby/examples/hello_world.rb new file mode 100644 index 0000000000..703febeba1 --- /dev/null +++ b/cpp/bindings/qpid/ruby/examples/hello_world.rb @@ -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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'qpid' + +# This is your classic Hello World application, written in +# Ruby, that uses Qpid. It demonstrates how to send and +# also receive messages. +# +if __FILE__ == $0 + broker = ARGV[0] || "localhost:5672" + address = ARGV[1] || "amq.topic" + options = ARGV[2] || "" + + connection = Qpid::Messaging::Connection.new broker + connection.open + session = connection.create_session + receiver = session.create_receiver address + sender = session.create_sender address + + # Send a simple message + sender.send Qpid::Messaging::Message.new :content => "Hello world!" + + # Now receive the message + message = receiver.fetch Qpid::Messaging::Duration::SECOND + puts "#{message.content}" + session.acknowledge + + connection.close +end + diff --git a/cpp/bindings/qpid/ruby/examples/map_receiver.rb b/cpp/bindings/qpid/ruby/examples/map_receiver.rb new file mode 100644 index 0000000000..805943a0a4 --- /dev/null +++ b/cpp/bindings/qpid/ruby/examples/map_receiver.rb @@ -0,0 +1,63 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'qpid' + +broker = ARGV[0] || "amqp:tcp:127.0.0.1:5672" +address = ARGV[1] || "message_queue; {create: always}" +options = ARGV[2] || "" + +connection = Qpid::Messaging::Connection.new broker, options +connection.open + +def display_value value + case value + when Array + result = "" + value.each_with_index {|element, index| result += "#{', ' if index > 0}#{element}"} + return "[#{result}]" + end + + value.to_s +end + +begin + session = connection.create_session + receiver = session.create_receiver address + + message = receiver.fetch + content = message.content + + print "content-type:#{message.content_type}" + print "{" + content.keys.sort.each_with_index do |key, index| + print "#{', ' if index > 0}#{key}:#{display_value content[key]}" + end + print "}\n" + + session.acknowledge + +rescue Exception => error + puts "Exception: #{error.message}" +end + +connection.close + diff --git a/cpp/bindings/qpid/ruby/examples/map_sender.rb b/cpp/bindings/qpid/ruby/examples/map_sender.rb new file mode 100644 index 0000000000..fa0c6e4562 --- /dev/null +++ b/cpp/bindings/qpid/ruby/examples/map_sender.rb @@ -0,0 +1,52 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'qpid' + +broker = ARGV[0] || "amqp:tcp:127.0.0.1:5672" +address = ARGV[1] || "message_queue; {create: always}" +options = ARGV[2] || [] + +connection = Qpid::Messaging::Connection.new broker, options +connection.open + +begin + session = connection.create_session + sender = session.create_sender address + message = Qpid::Messaging::Message.new + + content = { + :id => 987654321, + :name => "Widget", + :percent => 0.99, + :colors => ["red", "green", "blue"] + } + + message.content = content + + sender.send message + +rescue Exception => error + puts "Exception: #{error.message}" +end + +connection.close + diff --git a/cpp/bindings/qpid/ruby/examples/server.rb b/cpp/bindings/qpid/ruby/examples/server.rb new file mode 100644 index 0000000000..ead9d58472 --- /dev/null +++ b/cpp/bindings/qpid/ruby/examples/server.rb @@ -0,0 +1,51 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'qpid' + +if __FILE__ == $0 + broker = ARGV[0] || "amqp:tcp:localhost:5672" + options = ARGV[1] || "" + + connection = Qpid::Messaging::Connection.new broker, options + connection.open + session = connection.create_session + receiver = session.create_receiver "service_queue; {create:always}" + + loop do + request = receiver.fetch + address = request.reply_to + + if !address.nil? + sender = session.create_sender address + response = Qpid::Messaging::Message.new :content => request.content.upcase + sender.send response + puts "Processed request: #{request.content} -> #{response.content}" + session.acknowledge + else + puts "Error: no reply address specified for request: #{request.content}" + session.reject request + end + end + + connection.close +end + diff --git a/cpp/bindings/qpid/ruby/examples/spout.rb b/cpp/bindings/qpid/ruby/examples/spout.rb new file mode 100644 index 0000000000..c012e31f9d --- /dev/null +++ b/cpp/bindings/qpid/ruby/examples/spout.rb @@ -0,0 +1,126 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'qpid' +require 'optparse' + +options = { + :broker => "127.0.0.1", + :address => "", + :timeout => 0, + :count => 1, + :properties => {}, + :content => nil, + :mapped => {} +} + +opts = OptionParser.new do |opts| + opts.banner = "Usage: spout.rb [OPTIONS] ADDRESS" + + opts.on("-h", "--help", + "show this message") do |help| + puts opts + exit + end + + opts.on("-b","--broker VALUE", + "url of broker to connect to ") do |broker| + options[:broker] = broker + end + + opts.on("-t", "--timeout VALUE", Integer, + "exit after the specified time") do |timeout| + options[:timeout] = Qpid::Messaging::Duration.new timeout * 1000 + end + + opts.on("-c", "--count VALUE", Integer, + "stop after count messages have been sent, zero disables") do |count| + options[:count] = count + end + + opts.on("-i", "--id VALUE", + "use the supplied id instead of generating one") do |id| + options[:id] = id + end + + opts.on("--reply-to VALUE", + "specify reply-to address") do |replyto| + options[:replyto] = replyto + end + + opts.on("-P", "--property VALUE", + "specify message property") do |property| + name = property.split(/=/)[0] + value = property.split(/=/)[1] + options[:properties][name] = value + end + + opts.on("-M", "--map VALUE", + "specify entry for map content") do |mapped| + name = mapped.split(/=/)[0] + value = mapped.split(/=/)[1] + options[:mapped][name] = value + end + + opts.on("--content VALUE", + "specify textual content") do |content| + options[:content] = content + end + + opts.on(nil, "--connection-options VALUE", + "connection options string in the form {name1:value1, name2:value2}") do |conopts| + options[:connection_options] = conopts + end +end + +begin + opts.parse!(ARGV) +rescue => error + opts.parse(["-h"]) +end + +# now get the non-arg options +options[:address] = ARGV[0] unless ARGV[0].nil? + +connection = Qpid::Messaging::Connection.new options[:broker], options[:connection_options] +connection.open +session = connection.create_session +sender = session.create_sender options[:address] +message = Qpid::Messaging::Message.new + +options[:properties].each_key {|key| message.properties[key] = options[:properties][key]} + +(1..options[:count]).each do |count| + if !options[:mapped].keys.empty? + message.content = options[:mapped] + elsif options[:content] + message.content = options[:content] + end + message.content = options[:content] unless options[:content].nil? + message.properties["spout-id"] = "#{count}" + message.reply_to = options[:replyto] unless options[:replyto].nil? || options[:replyto].empty? + sender.send message +end + +# session.sync + +connection.close + diff --git a/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb b/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb new file mode 100644 index 0000000000..90292d4bec --- /dev/null +++ b/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb @@ -0,0 +1,73 @@ +# +# 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. +# + +# To create the Makefile then you need to specify the location +# of the Qpid shared libraries using the commandline: +# +# $ ruby extconf.rb --with-qpid-lib=[path to libraries] +# + +require 'mkmf' + +# Setup the build environment. +$CFLAGS = "-fPIC -fno-inline -x c++" + +REQUIRED_LIBRARIES = [ + 'qpidclient', + 'qpidcommon', + 'qpidmessaging', + 'qpidtypes' + ] + +REQUIRED_HEADERS = [ + 'qpid/messaging/Address.h', + 'qpid/messaging/Connection.h', + 'qpid/messaging/Duration.h', + 'qpid/messaging/exceptions.h', + 'qpid/messaging/FailoverUpdates.h', + 'qpid/messaging/Handle.h', + 'qpid/messaging/ImportExport.h', + 'qpid/messaging/Message.h', + 'qpid/messaging/Receiver.h', + 'qpid/messaging/Sender.h', + 'qpid/messaging/Session.h' + ] + +dir_config('qpid') + +def abort_build filetype, filename + abort "Missing required #{filetype}: #{filename}" +end + +def require_library lib + abort_build "library", lib unless have_library lib +end + +def require_header header + abort_build "header", header unless have_header header +end + +have_library('stdc++') + +REQUIRED_LIBRARIES.each {|library| require_library library} + +REQUIRED_HEADERS.each {|header| require_header header} + +create_makefile('cqpid') + diff --git a/cpp/bindings/qpid/ruby/lib/qpid.rb b/cpp/bindings/qpid/ruby/lib/qpid.rb new file mode 100644 index 0000000000..1f00c136c1 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid.rb @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'qpid/errors' +require 'qpid/duration' +require 'qpid/address' +require 'qpid/encoding' +require 'qpid/message' +require 'qpid/sender' +require 'qpid/receiver' +require 'qpid/session' +require 'qpid/connection' + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/address.rb b/cpp/bindings/qpid/ruby/lib/qpid/address.rb new file mode 100644 index 0000000000..73b61bb1c7 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/address.rb @@ -0,0 +1,125 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'cqpid' + +module Qpid + + module Messaging + + # Address represents an address to which messages can be sent or from + # which they can be received. + # + # An Address can be described using the following pattern: + # + #
[ / ] ; [ { : , ... } ] + # + # where *address* is a simple name and *subject* is a subject or subject + # pattern. + # + # The options, enclosed in curly braces, are key:value pairs delimited by + # a comma. The values can be nested maps also enclosed in curly braces. + # Or they can be lists of values, where they are contained within square + # brackets but still comma delimited, such as: + # + # [value1,value2,value3] + # + # The following are the list of supported options: + # + # create:: Indicates if the address should be created; values are *always*, + # *never*, *sender* or *reciever*. + # + # assert:: Indicates whether or not to assert any specified node properties; + # values are *always*, *never*, *sender* or *receiver*. + # + # delete:: Indicates whether or not to delete the addressed node when a + # sender or receiver is cancelled; values are *always*, *never*, + # *sender* or *receiver*. + # + # node:: A nested map describing properties for the addressed node. + # Properties are *type* (*topic* or *queue*), *durable* (a boolean), + # *x-declare* (a nested map of amqp 0.10-specific options) and + # *x-bindings*. (nested list which specifies a queue, exchange or + # a binding key and arguments. + # + # link:: A nested map through which properties of the link can be specified; + # properties are *durable*, *reliability*, *x-declare*, *x-subscribe* + # and *x-bindings*. + # + # mode:: (*For receivers only*) indicates whether the receiver should consume + # or browse messages; values are *consume* (the default) and *browse*. + class Address + + def initialize(name, subject, options = {}, _type = "", address_impl = nil) + @address_impl = address_impl || Cqpid::Address.new(name, subject, convert_options(options), _type) + end + + def address_impl # :nodoc: + @address_impl + end + + # Returns the name. + def name; @address_impl.getName; end + + # Sets the name. + def name=(name); @address_impl.setName name; end + + # Returns the subject. + def subject; @address_impl.getSubject; end + + # Sets the subject. + def subject=(subject); @address_impl.setSubject(subject); end + + # Returns the type. + #--- + # We cannot use "type" since that clashes with the Ruby object.type + # identifier. + def _type; @address_impl.getType; end + + # Sets the type. + # + # The type of the address determines how Sender and Receiver objects + # are constructed for it. If no type is specified then it will be + # determined by querying the broker. + def _type=(_type); @address_impl.setType(_type); end + + # Returns the options. + def options; @address_impl.getOptions; end + + # Sets the options for the address. + # Any symbols are converted to strings. + def options=(options); @address_impl.setOptions(convert_options(options)); end + + def to_s; @address_impl.str; end + + private + + def convert_options(options) + result = {} + options.each_pair {|key, value| result[key.to_s] = value.to_s} + + return result + end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/connection.rb b/cpp/bindings/qpid/ruby/lib/qpid/connection.rb new file mode 100644 index 0000000000..5c56c1f5d0 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/connection.rb @@ -0,0 +1,134 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'cqpid' + +module Qpid + + module Messaging + + # Connection allows for establishing connections to a remote endpoint. + class Connection + + # The following general options are supported (as strings or symbols): + # + # username:: + # password:: + # heartbeat:: + # tcp_nodelay:: + # sasl_mechanism:: + # sasl_service:: + # sasl_min_ssf:: + # sasl_max_ssf:: + # transport:: + # + # The following options specifically control reconnection behavior: + # + # reconnect:: *true* or *false*; indicates whether to attempt reconnections + # reconnect_timeout:: the number of seconds to attempt reconnecting + # reconnect_limit:: the number of retries before reporting failure + # reconnect_interval_min:: initial delay, in seconds, before attempting a reconnecting + # reconnect_interval_max:: number of seconds to wait before additional reconnect attempts + # reconnect_interval:: shorthand for setting box min and max values + # reconnect_urls:: a list of alternate URLs to use for reconnection attempts + def initialize(url, options = {}, connection_impl = nil) + @url = url + @connection_impl = connection_impl + @options = options + end + + def connection_impl # :nodoc: + @connection_impl + end + + # Opens the connection. + def open + @connection_impl = Cqpid::Connection.new(@url, convert_options) + @connection_impl.open + end + + # Reports whether the connection is open. + def open?; false || (@connection_impl.isOpen if @connection_impl); end + + # Closes the connection. + def close; @connection_impl.close if open?; end + + # Creates a new session. + # + # If :transactional => true then a transactional session is created. + # Otherwise a standard session is created. + def create_session(args = {}) + name = args[:name] || "" + if open? + if args[:transactional] + session = @connection_impl.createTransactionalSession name + else + session = @connection_impl.createSession name + end + return Session.new(session) + else + raise RuntimeError.new "No connection available." + end + end + + # Returns a session for the specified session name. + def session name + session_impl = @connection_impl.getSession name + Qpid::Messaging::Session.new session_impl if session_impl + end + + # Returns the username used to authenticate with the connection. + def authenticated_username; @connection_impl.getAuthenticatedUsername if open?; end + + # inherited from Handle + + # Returns whether the underlying handle is valid; i.e., not null. + def valid? + @connection_impl.isValid + end + + # Returns whether the underlying handle is null. + def null? + @connection_impl.isNull + end + + # Swaps the underlying connection handle. + def swap connection + @connection_impl.swap connection.connection_impl + end + + private + + def convert_options + result = {} + # map only those options defined in the C++ layer + # TODO when new options are added, this needs to be updated. + unless @options.nil? || @options.empty? + @options.each_pair {|key, value| result[key.to_s] = value.to_s} + end + + return result + end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/duration.rb b/cpp/bindings/qpid/ruby/lib/qpid/duration.rb new file mode 100644 index 0000000000..c1f44e9281 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/duration.rb @@ -0,0 +1,63 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'cqpid' + +module Qpid + + module Messaging + + # A Duration represents a period of time in milliseconds + # + # It defines the following named values as symbols: + # + # :FOREVER :: the maximum integer value for the platform + # :IMMEDIATE :: an alias for 0 + # :SECOND :: 1,000ms + # :MINUTE :: 60,000ms + class Duration + + def initialize duration # :nodoc: + @duration_impl = Cqpid::Duration.new duration + end + + def duration_impl # :nodoc: + @duration_impl + end + + def self.add_item(key, value) # :nodoc: + @hash ||= {} + @hash[key] = Duration.new value + end + + def self.const_missing(key) # :nodoc: + @hash[key] + end + + self.add_item :FOREVER, Cqpid::Duration.FOREVER.getMilliseconds + self.add_item :IMMEDIATE, Cqpid::Duration.IMMEDIATE.getMilliseconds + self.add_item :SECOND, Cqpid::Duration.SECOND.getMilliseconds + self.add_item :MINUTE, Cqpid::Duration.MINUTE.getMilliseconds + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/encoding.rb b/cpp/bindings/qpid/ruby/lib/qpid/encoding.rb new file mode 100644 index 0000000000..c8b843b597 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/encoding.rb @@ -0,0 +1,56 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'cqpid' + +module Qpid + + module Messaging + + # Encodes the supplied content into the given message. + def self.encode content, message, encoding = nil + prepared = content + case content + when Hash + prepared = {} + content.each_pair do |key,value| + prepared[key.to_s] = value.to_s + end + Cqpid::encode prepared, message.message_impl + when Array + prepared = [] + content.each {|value| prepared << value.to_s} + Cqpid::encode prepared, message.message_impl + end + end + + # Decodes and returns the message's content. + def self.decode(message, content_type = nil) + content_type = message.content_type unless content_type + + case content_type + when "amqp/map": Cqpid.decodeMap message.message_impl + when "amqp/list": Cqpid.decodeList message.message_impl + end + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/errors.rb b/cpp/bindings/qpid/ruby/lib/qpid/errors.rb new file mode 100644 index 0000000000..7a16d08d84 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/errors.rb @@ -0,0 +1,30 @@ +# +# 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. +# + +module Qpid + + module Messaging + + class KeyError < RuntimeError + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/message.rb b/cpp/bindings/qpid/ruby/lib/qpid/message.rb new file mode 100644 index 0000000000..9b1b68c7c3 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/message.rb @@ -0,0 +1,157 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'cqpid' + +module Qpid + + module Messaging + + # Message represents a message. + class Message + + def initialize(args = {}, message_impl = nil) + @message_impl = message_impl + @message_impl = Cqpid::Message.new if @message_impl.nil? + @message_impl.setContent args[:content].to_s if args[:content] + @content = nil + end + + def message_impl # :nodoc: + @message_impl + end + + # Assigns the reply to address. + # The address must be an instance of Address. + def reply_to=(address); @message_impl.setReplyTo address.address_impl; end + + # Returns the reply to address for the message as an instance of +Address+. + def reply_to + address_impl = @message_impl.getReplyTo + # only return an address if a reply to was specified + Qpid::Messaging::Address.new(nil, nil, nil, nil, address_impl) if address_impl + end + + # Sets the subject. + def subject=(subject); @message_impl.setSubject subject; end + + # Returns the subject. + def subject; @message_impl.getSubject; end + + # Sets the content type. + def content_type=(content_type); @message_impl.setContentType content_type; end + + # Returns the content type. + def content_type; @message_impl.getContentType; end + + # Sets the message id. + def message_id=(message_id); @message_impl.setMessageId message_id.to_s; end + + # Returns the message id. + def message_id; @message_impl.getMessageId; end + + # Sets the user id. + def user_id=(user_id); @message_impl.setUserId user_id; end + + # Returns the user id. + def user_id; @message_impl.getUserId; end + + # Sets the correlation id. + def correlation_id=(correlation_id); @message_impl.setCorrelationId correlation_id; end + + # Returns the correlation id. + def correlation_id; @message_impl.getCorrelationId; end + + # Sets the priority. + def priority=(priority); @message_impl.setPriority priority; end + + # Returns the priority. + def priority; @message_impl.getPriority; end + + # Sets the time-to-live in milliseconds. + def ttl=(duration); @message_impl.setTtl duration; end + + # Returns the time-to-live in milliseconds. + def ttl; @message_impl.getTtl; end + + # Sets the durability. + def durable=(durable); @message_impl.setDurable durable; end + + # Returns the durability. + def durable; @message_impl.getDurable; end + + # Allows marking the message as redelivered. + def redelivered=(redelivered); @message_impl.setRedelivered redelivered; end + + # Returns if the message was redelivered. + def redelivered; @message_impl.getRedelivered; end + + # Returns all named properties. + # *NOTE:* It is recommended to use the +foo[key]+ method for + # retrieving properties. + def properties; @message_impl.getProperties; end + + # Returns the value for the named property. + def [](key); self.properties[key.to_s]; end + + # Assigns a value to the named property. + def []=(key, value); @message_impl.setProperty(key.to_s, value.to_s); end + + # Sets the content. + def content=(content) + content_type = nil + @content = content + case @content + when Hash + content_type = "amqp/map" + when Array + content_type = "amqp/list" + end + if content_type.nil? + @message_impl.setContent @content + else + Qpid::Messaging.encode @content, self, content_type + end + end + + # Returns the content. + def content + if @content.nil? + @content = @message_impl.getContent + + # decode the content is necessary if it + # has an encoded content type + if ["amqp/list", "amqp/map"].include? @message_impl.getContentType + @content = Qpid::Messaging.decode(self, + @message_impl.getContentType) + end + + end + @content + end + + # Returns the content's size. + def content_size; @message_impl.getContentSize; end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/receiver.rb b/cpp/bindings/qpid/ruby/lib/qpid/receiver.rb new file mode 100644 index 0000000000..d498aa922b --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/receiver.rb @@ -0,0 +1,102 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'cqpid' + +require 'qpid/duration' + +module Qpid + + module Messaging + + # Receiver defines a type for receiving messages. + class Receiver + + def initialize(receiver_impl) # :nodoc: + @receiver_impl = receiver_impl + end + + def receiver_impl # :nodoc: + @receiver_impl + end + + # Retrieves a message from the receiver's local queue, or waits + # for up to the duration specified for one to become available. + def get(duration = Qpid::Messaging::Duration::FOREVER) + message_impl = @receiver_impl.get duration.duration_impl + create_message_wrapper message_impl unless message_impl.nil? + end + + # Retrieves a message from the receiver's subscription, or waits + # for up to the duration specified for one to become available. + def fetch(duration = Qpid::Messaging::Duration::FOREVER) + message_impl = @receiver_impl.fetch duration.duration_impl + create_message_wrapper message_impl unless message_impl.nil? + end + + # Sets the capacity. + # + # The capacity for a receiver determines the number of messages that + # can be held in the receiver before being fetched. + def capacity=(capacity); @receiver_impl.setCapacity capacity; end + + # Returns the capacity. + def capacity; @receiver_impl.getCapacity; end + + # Returns the number of available messages waiting to be fetched. + def available; @receiver_impl.getAvailable; end + + # Returns the number of messages that have been received and acknowledged + # but whose acknowledgements have not been confirmed by the sender. + def unsettled; @receiver_impl.getUnsettled; end + + # Cancels the reciever. + def close; @receiver_impl.close; end + + # Returns whether the receiver is closed. + def closed?; @receiver_impl.isClosed; end + + # Returns the name of the receiver + def name; @receiver_impl.getName; end + + # Returns the Session for this receiver. + def session; Qpid::Messaging::Session.new(@receiver_impl.getSession); end + + # Returns whether the underlying handle is valid. + def valid?; @receiver_impl.isValid; end + + # Returns whether the underlying handle is null. + def null?; @receiver_impl.isNull; end + + def swap receiver + @receiver_impl.swap receiver.receiver_impl + end + + private + + def create_message_wrapper message_impl + Qpid::Messaging::Message.new({}, message_impl) + end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/sender.rb b/cpp/bindings/qpid/ruby/lib/qpid/sender.rb new file mode 100644 index 0000000000..5d59c20d7e --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/sender.rb @@ -0,0 +1,82 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +module Qpid + + module Messaging + + # Sender defines a type for sending messages. + class Sender + + def initialize(sender_impl) # :nodoc: + @sender_impl = sender_impl + end + + def sender_impl # :nodoc: + @sender_impl + end + + # Sends a message. + def send(message, args = {}) + block = args[:block] || false + @sender_impl.send message.message_impl, block + end + + # Closes the sender. + def close; @sender_impl.close; end + + # Returns the name for the sender. + def name; @sender_impl.getName; end + + # Sets the capacity for the sender, which is the number of outgoing + # messages that can be held pending confirmation or receipt by + # the broker. + def capacity=(capacity); @sender_impl.setCapacity capacity; end + + # Returns the capacity. + def capacity; @sender_impl.getCapacity; end + + # Returns the number of messages sent that are pending receipt + # confirmation by the broker. + def unsettled; @sender_impl.getUnsettled; end + + # Returns the available capacity for sending messages. + def available + @sender_impl.getAvailable + end + + # Returns the Session for this sender. + def session; Qpid::Messaging::Session.new @sender_impl.getSession; end + + # Returns if the underlying sender is valid. + def valid?; @sender_impl.isValid; end + + # Returns if the underlying sender is null. + def null?; @sender_impl.isNull; end + + def swap sender + @sender_impl.swap sender.sender_impl + end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/session.rb b/cpp/bindings/qpid/ruby/lib/qpid/session.rb new file mode 100644 index 0000000000..543c26cc70 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/session.rb @@ -0,0 +1,186 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'cqpid' + +require 'qpid/errors' + +module Qpid + + module Messaging + + # A Session represents a distinct conversation between end points. + class Session + + def initialize(session) # :nodoc: + @session_impl = session + end + + def session_impl # :nodoc: + @session_impl + end + + # Returns the +Connection+ for the +Session+. + def connection + connection_impl = @session_impl.getConnection + Qpid::Messaging::Connection.new "", {}, connection_impl + end + + # Creates a new endpoint for sending messages. + def create_sender(address) + _address = address + + if address.class == Qpid::Messaging::Address + _address = address.address_impl + end + + Qpid::Messaging::Sender.new(@session_impl.createSender(_address)) + end + + # Retrieves the +Sender+ with the specified name. + def sender(name) + result = nil + + begin + sender_impl = @session_impl.getSender name + result = Sender.for_impl sender_impl + rescue + # treat any error as a key error + end + + raise Qpid::Messaging::KeyError, "No such sender: #{name}" if result.nil? + result + end + + # Retrieves the +Receiver+ with the specified name. + def receiver(name) + result = nil + + begin + receiver_impl = @session_impl.getReceiver name + result = Receiver.for_impl receiver_impl + rescue + # treat any error as a key error + end + + raise Qpid::Messaging::KeyError, "No such receiver: #{name}" if result.nil? + result + end + + # Creates a new endpoint for receiving messages. + def create_receiver(address) + result = nil + + if address.class == Qpid::Messaging::Address + address_impl = address.address_impl + result = Qpid::Messaging::Receiver.new(@session_impl.createReceiver(address_impl)) + else + result = Qpid::Messaging::Receiver.new(@session_impl.createReceiver(address)) + end + + return result + end + + # Closes the Session and all associated Senders and Receivers. + # All Sessions are closed when the associated Connection is closed. + def close; @session_impl.close; end + + # Commits any pending transactions for a transactional session. + def commit; @session_impl.commit; end + + # Rolls back any uncommitted transactions on a transactional session. + def rollback; @session_impl.rollback; end + + # Acknowledges one or more outstanding messages that have been received + # on this session. + # + # If a message is submitted (:message => something_message) then only + # that message is acknowledged. Otherwise all messsages are acknowledged. + # + # If :sync => true then the call will block until the server completes + # processing the acknowledgements. + # If :sync => true then the call will block until processed by the server (def. false) + def acknowledge(args = {}) + sync = args[:sync] || false + message = args[:message] if args[:message] + + unless message.nil? + @session_impl.acknowledge message.message_impl, sync + else + @session_impl.acknowledge sync + end + end + + # Rejects the specified message. A rejected message will not be redelivered. + # + # NOTE: A message cannot be rejected once it has been acknowledged. + def reject(message); @session_impl.reject message.message_impl; end + + # Releases the message, which allows the broker to attempt to + # redeliver it. + # + # NOTE: A message connot be released once it has been acknowled. + def release(message); @session_impl.release message.message_impl; end + + # Requests synchronization with the server. + # + # If :block => true then the call will block until the server acknowledges. + # + # If :block => false (default) then the call will complete and the server + # will send notification on completion. + def sync(args = {}) + block = args[:block] || false + @session_impl.sync block + end + + # Returns the total number of receivable messages, and messages already received, + # by Receivers associated with this session. + def receivable; @session_impl.getReceivable; end + + # Returns the number of messages that have been acknowledged by this session + # whose acknowledgements have not been confirmed as processed by the server. + def unsettled_acks; @session_impl.getUnsettledAcks; end + + # Fetches the receiver for the next message. + def next_receiver(timeout = Qpid::Messaging::Duration::FOREVER) + receiver_impl = @session_impl.nextReceiver(timeout.duration_impl) + Qpid::Messaging::Receiver.new receiver_impl + end + + # Returns whether there are errors on this session. + def error?; @session_impl.hasError; end + + def check_error; @session_impl.checkError; end + + # Returns if the underlying session is valid. + def valid?; @session_impl.isValid; end + + # Returns if the underlying session is null. + def null?; @session_impl.isNull; end + + def swap session + @session_impl.swap session.session_impl + end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/version.rb b/cpp/bindings/qpid/ruby/lib/qpid/version.rb new file mode 100644 index 0000000000..f387ba98dc --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid/version.rb @@ -0,0 +1,31 @@ +# +# 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. +# + +module Qpid + + module Version + + NUMBERS = [MAJOR = 0, + MINOR = 13, + BUILD = 0] + end + + VERSION = Version::NUMBERS.join('.') + +end diff --git a/cpp/bindings/qpid/ruby/test/lib/setup.rb b/cpp/bindings/qpid/ruby/test/lib/setup.rb new file mode 100644 index 0000000000..c4901ed907 --- /dev/null +++ b/cpp/bindings/qpid/ruby/test/lib/setup.rb @@ -0,0 +1,29 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'qpid' + +def create_session url, session_name + conn = Qpid::Messaging::Connection.new url + conn.open + conn.create_session session_name +end + diff --git a/cpp/bindings/qpid/ruby/test/test_address.rb b/cpp/bindings/qpid/ruby/test/test_address.rb new file mode 100644 index 0000000000..f54e93aa3d --- /dev/null +++ b/cpp/bindings/qpid/ruby/test/test_address.rb @@ -0,0 +1,39 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'test/unit' +require 'flexmock/test_unit' + +require 'cqpid' +require 'qpid/address' + +class TestAddress < Test::Unit::TestCase + + def test_constructor + result = Qpid::Messaging::Address.new "name", "subject", {:foo => :bar}, "type" + + assert_equal "name", result.name + assert_equal "subject", result.subject + assert_equal "type", result._type + end + +end + diff --git a/cpp/bindings/qpid/ruby/test/test_connection.rb b/cpp/bindings/qpid/ruby/test/test_connection.rb new file mode 100644 index 0000000000..648fb0588a --- /dev/null +++ b/cpp/bindings/qpid/ruby/test/test_connection.rb @@ -0,0 +1,257 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'test/unit' +require 'flexmock/test_unit' + +require 'cqpid' +require 'qpid/connection' + +class TestConnection < Test::Unit::TestCase + + def setup + @connection_impl = flexmock("connection_impl") + @other_connection = flexmock("other_connection") + @other_connection_impl = flexmock("other_connection_impl") + @cqpid_connection = flexmock(Cqpid::Connection) + + @session = flexmock("session") + @session_name = "test-session" + + @url = "localhost" + @options = {} + + @connection = Qpid::Messaging::Connection.new(@url, @options, @connection_impl) + end + + def test_create_with_username_and_password + @cqpid_connection. + should_receive(:new). + once.with("localhost", + {"username" => "username", + "password" => "password"}). + and_return(@connection_impl) + @connection_impl. + should_receive(:open). + once + + result = Qpid::Messaging::Connection.new("localhost", + :username => "username", + :password => "password") + result.open + + assert_same @connection_impl, result.connection_impl + end + + def test_create_with_hostname + result = Qpid::Messaging::Connection.new("localhost") + + assert_not_nil result + end + + def test_open + @cqpid_connection. + should_receive(:new). + once. + with(@url, {}). + and_return(@connection_impl) + @connection_impl. + should_receive(:open). + once + + @connection.open + + assert_same @connection_impl, @connection.connection_impl + end + + def test_check_open_when_open + @connection_impl. + should_receive(:isOpen). + once. + and_return(true) + + assert @connection.open? + end + + def test_check_open_before_connection + result = Qpid::Messaging::Connection.new("hostname") + + assert !result.open? + end + + def test_check_open_when_closed + @connection_impl. + should_receive(:isOpen). + once. + and_return(false) + + assert !@connection.open? + end + + def test_close_an_unopened_session + @connection_impl. + should_receive(:isOpen). + once. + and_return(false) + + @connection.close + end + + def test_close + @connection_impl. + should_receive(:isOpen). + once. + and_return(true). + should_receive(:close). + once + + @connection.close + end + + def test_create_session_without_name + @connection_impl. + should_receive(:isOpen). + once. + and_return(true). + should_receive(:createSession). + once. + with(""). + and_return(@session) + + result = @connection.create_session + + assert_not_nil result + assert_same @session, result.session_impl + end + + def test_create_session + @connection_impl. + should_receive(:isOpen). + once. + and_return(true). + should_receive(:createSession). + once. + with(@session_name). + and_return(@session) + + result = @connection.create_session :name => @session_name + + assert_not_nil result + assert_same @session, result.session_impl + end + + def test_create_session_raises_exception_when_closed + @connection_impl. + should_receive(:isOpen). + once. + and_return(false) + + assert_raise(RuntimeError) {@connection.create_session @session_name} + end + + def test_create_transactional_session + @connection_impl. + should_receive(:isOpen). + once. + and_return(true). + should_receive(:createTransactionalSession). + once. + with(""). + and_return(@session) + + result = @connection.create_session :transactional => true + + assert_not_nil result + assert_same @session, result.session_impl + end + + def test_authenticated_username_when_not_connected + @connection_impl. + should_receive(:isOpen). + once. + and_return(false) + + result = @connection.authenticated_username + + assert_nil result + end + + def test_authenticated_username + @connection_impl. + should_receive(:isOpen). + once. + and_return(true). + should_receive(:getAuthenticatedUsername). + once. + and_return("farkle") + + result = @connection.authenticated_username + + assert_equal "farkle", result + end + + def test_get_session_with_invalid_name + @connection_impl. + should_receive(:getSession). + once. + with(@session_name). + and_return(nil) + + result = @connection.session @session_name + + assert_nil result + end + + # APIs inherited from Handle + + def test_is_valid + @connection_impl. + should_receive(:isValid). + once. + and_return(true) + + assert @connection.valid? + end + + def test_is_null + @connection_impl. + should_receive(:isNull). + once. + and_return(false) + + assert !@connection.null? + end + + def test_swap + @other_connection. + should_receive(:connection_impl). + once. + and_return(@other_connection_impl) + @connection_impl. + should_receive(:swap). + once. + with(@other_connection_impl) + + @connection.swap @other_connection + end + +end + diff --git a/cpp/bindings/qpid/ruby/test/test_encoding.rb b/cpp/bindings/qpid/ruby/test/test_encoding.rb new file mode 100644 index 0000000000..060975a1d5 --- /dev/null +++ b/cpp/bindings/qpid/ruby/test/test_encoding.rb @@ -0,0 +1,146 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'test/unit' +require 'flexmock/test_unit' + +require 'cqpid' +require 'qpid/encoding' + +class TestEncoding < Test::Unit::TestCase + + def setup + @cqpid = flexmock(Cqpid) + + @message = flexmock("message") + @message_impl = flexmock("message_impl") + + @encoded = {"foo" => "bar"} + end + + def test_encode_map_with_symbols + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @cqpid. + should_receive(:encode). + once. + with({"foo" => "bar"}, @message_impl). + and_return(@encoded) + + result = Qpid::Messaging.encode({:foo => :bar}, @message) + + assert_same @encoded, result + end + + def test_encode_list_with_symbols + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @cqpid. + should_receive(:encode). + once. + with(["foo", "bar"], @message_impl). + and_return(@encoded) + + result = Qpid::Messaging.encode([:foo, :bar], @message) + + assert_same @encoded, result + end + + def test_encode_with_content_type + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @cqpid. + should_receive(:encode). + once. + with({"foo" => "bar"}, @message_impl). + and_return(@encoded) + + result = Qpid::Messaging.encode({:foo => :bar}, @message) + + assert_same @encoded, result + end + + def test_encode + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @cqpid. + should_receive(:encode). + once. + with({"foo" => "bar"}, @message_impl). + and_return(@encoded) + + result = Qpid::Messaging.encode({"foo" => "bar"}, @message) + + assert_same @encoded, result + end + + def test_decode_for_map + decoded = {"foo" => "bar"} + @message. + should_receive(:content_type). + once. + and_return("amqp/map") + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @cqpid. + should_receive(:decodeMap). + once. + with(@message_impl). + and_return(decoded) + + result = Qpid::Messaging.decode(@message) + + assert_same decoded, result + end + + def test_decode_for_list + decoded = ["foo", "bar"] + @message. + should_receive(:content_type). + once. + and_return("amqp/list") + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @cqpid. + should_receive(:decodeList). + once. + with(@message_impl). + and_return(decoded) + + result = Qpid::Messaging.decode(@message) + + assert_same decoded, result + end + +end + diff --git a/cpp/bindings/qpid/ruby/test/test_message.rb b/cpp/bindings/qpid/ruby/test/test_message.rb new file mode 100644 index 0000000000..3fc705bf7e --- /dev/null +++ b/cpp/bindings/qpid/ruby/test/test_message.rb @@ -0,0 +1,353 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'test/unit' +require 'flexmock/test_unit' + +require 'qpid' + +class TestMessage < Test::Unit::TestCase + + def setup + @address = flexmock("address") + @address_impl = flexmock("address_impl") + + @messaging = flexmock(Qpid::Messaging) + @message_impl = flexmock("message") + @message = Qpid::Messaging::Message.new({}, @message_impl) + end + + def test_message_impl + assert_same @message_impl, @message.message_impl + end + + def test_set_reply_to + @address. + should_receive(:address_impl). + once. + and_return(@address_impl) + @message_impl. + should_receive(:setReplyTo). + once. + with(@address_impl) + + @message.reply_to = @address + end + + def test_get_reply_to + @message_impl. + should_receive(:getReplyTo). + once. + and_return(@address_impl) + + result = @message.reply_to + + assert_not_nil result + assert_same @address_impl, result.address_impl + end + + def test_set_subject + @message_impl. + should_receive(:setSubject). + once. + with("New Subject") + + @message.subject = "New Subject" + end + + def test_get_subject + @message_impl. + should_receive(:getSubject). + once. + and_return("Old Subject") + + assert_equal "Old Subject", @message.subject + end + + def test_set_content_type + @message_impl. + should_receive(:setContentType). + once. + and_return("amqp/map") + + @message.content_type = "amqp/map" + end + + def test_get_content_type + @message_impl. + should_receive(:getContentType). + once. + and_return("amqp/list") + + assert_equal "amqp/list", @message.content_type + end + + def test_set_message_id + @message_impl. + should_receive(:setMessageId). + once. + with("717") + + @message.message_id = "717" + end + + def test_get_message_id + @message_impl. + should_receive(:getMessageId). + once. + and_return("1965") + + assert_equal "1965", @message.message_id + end + + def test_set_user_id + @message_impl. + should_receive(:setUserId). + once. + with("129") + + @message.user_id = "129" + end + + def test_get_user_id + @message_impl. + should_receive(:getUserId). + once. + and_return("1971") + + assert_equal "1971", @message.user_id + end + + def test_set_correlation_id + @message_impl. + should_receive(:setCorrelationId). + once. + with("320") + + @message.correlation_id = "320" + end + + def test_get_correlation_id + @message_impl. + should_receive(:getCorrelationId). + once. + and_return("1996") + + assert_equal "1996", @message.correlation_id + end + + def test_set_priority + @message_impl. + should_receive(:setPriority). + once. + with(9) + + @message.priority = 9 + end + + def test_get_priority + @message_impl. + should_receive(:getPriority). + once. + and_return(21) + + assert_equal 21, @message.priority + end + + def test_set_ttl + @message_impl. + should_receive(:setTtl). + once. + with(Qpid::Messaging::Duration::FOREVER) + + @message.ttl = Qpid::Messaging::Duration::FOREVER + end + + def test_get_ttl + @message_impl. + should_receive(:getTtl). + once. + and_return(Qpid::Messaging::Duration::SECOND) + + assert_equal Qpid::Messaging::Duration::SECOND, @message.ttl + end + + def test_set_durable + @message_impl. + should_receive(:setDurable). + once. + with(true) + + @message.durable = true + end + + def test_set_not_durable + @message_impl. + should_receive(:setDurable). + once. + with(false) + + @message.durable = false + end + + def test_get_durable + @message_impl. + should_receive(:getDurable). + once. + and_return(true) + + assert @message.durable + end + + def test_set_redelivered + @message_impl. + should_receive(:setRedelivered). + once. + with(true) + + @message.redelivered = true + end + + def test_set_not_redelivered + @message_impl. + should_receive(:setRedelivered). + once. + with(false) + + @message.redelivered = false + end + + def test_get_redelivered + @message_impl. + should_receive(:getRedelivered). + once. + and_return(false) + + assert !@message.redelivered + end + + def test_get_properties + properties = {"foo" => "bar"} + @message_impl. + should_receive(:getProperties). + once. + and_return(properties) + + result = @message.properties + + assert_equal properties, result + end + + def test_get_property + @message_impl. + should_receive(:getProperties). + once. + and_return({"foo" => "bar"}) + + result = @message["foo"] + + assert_equal "bar", result + end + + def test_set_property + @message_impl. + should_receive(:setProperty). + once. + with("foo", "bar") + + @message["foo"] = "bar" + end + + def test_set_content + @message_impl. + should_receive(:setContent). + once. + with("foo") + + @message.content = "foo" + assert_equal "foo", @message.content + end + + def test_set_content_with_array + content = ["one", "two", "three"] + + @messaging. + should_receive(:encode). + once. + with(content, @message, "amqp/list") + + @message.content = content + assert_same content, @message.content + end + + def test_set_content_with_map + content = {:foo => "bar", :dog => "cat"} + + @messaging. + should_receive(:encode). + once. + with(content, @message, "amqp/map") + + @message.content = content + assert_same content, @message.content + end + + def test_get_content + @message_impl. + should_receive(:getContent). + and_return("foo") + @message_impl. + should_receive(:getContentType). + and_return(String) + + assert_equal "foo", @message.content + end + + def test_get_content_with_array + decoded = ["foo", "bar"] + + @message_impl. + should_receive(:getContent). + and_return("[foo,bar]") + @message_impl. + should_receive(:getContentType). + and_return("amqp/list") + @messaging. + should_receive(:decode). + once. + with(@message, "amqp/list"). + and_return(decoded) + + result = @message.content + assert_same decoded, result + end + + def test_get_content_size + @message_impl. + should_receive(:getContentSize). + once. + and_return(68) + + assert_equal 68, @message.content_size + end + +end + diff --git a/cpp/bindings/qpid/ruby/test/test_receiver.rb b/cpp/bindings/qpid/ruby/test/test_receiver.rb new file mode 100644 index 0000000000..61a4db17f2 --- /dev/null +++ b/cpp/bindings/qpid/ruby/test/test_receiver.rb @@ -0,0 +1,238 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'test/unit' +require 'flexmock/test_unit' + +require 'qpid/receiver' + +class TestReceiver < Test::Unit::TestCase + + def setup + @session_impl = flexmock("session") + + @Message_class = flexmock(Qpid::Messaging::Message) + @Messaging_module = flexmock(Qpid::Messaging) + @message_impl = flexmock("message_impl") + @message = flexmock("message") + + @receiver_impl = flexmock("receiver") + @other_receiver = flexmock("other_receiver") + @other_receiver_impl = flexmock("other_receiver_impl") + @receiver = Qpid::Messaging::Receiver.new @receiver_impl + end + + def test_receiver_impl + assert_same @receiver_impl, @receiver.receiver_impl + end + + def test_get + @receiver_impl. + should_receive(:get). + once. + with_any_args. + and_return(@message_impl) + + result = @receiver.get + + assert_not_nil result + assert_same @message_impl, result.message_impl + end + + def test_get_with_duration + @receiver_impl. + should_receive(:get). + once. + with_any_args. + and_return(@message_impl) + + result = @receiver.get Qpid::Messaging::Duration::MINUTE + + assert_not_nil result + assert_same @message_impl, result.message_impl + end + + def test_get_with_no_message_received + @receiver_impl. + should_receive(:get). + once. + with_any_args. + and_return(nil) + + result = @receiver.get Qpid::Messaging::Duration::SECOND + + assert_nil result + end + + def test_fetch + @receiver_impl. + should_receive(:fetch). + once. + with_any_args. + and_return(@message_impl) + + result = @receiver.fetch + + assert_not_nil result + assert_same @message_impl, result.message_impl + end + + def test_fetch_with_duration + @receiver_impl. + should_receive(:fetch). + once. + with_any_args. + and_return(@message_impl) + + result = @receiver.fetch Qpid::Messaging::Duration::MINUTE + + assert_not_nil result + assert_same @message_impl, result.message_impl + end + + def test_fetch_with_no_message_received + @receiver_impl. + should_receive(:fetch). + once. + with_any_args. + and_return(nil) + + result = @receiver.fetch Qpid::Messaging::Duration::SECOND + + assert_nil result + end + + def test_set_capacity + @receiver_impl. + should_receive(:setCapacity). + once. + with(15) + + @receiver.capacity = 15 + end + + def test_get_capacity + @receiver_impl. + should_receive(:getCapacity). + once. + and_return(17) + + assert_equal 17, @receiver.capacity + end + + def test_get_available + @receiver_impl. + should_receive(:getAvailable). + once. + and_return(2) + + assert_equal 2, @receiver.available + end + + def test_get_unsettled + @receiver_impl. + should_receive(:getUnsettled). + once. + and_return(12) + + assert_equal 12, @receiver.unsettled + end + + def test_close + @receiver_impl. + should_receive(:close). + once + + @receiver.close + end + + def test_closed_when_open + @receiver_impl. + should_receive(:isClosed). + once. + and_return(false) + + assert !@receiver.closed? + end + + def test_closed + @receiver_impl. + should_receive(:isClosed). + once. + and_return(true) + + assert @receiver.closed? + end + + def test_get_name + @receiver_impl. + should_receive(:getName). + once. + and_return("my-queue") + + assert_equal "my-queue", @receiver.name + end + + def test_get_session + @receiver_impl. + should_receive(:getSession). + once. + and_return(@session_impl) + + result = @receiver.session + + assert_not_nil result + assert_same @session_impl, result.session_impl + end + + def test_is_valid + @receiver_impl. + should_receive(:isValid). + once. + and_return(false) + + assert !@receiver.valid? + end + + def test_is_null + @receiver_impl. + should_receive(:isNull). + once. + and_return(true) + + assert @receiver.null? + end + + def test_swap + @other_receiver. + should_receive(:receiver_impl). + once. + and_return(@other_receiver_impl) + @receiver_impl. + should_receive(:swap). + once. + with(@other_receiver_impl) + + @receiver.swap @other_receiver + end + +end + diff --git a/cpp/bindings/qpid/ruby/test/test_sender.rb b/cpp/bindings/qpid/ruby/test/test_sender.rb new file mode 100644 index 0000000000..64348b9f72 --- /dev/null +++ b/cpp/bindings/qpid/ruby/test/test_sender.rb @@ -0,0 +1,183 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'test/unit' +require 'flexmock/test_unit' + +require 'qpid/sender' + +class TestSender < Test::Unit::TestCase + + def setup + @messaging = flexmock(Qpid::Messaging) + @message = flexmock("message") + + @session_impl = flexmock("session_impl") + + @sender_impl = flexmock("sender_impl") + @other_sender_impl = flexmock("other_sender_impl") + @sender = Qpid::Messaging::Sender.new @sender_impl + @other_sender = flexmock("other_sender") + end + + def test_send + message_impl = "message_impl" + content = {:foo => :bar} + @message. + should_receive(:message_impl). + once. + and_return(message_impl) + @sender_impl. + should_receive(:send). + once. + with(message_impl, false) + + @sender.send @message + end + + def test_send_and_dont_block + message_impl = "message_impl" + content = {:foo => :bar} + @message. + should_receive(:message_impl). + once. + and_return(message_impl) + @sender_impl. + should_receive(:send). + once. + with(message_impl, false) + + @sender.send @message, :block => false + end + + def test_send_and_block + message_impl = "message_impl" + content = {:foo => :bar} + @message. + should_receive(:message_impl). + once. + and_return(message_impl) + @sender_impl. + should_receive(:send). + once. + with(message_impl, true) + + @sender.send @message, :block => true + end + + def test_close + @sender_impl. + should_receive(:close). + once + + @sender.close + end + + def test_set_capacity + @sender_impl. + should_receive(:setCapacity). + once. + with(17) + + @sender.capacity = 17 + end + + def test_get_capacity + @sender_impl. + should_receive(:getCapacity). + once. + and_return(12) + + assert_equal 12, @sender.capacity + end + + def test_unsettled + @sender_impl. + should_receive(:getUnsettled). + once. + and_return(5) + + assert_equal 5, @sender.unsettled + end + + def test_available + @sender_impl. + should_receive(:getAvailable). + once. + and_return(15) + + assert_equal 15, @sender.available + end + + def test_name + @sender_impl. + should_receive(:getName). + once. + and_return("myname") + + assert_equal "myname", @sender.name + end + + def test_session + @sender_impl. + should_receive(:getSession). + once. + and_return(@session_impl) + + result = @sender.session + + assert_not_nil result + assert_same @session_impl, result.session_impl + end + + def test_is_valid + @sender_impl. + should_receive(:isValid). + once. + and_return(true) + + assert @sender.valid? + end + + def test_is_null + @sender_impl. + should_receive(:isNull). + once. + and_return(false) + + assert !@sender.null? + end + + def test_swap + @other_sender. + should_receive(:sender_impl). + once. + and_return(@other_sender_impl) + @sender_impl. + should_receive(:swap). + once. + with(@other_sender_impl) + + @sender.swap @other_sender + end + +end + diff --git a/cpp/bindings/qpid/ruby/test/test_session.rb b/cpp/bindings/qpid/ruby/test/test_session.rb new file mode 100644 index 0000000000..20f055967b --- /dev/null +++ b/cpp/bindings/qpid/ruby/test/test_session.rb @@ -0,0 +1,445 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'test/unit' +require 'flexmock/test_unit' + +require 'qpid/errors' +require 'qpid/duration' +require 'qpid/session' + +class TestSession < Test::Unit::TestCase + + def setup + @session_impl = flexmock("session_impl") + @other_session = flexmock("other_session") + @other_session_impl = flexmock("other_session_impl") + @sender = flexmock("sender") + + @Connection_class = flexmock(Qpid::Messaging::Connection) + @connection_impl = flexmock("connection_impl") + @connection = flexmock("connection") + + @Receiver_class = flexmock(Qpid::Messaging::Receiver) + @receiver = flexmock("receiver") + @receiver_impl = flexmock("receiver_impl") + + @address = flexmock("address") + @address_impl = flexmock("address_impl") + + @Sender_class = flexmock(Qpid::Messaging::Sender) + @sender = flexmock("sender") + @sender_impl = flexmock("sender_impl") + + @message = flexmock("message") + @message_impl = flexmock("message_impl") + + @duration = flexmock("duration") + @duration_impl = flexmock("duration_impl") + + @session = Qpid::Messaging::Session.new(@session_impl) + end + + def test_create_sender_with_Address + @address. + should_receive(:class). + once. + and_return(Qpid::Messaging::Address). + should_receive(:address_impl). + once. + and_return(@address_impl) + @session_impl. + should_receive(:createSender). + once. + with(@address_impl). + and_return(@sender_impl) + + result = @session.create_sender @address + + assert_not_nil result + end + + def test_create_sender + @session_impl. + should_receive(:createSender). + once. + with_any_args. + and_return(@sender_impl) + + result = @session.create_sender("my-queue") + + assert_not_nil result + end + + def test_create_sender_with_address_string + @session_impl. + should_receive(:createSender). + once. + with("my-queue;{create:always}"). + and_return(@sender_impl) + + result = @session.create_sender "my-queue;{create:always}" + + assert_same @sender_impl, result.sender_impl + end + + def test_create_receiver + @address. + should_receive(:class). + once. + and_return(Qpid::Messaging::Address). + should_receive(:address_impl). + once. + and_return(@address_impl) + @session_impl. + should_receive(:createReceiver). + once. + with(@address_impl). + and_return(@receiver_impl) + + result = @session.create_receiver(@address) + + assert_equal @receiver_impl, result.receiver_impl + end + + def test_create_receiver_with_address_string + @session_impl. + should_receive(:createReceiver). + once. + with("my-queue"). + and_return(@receiver_impl) + + result = @session.create_receiver("my-queue") + + assert_same @receiver_impl, result.receiver_impl + end + + def test_close + @session_impl. + should_receive(:close). + once + + @session.close + end + + def test_commit + @session_impl. + should_receive(:commit). + once + + @session.commit + end + + def test_rollback + @session_impl. + should_receive(:rollback). + once + + @session.rollback + end + + def test_acknowledge_with_no_args + @session_impl. + should_receive(:acknowledge). + once. + with(false) + + @session.acknowledge + end + + def test_acknowledge_and_sync + @session_impl. + should_receive(:acknowledge). + once. + with(true) + + @session.acknowledge :sync => true + end + + def test_acknowledge_and_dont_sync + @session_impl. + should_receive(:acknowledge). + once. + with(false) + + @session.acknowledge :sync => false + end + + def test_acknowledge_message_without_sync + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @session_impl. + should_receive(:acknowledge). + once. + with(@message_impl, false) + + @session.acknowledge :message => @message + end + + def test_acknowledge_message_and_sync + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @session_impl. + should_receive(:acknowledge). + once. + with(@message_impl, true) + + @session.acknowledge :message => @message, :sync => true + end + + def test_acknowledge_message_and_dont_sync + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @session_impl. + should_receive(:acknowledge). + once. + with(@message_impl, false) + + @session.acknowledge :message => @message, :sync => false + end + + def test_reject_message + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @session_impl. + should_receive(:reject). + once. + with(@message_impl) + + @session.reject @message + end + + def test_release_message + @message. + should_receive(:message_impl). + once. + and_return(@message_impl) + @session_impl. + should_receive(:release). + once. + with(@message_impl) + + @session.release @message + end + + def test_sync_without_block + @session_impl. + should_receive(:sync). + once + + @session.sync + end + + def test_sync_and_block + @session_impl. + should_receive(:sync). + once. + with(true) + + @session.sync :block => true + end + + def test_sync_and_dont_block + @session_impl. + should_receive(:sync). + once. + with(false) + + @session.sync :block => false + end + + def test_receivable + @session_impl. + should_receive(:getReceivable). + once. + and_return(5) + + assert_equal 5, @session.receivable + end + + def test_unsettled_acks + @session_impl. + should_receive(:getUnsettledAcks). + once. + and_return(17) + + assert_equal 17, @session.unsettled_acks + end + + def test_next_receiver_with_no_duration + @session_impl. + should_receive(:nextReceiver). + once. + with(Qpid::Messaging::Duration::FOREVER.duration_impl). + and_return(@receiver_impl) + + result = @session.next_receiver + + assert_same @receiver_impl, result.receiver_impl + end + + def test_next_receiver_with_duration + @duration. + should_receive(:duration_impl). + once. + and_return(@duration_impl) + @session_impl. + should_receive(:nextReceiver). + once. + with(@duration_impl). + and_return(@receiver_impl) + + result = @session.next_receiver @duration + + assert_same @receiver_impl, result.receiver_impl + end + + def test_sender + @session_impl. + should_receive(:getSender). + once. + with("farkle"). + and_return(@sender_impl) + @Sender_class. + should_receive(:for_impl). + once. + with(@sender_impl). + and_return(@sender) + + result = @session.sender "farkle" + + assert_same @sender, result + end + + def test_sender_with_invalid_name + @session_impl. + should_receive(:getSender). + once. + with("farkle"). + and_throw(RuntimeError) + + assert_raise(Qpid::Messaging::KeyError) {@session.sender "farkle"} + end + + def test_receiver + @session_impl. + should_receive(:getReceiver). + once. + with("farkle"). + and_return(@receiver_impl) + @Receiver_class. + should_receive(:for_impl). + once. + with(@receiver_impl). + and_return(@receiver) + + result = @session.receiver "farkle" + + assert_same @receiver, result + end + + def test_receiver_with_invalid_name + @session_impl. + should_receive(:getReceiver). + once. + with("farkle"). + and_throw(RuntimeError) + + assert_raise(Qpid::Messaging::KeyError) {@session.receiver "farkle"} + end + + def test_connection + @session_impl. + should_receive(:getConnection). + once. + and_return(@connection_impl) + + result = @session.connection + + assert_same @connection_impl, result.connection_impl + end + + def test_error_with_none + @session_impl. + should_receive(:hasError). + once. + and_return(false) + + assert !@session.error? + end + + def test_error + @session_impl. + should_receive(:hasError). + once. + and_return(true) + + assert @session.error? + end + + def test_check_error + @session_impl. + should_receive(:checkError). + once + + @session.check_error + end + + def test_is_valid + @session_impl. + should_receive(:isValid). + once. + and_return(false) + + assert !@session.valid? + end + + def test_is_null + @session_impl. + should_receive(:isNull). + once. + and_return(false) + + assert !@session.null? + end + + def test_swap + @other_session. + should_receive(:session_impl). + once. + and_return(@other_session_impl) + @session_impl. + should_receive(:swap). + once. + with(@other_session_impl) + + @session.swap @other_session + end + +end diff --git a/cpp/bindings/qpid/ruby/test/ts_bindings.rb b/cpp/bindings/qpid/ruby/test/ts_bindings.rb new file mode 100644 index 0000000000..7aa410c8f8 --- /dev/null +++ b/cpp/bindings/qpid/ruby/test/ts_bindings.rb @@ -0,0 +1,30 @@ +# +# 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. +# + +$:.unshift File.join(File.dirname(__FILE__), "..", "lib") + +require 'test/unit' +require 'test_encoding' +require 'test_address' +require 'test_message' +require 'test_sender' +require 'test_receiver' +require 'test_session' +require 'test_connection' + diff --git a/cpp/bindings/swig_python_typemaps.i b/cpp/bindings/swig_python_typemaps.i index b69784a6de..18bfd48f72 100644 --- a/cpp/bindings/swig_python_typemaps.i +++ b/cpp/bindings/swig_python_typemaps.i @@ -17,6 +17,25 @@ * under the License. */ +/* For UUID objects, to convert them to Python uuid.UUID objects, + * we'll need a reference to the uuid module. + */ +%{ +static PyObject* pUuidModule; +%} + +%init %{ + pUuidModule = PyImport_ImportModule("uuid"); + + /* Although it is not required, we'll publish the uuid module in our + * module, as if this module was a python module and we called + * "import uuid" + */ + Py_INCREF(pUuidModule); + PyModule_AddObject(m, "uuid", pUuidModule); +%} + + %wrapper %{ #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) @@ -28,6 +47,7 @@ typedef int Py_ssize_t; PyObject* MapToPy(const qpid::types::Variant::Map*); PyObject* ListToPy(const qpid::types::Variant::List*); + PyObject* UuidToPy(const qpid::types::Uuid*); void PyToMap(PyObject*, qpid::types::Variant::Map*); void PyToList(PyObject*, qpid::types::Variant::List*); @@ -104,6 +124,9 @@ typedef int Py_ssize_t; break; } case qpid::types::VAR_UUID : { + qpid::types::Uuid uuid = v->asUuid(); + result = UuidToPy(&uuid); + break; } } } catch (qpid::types::Exception& ex) { @@ -143,6 +166,30 @@ typedef int Py_ssize_t; return result; } + PyObject* UuidToPy(const qpid::types::Uuid * uuid) { + PyObject* pUuidClass = PyObject_GetAttrString(pUuidModule, "UUID"); + if (!pUuidClass) { + // Failed to get UUID class + return 0; + } + + PyObject* pArgs = PyTuple_New(0); + PyObject* pKw = PyDict_New(); + PyObject* pData = PyString_FromStringAndSize( + (const char*)(uuid->data()), 16); + PyDict_SetItemString(pKw, "bytes", pData); + + PyObject* result = PyObject_Call(pUuidClass, pArgs, pKw); + + Py_DECREF(pData); + Py_DECREF(pKw); + Py_DECREF(pArgs); + Py_DECREF(pUuidClass); + + return result; + } + + void PyToMap(PyObject* obj, qpid::types::Variant::Map* map) { map->clear(); Py_ssize_t iter(0); @@ -304,6 +351,15 @@ typedef int Py_ssize_t; Py_INCREF($result); } +/* + * UUID type: C++ --> Python + */ +%typemap(out) qpid::types::UUID & { + $result = UuidToPy($1); + if ($result) + Py_INCREF($result); +} + /* * Variant types: Ruby --> C++ diff --git a/cpp/bindings/swig_ruby_typemaps.i b/cpp/bindings/swig_ruby_typemaps.i index 79e679663d..326d607c8d 100644 --- a/cpp/bindings/swig_ruby_typemaps.i +++ b/cpp/bindings/swig_ruby_typemaps.i @@ -49,7 +49,7 @@ } VALUE VariantToRb(const qpid::types::Variant* v) { - VALUE result; + VALUE result = Qnil; try { switch (v->getType()) { case qpid::types::VAR_VOID: { diff --git a/cpp/bld-winsdk.ps1 b/cpp/bld-winsdk.ps1 index 8f0a5886dc..bea46da28f 100644 --- a/cpp/bld-winsdk.ps1 +++ b/cpp/bld-winsdk.ps1 @@ -186,9 +186,6 @@ function BuildAPlatform 'examples/qmf-console', 'examples/request-response', 'examples/tradedemo', - 'examples/old-examples.sln', - 'examples/README.*', - 'examples/verify*', 'include', 'plugins') diff --git a/cpp/configure.ac b/cpp/configure.ac index ea1a1b49ea..092694d56b 100644 --- a/cpp/configure.ac +++ b/cpp/configure.ac @@ -68,8 +68,10 @@ if test x$GXX = xyes; then # The following warnings are deliberately omitted, they warn on valid code. # -Wunreachable-code -Wpadded -Winline # -Wshadow - warns about boost headers. + # Can't test for -Werror as whether it fails or not depends on what's in + # CFLAGS/CXXFLAGS. In any case it's been in gcc for a long time (since 2.95 at least) if test "${enableval}" = yes; then - gl_COMPILER_FLAGS(-Werror) + COMPILER_FLAGS="-Werror" gl_COMPILER_FLAGS(-pedantic) gl_COMPILER_FLAGS(-Wall) gl_COMPILER_FLAGS(-Wextra) @@ -521,18 +523,19 @@ AM_PATH_PYTHON() builddir_lib_suffix="/.libs" AC_SUBST([builddir_lib_suffix]) -# Files to generate +# Files to generate AC_CONFIG_FILES([ Makefile examples/Makefile - examples/direct/Makefile - examples/fanout/Makefile - examples/pub-sub/Makefile - examples/request-response/Makefile - examples/failover/Makefile - examples/xml-exchange/Makefile + examples/old_api/Makefile + examples/old_api/direct/Makefile + examples/old_api/fanout/Makefile + examples/old_api/pub-sub/Makefile + examples/old_api/request-response/Makefile + examples/old_api/failover/Makefile + examples/old_api/xml-exchange/Makefile examples/qmf-console/Makefile - examples/tradedemo/Makefile + examples/old_api/tradedemo/Makefile examples/messaging/Makefile bindings/qpid/Makefile bindings/qpid/ruby/Makefile diff --git a/cpp/design_docs/hot-standby-design.txt b/cpp/design_docs/hot-standby-design.txt new file mode 100644 index 0000000000..99a5dc0199 --- /dev/null +++ b/cpp/design_docs/hot-standby-design.txt @@ -0,0 +1,239 @@ +-*-org-*- +# 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. + +* Another new design for Qpid clustering. + +For background see [[./new-cluster-design.txt]] which describes the issues +with the old design and a new active-active design that could replace it. + +This document describes an alternative hot-standby approach. + +** Delivery guarantee + +We guarantee N-way redundant, at least once delivey. Once a message +from a client has been acknowledged by the broker, it will be +delivered even if N-1 brokers subsequently fail. There may be +duplicates in the event of a failure. We don't make duplicates +during normal operation (i.e when no brokers have failed) + +This is the same guarantee as the old cluster and the alternative +active-active design. + +** Active-active vs. hot standby (aka primary-backup) + +An active-active cluster allows clients to connect to any broker in +the cluster. If a broker fails, clients can fail-over to any other +live broker. + +A hot-standby cluster has only one active broker at a time (the +"primary") and one or more brokers on standby (the "backups"). Clients +are only served by the leader, clients that connect to a backup are +redirected to the leader. The backpus are kept up-to-date in real time +by the primary, if the primary fails a backup is elected to be the new +primary. + +Aside: A cold-standby cluster is possible using a standalone broker, +CMAN and shared storage. In this scenario only one broker runs at a +time writing to a shared store. If it fails, another broker is started +(by CMAN) and recovers from the store. This bears investigation but +the store recovery time is probably too long for failover. + +** Why hot standby? + +Active-active has some advantages: +- Finding a broker on startup or failover is simple, just pick any live broker. +- All brokers are always running in active mode, there's no +- Distributing clients across brokers gives better performance, but see [1]. +- A broker failure affects only clients connected to that broker. + +The main problem with active-active is co-ordinating consumers of the +same queue on multiple brokers such that there are no duplicates in +normal operation. There are 2 approaches: + +Predictive: each broker predicts which messages others will take. This +the main weakness of the old design so not appealing. + +Locking: brokers "lock" a queue in order to take messages. This is +complex to implement, its not straighforward to determine the most +performant strategie for passing the lock. + +Hot-standby removes this problem. Only the primary can modify queues +so it just has to tell the backups what it is doing, there's no +locking. + +The primary can enqueue messages and replicate asynchronously - +exactly like the store does, but it "writes" to the replicas over the +network rather than writing to disk. + +** Failover in a hot-standby cluster. + +Hot-standby has some potential performance issues around failover: + +- Failover "spike": when the primary fails every client will fail over + at the same time, putting strain on the system. + +- Until a new primary is elected, cluster cannot serve any clients or + redirect clients to the primary. + +We want to minimize the number of re-connect attempts that clients +have to make. The cluster can use a well-known algorithm to choose the +new primary (e.g. round robin on a known sequence of brokers) so that +clients can guess the new primary correctly in most cases. + +Even if clients do guess correctly it may be that the new primary is +not yet aware of the death of the old primary, which is may to cause +multiple failed connect attempts before clients eventually get +connected. We will need to prototype to see how much this happens in +reality and how we can best get clients redirected. + +** Threading and performance. + +The primary-backup cluster operates analogously to the way the disk store does now: +- use the same MessageStore interface as the store to interact with the broker +- use the same asynchronous-completion model for replicating messages. +- use the same recovery interfaces (?) for new backups joining. + +Re-using the well-established store design gives credibility to the new cluster design. + +The single CPG dispatch thread was a severe performance bottleneck for the old cluster. + +The primary has the same threading model as a a standalone broker with +a store, which we know that this performs well. + +If we use CPG for replication of messages, the backups will receive +messages in the CPG dispatch thread. To get more concurency, the CPG +thread can dump work onto internal PollableQueues to be processed in +parallel. + +Messages from the same broker queue need to go onto the same +PollableQueue. There could be a separate PollableQueue for each broker +queue. If that's too resource intensive we can use a fixed set of +PollableQueues and assign broker queues to PollableQueues via hashing +or round robin. + +Another possible optimization is to use multiple CPG queues: one per +queue or a hashed set, to get more concurrency in the CPG layer. The +old cluster is not able to keep CPG busy. + +TODO: Transactions pose a challenge with these concurrent models: how +to co-ordinate multiple messages being added (commit a publish or roll +back an accept) to multiple queues so that all replicas end up with +the same message sequence while respecting atomicity. + +** Use of CPG + +CPG provides several benefits in the old cluster: +- tracking membership (essential for determining the primary) +- handling "spit brain" (integrates with partition support from CMAN) +- reliable multicast protocol to distribute messages. + +I believe we still need CPG for membership and split brain. We could +experiment with sending the bulk traffic over AMQP conections. + +** Flow control + +Need to ensure that +1) In-memory internal queues used by the cluster don't overflow. +2) The backups don't fall too far behind on processing CPG messages + +** Recovery +When a new backup joins an active cluster it must get a snapshot +from one of the other backups, or the primary if there are none. In +store terms this is "recovery" (old cluster called it an "update) + +Compared to old cluster we only replidate well defined data set of the store. +This is the crucial sore spot of old cluster. + +We can also replicated it more efficiently by recovering queues in +reverse (LIFO) order. That means as clients actively consume messages +from the front of the queue, they are redeucing the work we have to do +in recovering from the back. (NOTE: this may not be compatible with +using the same recovery interfaces as the store.) + +** Selective replication +In this model it's easy to support selective replication of individual queues via +configuration. +- Explicit exchange/queue declare argument and message boolean: x-qpid-replicate. + Treated analogously to persistent/durable properties for the store. +- if not explicitly marked, provide a choice of default + - default is replicate (replicated message on replicated queue) + - default is don't replicate + - default is replicate persistent/durable messages. + +** Inconsistent errors + +The new design eliminates most sources of inconsistent errors in the +old design (connections, sessions, security, management etc.) and +eliminates the need to stall the whole cluster till an error is +resolved. We still have to handle inconsistent store errors when store +and cluster are used together. + +We also have to include error handling in the async completion loop to +guarantee N-way at least once: we should only report success to the +client when we know the message was replicated and stored on all N-1 +backups. + +TODO: We have a lot more options than the old cluster, need to figure +out the best approach, or possibly allow mutliple approaches. Need to +go thru the various failure cases. We may be able to do recovery on a +per-queue basis rather than restarting an entire node. + +** New members joining + +We should be able to catch up much faster than the the old design. A +new backup can catch up ("recover") the current cluster state on a +per-queue basis. +- queues can be updated in parallel +- "live" updates avoid the the "endless chase" + +During a "live" update several things are happening on a queue: +- clients are publishing messages to the back of the queue, replicated to the backup +- clients are consuming messages from the front of the queue, replicated to the backup. +- the primary is sending pre-existing messages to the new backup. + +The primary sends pre-existing messages in LIFO order - starting from +the back of the queue, at the same time clients are consuming from the front. +The active consumers actually reduce the amount of work to be done, as there's +no need to replicate messages that are no longer on the queue. + +* Steps to get there + +** Baseline replication +Validate the overall design get initial notion of performance. Just +message+wiring replication, no update/recovery for new members joining, +single CPG dispatch thread on backups, no failover, no transactions. + +** Failover +Electing primary, backups redirect to primary. Measure failover time +for large # clients. Strategies to minimise number of retries after a +failure. + +** Flow Control +Keep internal queues from over-flowing. Similar to internal flow control in old cluster. +Needed for realistic performance/stress tests + +** Concurrency +Experiment with multiple threads on backups, multiple CPG groups. + +** Recovery/new member joining +Initial status handshake for new member. Recovering queues from the back. + +** Transactions +TODO: How to implement transactions with concurrency. Worst solution: +a global --cluster-use-transactions flag that forces single thread +mode. Need to find a better solution. diff --git a/cpp/design_docs/new-cluster-design.txt b/cpp/design_docs/new-cluster-design.txt index 7adb46fee3..936530a39a 100644 --- a/cpp/design_docs/new-cluster-design.txt +++ b/cpp/design_docs/new-cluster-design.txt @@ -17,7 +17,6 @@ # under the License. * A new design for Qpid clustering. - ** Issues with current design. The cluster is based on virtual synchrony: each broker multicasts @@ -84,19 +83,21 @@ context. ** A new cluster design. -Clearly defined interface between broker code and cluster plug-in. +1. Clearly defined interface between broker code and cluster plug-in. -Replicate queue events rather than client data. -- Broker behavior only needs to match per-queue. -- Smaller amount of code (queue implementation) that must behave predictably. -- Events only need be serialized per-queue, allows concurrency between queues +2. Replicate queue events rather than client data. + - Only requires consistent enqueue order. + - Events only need be serialized per-queue, allows concurrency between queues + - Allows for replicated and non-replicated queues. -Use a moving queue ownership protocol to agree order of dequeues. -No longer relies on identical state and lock-step behavior to cause -identical dequeues on each broker. +3. Use a lock protocol to agree order of dequeues: only the broker + holding the lock can acqiure & dequeue. No longer relies on + identical state and lock-step behavior to cause identical dequeues + on each broker. -Each queue has an associated thread-context. Events for a queue are executed -in that queues context, in parallel with events for other queues. +4. Use multiple CPG groups to process different queues in + parallel. Use a fixed set of groups and hash queue names to choose + the group for each queue. *** Requirements @@ -149,7 +150,7 @@ a release-queue event, allowing another interested broker to take ownership. *** Asynchronous completion of accept -### HERE + In acknowledged mode a message is not forgotten until it is accepted, to allow for requeue on rejection or crash. The accept should not be completed till the message has been forgotten. @@ -162,19 +163,32 @@ On receiving an accept the broker: NOTE: The message store does not currently implement asynchronous completions of accept, this is a bug. +*** Multiple CPG groups. + +The old cluster was bottlenecked by processing everything in a single +CPG deliver thread. + +The new cluster uses a set of CPG groups, one per core. Queue names +are hashed to give group indexes, so statistically queues are likely +to be spread over the set of groups. + +Operations on a given queue always use the same group, so we have +order within each queue, but operations on different queues can use +different groups giving greater throughput sending to CPG and multiple +handler threads to process CPG messages. + ** Inconsistent errors. -The new design eliminates most sources of inconsistent errors -(connections, sessions, security, management etc.) The only points -where inconsistent errors can occur are at enqueue and dequeue (most -likely store-related errors.) +An inconsistent error means that after multicasting an enqueue, accept +or dequeue, some brokers succeed in processing it and others fail. -The new design can use the exisiting error-handling protocol with one -major improvement: since brokers are no longer required to maintain -identical state they do not have to stall processing while an error is -being resolved. +The new design eliminates most sources of inconsistent errors in the +old broker: connections, sessions, security, management etc. Only +store journal errors remain. -#TODO: The only source of dequeue errors is probably an unrecoverable journal failure. +The new inconsistent error protocol is similar to the old one with one +major improvement: brokers do not have to stall processing while an +error is being resolved. ** Updating new members @@ -193,60 +207,44 @@ catch up (which is not guaranteed to happen in a bounded time.) With the new cluster design only exchanges, queues, bindings and messages need to be replicated. -Update of wiring (exchanges, queues, bindings) is the same as current -design. - -Update of messages is different: -- per-queue rather than per-broker, separate queues can be updated in parallel. -- updates queues in reverse order to eliminate unbounded catch-up -- does not require updater & updatee to stall during update. +We update individual objects (queues and exchanges) independently. +- create queues first, then update all queues and exchanges in parallel. +- multiple updater threads, per queue/exchange. -Replication events, multicast to cluster: -- enqueue(q,m): message m pushed on back of queue q . -- acquire(q,m): mark m acquired -- dequeue(q,m): forget m. -Messages sent on update connection: -- update_front(q,m): during update, receiver pushes m to *front* of q -- update_done(q): during update, update of q is complete. +Queue updater: +- marks the queue position at the sync point +- sends messages starting from the sync point working towards the head of the queue. +- send "done" message. -Updater: -- when updatee joins set iterator i = q.end() -- while i != q.begin(): --i; send update_front(q,*i) to updatee -- send update_done(q) to updatee +Queue updatee: +- enqueues received from CPG: add to back of queue as normal. +- dequeues received from CPG: apply if found, else save to check at end of update. +- messages from updater: add to the *front* of the queue. +- update complete: apply any saved dequeues. -Updatee: -- q initially in locked state, can't dequeue locally. -- start processing replication events for q immediately (enqueue, dequeue, acquire etc.) -- receive update_front(q,m): q.push_front(m) -- receive update_done(q): q can be unlocked for local dequeing. +Exchange updater: +- updater: send snapshot of exchange as it was at the sync point. -Benefits: -- Stall only for wiring update: updater & updatee can process multicast messages while messages are updated. -- No unbounded catch-up: update consists of at most N update_front() messages where N=q.size() at start of update. -- During update consumers actually help by removing messages before they need to be updated. -- Needs no separate "work to do" queue, only the broker queues themselves. +Exchange updatee: +- queue exchange operations after the sync point. +- when snapshot is received: apply saved operations. -# TODO how can we recover from updater crashing before update complete? -# Clear queues that are not updated & send request for udpates on those queues? +Note: +- Updater is active throughout, no stalling. +- Consuming clients actually reduce the size of the update. +- Updatee stalls clients until the update completes. + (Note: May be possible to avoid updatee stall as well, needs thought) -# TODO updatee may receive a dequeue for a message it has not yet seen, needs -# to hold on to that so it can drop the message when it is seen. -# Similar problem exists for wiring? +** Internal cluster interface -** Cluster API - -The new cluster API is similar to the MessageStore interface. -(Initially I thought it would be an extension of the MessageStore interface, -but as the design develops it seems better to make it a separate interface.) +The new cluster interface is similar to the MessageStore interface, but +provides more detail (message positions) and some additional call +points (e.g. acquire) The cluster interface captures these events: - wiring changes: queue/exchange declare/bind - message enqueued/acquired/released/rejected/dequeued. - -The cluster will require some extensions to the Queue: -- Queues can be "locked", locked queues are ignored by IO-driven output. -- Cluster must be able to apply queue events from the cluster to a queue. - These appear to fit into existing queue operations. +- transactional events. ** Maintainability @@ -273,106 +271,48 @@ A number of specific ways the code will be simplified: ** Performance -The only way to verify the relative performance of the new design is -to prototype & profile. The following points suggest the new design -may scale/perform better: - -Some work moved from virtual synchrony thread to connection threads: -- All connection/session logic moves to connection thread. -- Exchange routing logic moves to connection thread. -- On local broker dequeueing is done in connection thread -- Local broker dequeue is IO driven as for a standalone broker. - -For queues with all consumers on a single node dequeue is all -IO-driven in connection thread. Pay for time-sharing only if queue has -consumers on multiple brokers. - -Doing work for different queues in parallel scales on multi-core boxes when -there are multiple queues. - -One difference works against performance, thre is an extra -encode/decode. The old design multicasts raw client data and decodes -it in the virtual synchrony thread. The new design would decode -messages in the connection thread, re-encode them for multicast, and -decode (on non-local brokers) in the virtual synchrony thread. There -is extra work here, but only in the *connection* thread: on a -multi-core machine this happens in parallel for every connection, so -it probably is not a bottleneck. There may be scope to optimize -decode/re-encode by re-using some of the original encoded data, this -could also benefit the stand-alone broker. - -** Asynchronous queue replication - -The existing "asynchronous queue replication" feature maintains a -passive backup passive backup of queues on a remote broker over a TCP -connection. - -The new cluster replication protocol could be re-used to implement -asynchronous queue replication: its just a special case where the -active broker is always the queue owner and the enqueue/dequeue -messages are sent over a TCP connection rather than multicast. - -The new update update mechanism could also work with 'asynchronous -queue replication', allowing such replication (over a TCP connection -on a WAN say) to be initiated after the queue had already been created -and been in use (one of the key missing features). - -** Increasing Concurrency and load sharing - -The current cluster is bottlenecked by processing everything in the -CPG deliver thread. By removing the need for identical operation on -each broker, we open up the possiblility of greater concurrency. - -Handling multicast enqueue, acquire, accpet, release etc: concurrency -per queue. Operatons on different queues can be done in different -threads. - -The new design does not force each broker to do all the work in the -CPG thread so spreading load across cluster members should give some -scale-up. - -** Misc outstanding issues & notes - -Replicating wiring -- Need async completion of wiring commands? -- qpid.sequence_counter: need extra work to support in new design, do we care? - -Cluster+persistence: -- finish async completion: dequeue completion for store & cluster -- cluster restart from store: clean stores *not* identical, pick 1, all others update. -- need to generate cluster ids for messages recovered from store. - -Live updates: we don't need to stall brokers during an update! -- update on queue-by-queue basis. -- updatee locks queues during update, no dequeue. -- update in reverse: don't update messages dequeued during update. -- updatee adds update messages at front (as normal), replicated messages at back. -- updater starts from back, sends "update done" when it hits front of queue. - -Flow control: need to throttle multicasting -1. bound the number of outstanding multicasts. -2. ensure the entire cluster keeps up, no unbounded "lag" -The existing design uses read-credit to solve 1., and does not solve 2. -New design should stop reading on all connections while flow control -condition exists? - -Can federation also be unified, at least in configuration? - -Consider queues (and exchanges?) as having "reliability" attributes: -- persistent: is the message stored on disk. -- backed-up (to another broker): active/passive async replication. -- replicated (to a cluster): active/active multicast replication to cluster. -- federated: federation link to a queue/exchange on another broker. - -"Reliability" seems right for the first 3 but not for federation, is -there a better term? - -Clustering and scalability: new design may give us the flexibility to -address scalability as part of cluster design. Think about -relationship to federation and "fragmented queues" idea. - -* Design debates/descisions +The standalone broker processes _connections_ concurrently, so CPU +usage increases as you add more connections. + +The new cluster processes _queues_ concurrently, so CPU usage increases as you +add more queues. + +In both cases, CPU usage peaks when the number of "units of + concurrency" (connections or queues) goes above the number of cores. + +When all consumers on a queue are connected to the same broker the new +cluster uses the same messagea allocation threading/logic as a +standalone broker, with a little extra asynchronous book-keeping. + +If a queue has multiple consumers connected to multiple brokers, the +new cluster time-shares the queue which is less efficient than having +all consumers on a queue connected to the same broker. +** Flow control +New design does not queue up CPG delivered messages, they are +processed immediately in the CPG deliver thread. This means that CPG's +flow control is sufficient for qpid. + +** Live upgrades + +Live upgrades refers to the ability to upgrade a cluster while it is +running, with no downtime. Each brokers in the cluster is shut down, +and then re-started with a new version of the broker code. + +To achieve this +- Cluster protocl XML file has a new element attached + to each method. This is the version at which the method was added. +- New versions can only add methods, existing methods cannot be changed. +- The cluster handshake for new members includes the protocol version + at each member. +- The cluster's version is the lowest version among its members. +- A newer broker can join and older cluster. When it does, it must restrict + itself to speaking the older version protocol. +- When the cluster version increases (because the lowest version member has left) + the remaining members may move up to the new version. + + +* Design debates ** Active/active vs. active passive An active-active cluster can be used in an active-passive mode. In @@ -385,7 +325,7 @@ An active/passive implementation allows some simplifications over active/active: - can do immediate local enqueue and still guarantee order. Active/passive introduces a few extra requirements: -- Exactly one broker hast to take over if primary fails. +- Exactly one broker has to take over if primary fails. - Passive members must refuse client connections. - On failover, clients must re-try all known addresses till they find the active member. @@ -393,43 +333,17 @@ Active/active benefits: - A broker failure only affects the subset of clients connected to that broker. - Clients can switch to any other broker on failover - Backup brokers are immediately available on failover. -- Some load sharing: reading from client + multicast only done on direct node. - -Active/active drawbacks: -- Co-ordinating message acquisition may impact performance (not tested) -- Code may be more complex that active/passive. +- As long as a client can connect to any broker in the cluster, it can be served. Active/passive benefits: -- Don't need message allocation strategy, can feed consumers at top speed. -- Code may be simpler than active/active. +- Don't need to replicate message allocation, can feed consumers at top speed. Active/passive drawbacks: - All clients on one node so a failure affects every client in the system. - After a failure there is a "reconnect storm" as every client reconnects to the new active node. - After a failure there is a period where no broker is active, until the other brokers realize the primary is gone and agree on the new primary. - Clients must find the single active node, may involve multiple connect attempts. +- No service if a partition separates a client from the active broker, + even if the client can see other brokers. -** Total ordering. - -Initial thinking: allow message ordering to differ between brokers. -New thinking: use CPG total ordering, get identical ordering on all brokers. -- Allowing variation in order introduces too much chance of unexpected behavior. -- Usign total order allows other optimizations, see Message Identifiers below. - -** Message identifiers. - -Initial thinking: message ID = CPG node id + 64 bit sequence number. -This involves a lot of mapping between cluster IDs and broker messsages. - -New thinking: message ID = queue name + queue position. -- Removes most of the mapping and memory management for cluster code. -- Requires total ordering of messages (see above) - -** Message rejection - -Initial thinking: add special reject/rejected points to cluster interface so -rejected messages could be re-queued without multicast. -New thinking: treat re-queueing after reject as entirely new message. -- Simplifies cluster interface & implementation -- Not on the critical path. diff --git a/cpp/design_docs/new-cluster-plan.txt b/cpp/design_docs/new-cluster-plan.txt index 781876e55a..626e443be7 100644 --- a/cpp/design_docs/new-cluster-plan.txt +++ b/cpp/design_docs/new-cluster-plan.txt @@ -17,376 +17,156 @@ # specific language governing permissions and limitations # under the License. +* Status of impementation -Notes on new cluster implementation. See also: new-cluster-design.txt +Meaning of priorities: +[#A] Essential for basic functioning. +[#B] Required for first release. +[#C] Can be addressed in a later release. -* Implementation plan. +The existig prototype is bare bones to do performance benchmarks: +- Implements publish and consumer locking protocol. +- Defered delivery and asynchronous completion of message. +- Optimize the case all consumers are on the same node. +- No new member updates, no failover updates, no transactions, no persistence etc. -Co-existence with old cluster code and tests: -- Separate plugin cluster2, options --cluster2-*. Eventually renamed to replace cluster. -- Double up tests with old version/new version as the new code develops. +Prototype code is on branch qpid-2920-active, in cpp/src/qpid/cluster/exp/ -Minimal POC for message delivery & perf test. -- no wiring replication, no updates, no failover, no persistence, no async completion. -- just implement publish and acquire/dequeue locking protocol. -- optimize the special case where all consumers are on the same node. -- measure performance: compare active-passive and active-active modes of use. +** Similarities to existing cluster. -Full implementation of transient cluster -- Update (based on existing update), async completion etc. -- Passing all existing transient cluster tests. +/Active-active/: the new cluster can be a drop-in replacement for the +old, existing tests & customer deployment configurations are still +valid. -Persistent cluster -- Make sure async completion works correctly. -- InitialStatus protoocl etc. to support persistent start-up (existing code) -- cluster restart from store: stores not identical. Load one, update the rest. - - assign cluster ID's to messages recovered from store, don't replicate. +/Virtual synchrony/: Uses corosync to co-ordinate activity of members. -Improved update protocol -- per-queue, less stalling, bounded catch-up. +/XML controls/: Uses XML to define the primitives multicast to the +cluster. -* Task list +** Differences with existing cluster. -** TODO [#A] Minimal POC: publish/acquire/dequeue protocol. +/Report rather than predict consumption/: brokers explicitly tell each +other which messages have been acquired or dequeued. This removes the +major cause of bugs in the existing cluster. -NOTE: as implementation questions arise, take the easiest option and make -a note for later optimization/improvement. +/Queue consumer locking/: to avoid duplicates only one broker can acquire or +dequeue messages at a time - while has the consume-lock on the +queue. If multiple brokers are consuming from the same queue the lock +is passed around to time-share access to the queue. -*** Tests -- python test: 4 senders, numbered messages, 4 receivers, verify message set. -- acquire then release messages: verify can be dequeued on any member -- acquire then kill broker: verify can be dequeued other members. -- acquire then reject: verify goes on alt-exchange once only. +/Per-queue concurrency/: uses a fixed-size set of CPG groups (reflecting +the concurrency of the host) to allow concurrent processing on +different queues. Queues are hashed onto the groups. -*** DONE broker::Cluster interface and call points. +* Completed tasks +** DONE [#A] Minimal POC: publish/acquire/dequeue protocol. + CLOSED: [2011-10-05 Wed 16:03] -Initial interface commited. +Defines broker::Cluster interface and call points. +Initial interface commite -*** Main classes +Main classes +Core: central object holding cluster classes together (replaces cluster::Cluster) +BrokerContext: implements broker::Cluster interface. +QueueContext: Attached to a broker::Queue, holds cluster status. +MessageHolder:holds local messages while they are being enqueued. -BrokerHandler: -- implements broker::Cluster intercept points. -- sends mcast events to inform cluster of local actions. -- thread safe, called in connection threads. +Implements multiple CPG groups for better concurrency. -LocalMessageMap: -- Holds local messages while they are being enqueued. -- thread safe: called by both BrokerHandler and MessageHandler - -MessageHandler: -- handles delivered mcast messages related to messages. -- initiates local actions in response to mcast events. -- thread unsafe, only called in deliver thread. -- maintains view of cluster state regarding messages. +** DONE [#A] Large message replication. + CLOSED: [2011-10-05 Wed 17:22] +Multicast using fixed-size (64k) buffers, allow fragmetation of messages across buffers (frame by frame) -QueueOwnerHandler: -- handles delivered mcast messages related to queue consumer ownership. -- thread safe, called in deliver, connection and timer threads. -- maintains view of cluster state regarding queue ownership. - -cluster::Core: class to hold new cluster together (replaces cluster::Cluster) -- thread safe: manage state used by both MessageHandler and BrokerHandler - -The following code sketch illustrates only the "happy path" error handling -is omitted. - -*** BrokerHandler -Types: -- struct QueuedMessage { Message msg; QueueName q; SequenceNumber position; } -- struct - -NOTE: -- Messages on queues are identified by a queue name + a position. -- Messages being routed are identified by a sequence number. - -Members: -- thread_local bool noReplicate // suppress replication. -- thread_local bool isRouting // suppress operations while routing -- Message localMessage[SequenceNumber] // local messages being routed. -- thread_local SequenceNumber routingSequence - -NOTE: localMessage is also modified by MessageHandler. - -broker::Cluster intercept functions: - -routing(msg) - if noReplicate: return - # Supress everything except enqueues while we are routing. - # We don't want to replicate acquires & dequeues caused by an enqueu, - # e.g. removal of messages from ring/LV queues. - isRouting = true - -enqueue(qmsg): - if noReplicate: return - if routingSequence == 0 # thread local - routingSequence = nextRoutingSequence() - mcast create(encode(qmsg.msg),routingSeq) - mcast enqueue(qmsg.q,routingSeq) - -routed(msg): - if noReplicate: return - isRouting = false - -acquire(qmsg): - if noReplicate: return - if isRouting: return # Ignore while we are routing a message. - if msg.id: mcast acquire(qmsg) - -release(QueuedMessage) - if noReplicate: return - if isRouting: return # Ignore while we are routing a message. - mcast release(qmsg) - -accept(QueuedMessage): - if noReplicate: return - if isRouting: return # Ignore while we are routing a message. - mcast accept(qmsg) - -reject(QueuedMessage): - isRejecting = true - mcast reject(qmsg) - -# FIXME no longer needed? -drop(QueuedMessage) - cleanup(qmsg) - -*** MessageHandler and mcast messages -Types: -- struct QueueEntry { QueuedMessage qmsg; NodeId acquired; } -- struct QueueKey { MessageId id; QueueName q; } -- typedef map Queue -- struct Node { Message routing[SequenceNumber]; list acquired; } - -Members: -- QueueEntry enqueued[QueueKey] -- Node node[NodeId] - -Mcast messages in Message class: - -create(msg,seq) - if sender != self: node[sender].routing[seq] = decode(msg) - -enqueue(q,seq): - id = (sender,seq) - if sender == self: - enqueued[id,q] = (localMessage[seq], acquired=None) - else: - msg = sender.routing[seq] - enqueued[id,q] = (qmsg, acquired=None) - with noReplicate=true: qmsg = broker.getQueue(q).push(msg) - -routed(seq): - if sender == self: localMessage.erase(msg.id.seq) - else: sender.routing.erase(seq) - -acquire(id,q): - enqueued[id,q].acquired = sender - node[sender].acquired.push_back((id,q)) - if sender != self: - with noReplicate=true: broker.getQueue(q).acquire(enqueued[id,q]) - -release(id,q) - enqueued[id,q].acquired = None - node[sender].acquired.erase((id,q)) - if sender != self - with noReplicate=true: broker.getQueue(q).requeue(enqueued[id,q]) - -reject(id,q): - sender.routing[id] = enqueued[id,q] # prepare for re-queueing - -rejected(id,q) - sender.routing.erase[id] - -dequeue(id,q) - entry = enqueued[id,q] - enqueued.erase[id,q] - node[entry.acquired].acquired.erase(id,q) - if sender != self: - with noReplicate=true: broker.getQueue(q).dequeue(entry.qmsg) - -member m leaves cluster: - for key in node[m].acquired: - release(key.id, key.q) - node.erase(m) - -*** Queue consumer locking - -When a queue is locked it does not deliver messages to its consumers. - -New broker::Queue functions: -- stopConsumers(): set consumersStopped flag, wait for currently busy consumers to exit. -- startConsumers(): reset consumersStopped flag - -Implementation sketch, locking omitted: - -void Queue::stopConsumers() { - consumersStopped = true; - while (consumersBusy) consumersBusyMonitor.wait(); -} - -void Queue::startConsumers() { - consumersStopped = false; - listeners.notify(); -} - -bool Queue::dispatch(consumer) { - if (consumersStopped) return false; - ++consumersBusy; - do_regular_dispatch_body() - if (--consumersBusy == 0) consumersBusyMonitor.notify(); -} - -*** QueueOwnerHandler - -Invariants: -- Each queue is owned by at most one node at any time. -- Each node is interested in a set of queues at any given time. -- A queue is un-owned if no node is interested. - -The queue owner releases the queue when -- it loses interest i.e. queue has no consumers with credit. -- a configured time delay expires and there are other interested nodes. - -The owner mcasts release(q). On delivery the new queue owner is the -next node in node-id order (treating nodes as a circular list) -starting from the old owner that is interested in the queue. - -Queue consumers initially are stopped, only started when we get -ownership from the cluster. - -Thread safety: called by deliver, connection and timer threads, needs locking. - -Thread safe object per queue holding queue ownership status. -Called by deliver, connection and timer threads. - -class QueueOwnership { - bool owned; - Timer timer; - BrokerQueue q; - - drop(): # locked - if owned: - owned = false - q.stopConsumers() - mcast release(q.name, false) - timer.stop() - - take(): # locked - if not owned: - owned = true - q.startConsumers() - timer.start(timeout) - - timer.fire(): drop() -} - -Data Members, only modified/examined in deliver thread: -- typedef set ConsumerSet -- map consumers -- map owner +* Open questions -Thread safe data members, accessed in connection threads (via BrokerHandler): -- map ownership +** TODO [#A] Queue sequence numbers vs. independant message IDs. + SCHEDULED: <2011-10-07 Fri> -Multicast messages in QueueOwner class: +Current prototype uses queue sequence numbers to identify +message. This is tricky for updating new members as the sequence +numbers are only known on delivery. -consume(q): - if sender==self and consumers[q].empty(): ownership[q].take() - consumers[q].insert(sender) +Independent message IDs that can be generated and sent with the message simplify +this and potentially allow performance benefits by relaxing total ordering. +However they imply additional map lookups that might hurt performance. -release(q): - asssert(owner[q] == sender and owner[q] in consumers[q]) - owner[q] = circular search from sender in consumers[q] - if owner==self: ownership[q].take() +- [X] Prototype independent message IDs, check performance. +Throughput worse by 30% in contented case, 10% in uncontended. +Sticking with queue sequence numbers. -cancel(q): - assert(queue[q].owner != sender) # sender must release() before cancel() - consumers[q].erase(sender) +* Outstanding Tasks +** TODO [#A] Defer and async completion of wiring commands. -member-leaves: - for q in queue: if owner[q] = left: left.release(q) +Testing requirement: Many tests assume wiring changes are visible +across the cluster once the commad completes. -Need 2 more intercept points in broker::Cluster: +Name clashes: need to avoid race if same name queue/exchange declared +on 2 brokers simultaneously -consume(q,consumer,consumerCount) - Queue::consume() - if consumerCount == 1: mcast consume(q) +** TODO [#A] Passing all existing cluster tests. -cancel(q,consumer,consumerCount) - Queue::cancel() - if consumerCount == 0: - ownership[q].drop() - mcast cancel(q) +The new cluster should be a drop-in replacement for the old, so it +should be able to pass all the existing tests. -#TODO: lifecycle, updating cluster data structures when queues are destroyed - -*** Increasing concurrency -The major performance limitation of the old cluster is that it does -everything in the single CPG deliver thread context. - -We can get additional concurrency by creating a thread context _per queue_ -for queue operations: enqueue, acquire, accept etc. - -We associate a PollableQueue of queue operations with each AMQP queue. -The CPG deliver thread would -- build messages and associate with cluster IDs. -- push queue ops to the appropriate PollableQueue to be dispatched the queues thread. - -Serializing operations on the same queue avoids contention, but takes advantage -of the independence of operations on separate queues. +** TODO [#A] Update to new members joining. -*** Re-use of existing cluster code -- re-use Event -- re-use Multicaster -- re-use same PollableQueueSetup (may experiment later) -- new Core class to replace Cluster. -- keep design modular, keep threading rules clear. +Need to resolve [[Queue sequence numbers vs. independant message IDs]] first. +- implicit sequence numbers are more tricky to replicate to new member. -** TODO [#B] Large message replication. -Multicast should encode messages in fixed size buffers (64k)? -Can't assume we can send message in one chunk. -For 0-10 can use channel numbers & send whole frames packed into larger buffer. -** TODO [#B] Transaction support. -Extend broker::Cluster interface to capture transaction context and completion. -Sequence number to generate per-node tx IDs. -Replicate transaction completion. -** TODO [#B] Batch CPG multicast messages -The new cluster design involves a lot of small multicast messages, -they need to be batched into larger CPG messages for efficiency. -** TODO [#B] Genuine async completion -Replace current synchronous waiting implementation with genuine async completion. +Update individual objects (queues and exchanges) independently. +- create queues first, then update all queues and exchanges in parallel. +- multiple updater threads, per queue/exchange. +- updater sends messages to special exchange(s) (not using extended AMQP controls) + +Queue updater: +- marks the queue position at the sync point +- sends messages starting from the sync point working towards the head of the queue. +- send "done" message. +Note: updater remains active throughout, consuming clients actually reduce the +size of the update. -Test: enhance test_store.cpp to defer enqueueComplete till special message received. +Queue updatee: +- enqueues received from CPG: add to back of queue as normal. +- dequeues received from CPG: apply if found, else save to check at end of update. +- messages from updater: add to the *front* of the queue. +- update complete: apply any saved dequeues. -Async callback uses *requestIOProcessing* to queue action on IO thread. +Exchange updater: +- updater: send snapshot of exchange as it was at the sync point. -** TODO [#B] Async completion of accept when dequeue completes. -Interface is already there on broker::Message, just need to ensure -that store and cluster implementations call it appropriately. +Exchange updatee: +- queue exchange operations after the sync point. +- when snapshot is received: apply saved operations. -** TODO [#B] Replicate wiring. -From messageStore create/destroy/bind, replicate encoded declare/destroy/bind command. +Updater remains active throughout. +Updatee stalls clients until the update completes. -** TODO [#B] New members joining - first pass +Updating queue/exchange/binding objects is via the same encode/decode +that is used by the store. Updatee to use recovery interfaces to +recover? -Re-use update code from old cluster but don't replicate sessions & -connections. +** TODO [#A] Failover updates to client. +Implement the amq.failover exchange to notify clients of membership. -Need to extend it to send cluster IDs with messages. +** TODO [#B] Initial status protocol. +Handshake to give status of each broker member to new members joining. +Status includes +- persistent store state (clean, dirty) +- cluster protocol version. -Need to replicate the queue ownership data as part of the update. +** TODO [#B] Replace boost::hash with our own hash function. +The hash function is effectively part of the interface so +we need to be sure it doesn't change underneath us. -** TODO [#B] Persistence support. -InitialStatus protoocl etc. to support persistent start-up (existing code) +** TODO [#B] Persistent cluster support. +Initial status protoocl to support persistent start-up (see existing code) Only one broker recovers from store, update to others. Assign cluster IDs to messages recovered from store, don't replicate. See Queue::recover. -** TODO [#B] Handle other ways that messages can leave a queue. - -Other ways (other than via a consumer) that messages are take off a queue. - -NOTE: Not controlled by queue lock, how to make them consistent? - +** TODO [#B] Management support +Replicate management methods that modify queues - e.g. move, purge. Target broker may not have all messages on other brokers for purge/destroy. - Queue::move() - need to wait for lock? Replicate? - Queue::get() - ??? @@ -395,66 +175,48 @@ Target broker may not have all messages on other brokers for purge/destroy. Need to add callpoints & mcast messages to replicate these? -** TODO [#B] Flow control for internal queues. - -Need to bound the size of internal queues: delivery and multicast. -- stop polling for read on client connections when we reach a bound. -- restart polling when we get back under it. - -That will stop local multicasting, we still have to deal with remote -multicasting (note existing cluster does not do this.) Something like: -- when over bounds multicast a flow-control event. -- on delivery of flow-control all members stop polling to read client connections -- when back under bounds send flow-control-end, all members resume -- if flow-controling member dies others resume - -** TODO [#B] Integration with transactions. -Do we want to replicate during transaction & replicate commit/rollback -or replicate only on commit? -No integration with DTX transactions. -** TODO [#B] Make new cluster work with replication exchange. -Possibly re-use some common logic. Replication exchange is like clustering -except over TCP. -** TODO [#B] Better concurrency, scalabiility on multi-cores. -Introduce PollableQueue of operations per broker queue. Queue up mcast -operations (enqueue, acquire, accept etc.) to be handled concurrently -on different queue. Performance testing to verify improved scalability. -** TODO [#C] Async completion for declare, bind, destroy queues and exchanges. -Cluster needs to complete these asynchronously to guarantee resources -exist across the cluster when the command completes. +** TODO [#B] TX transaction support. +Extend broker::Cluster interface to capture transaction context and completion. +Running brokers exchange TX information. +New broker update includes TX information. -** TODO [#C] Allow non-replicated exchanges, queues. + // FIXME aconway 2010-10-18: As things stand the cluster is not + // compatible with transactions + // - enqueues occur after routing is complete + // - no call to Cluster::enqueue, should be in Queue::process? + // - no transaction context associated with messages in the Cluster interface. + // - no call to Cluster::accept in Queue::dequeueCommitted -Set qpid.replicated=false in declare arguments, set flag on Exchange, Queue objects. -- save replicated status to store. -- support in management tools. -Replicated exchange: replicate binds to replicated queues. -Replicated queue: replicate all messages. +** TODO [#B] DTX transaction support. +Extend broker::Cluster interface to capture transaction context and completion. +Running brokers exchange DTX information. +New broker update includes DTX information. -** TODO [#C] New members joining - improved. +** TODO [#B] Async completion of accept. +When this is fixed in the standalone broker, it should be fixed for cluster. -Replicate wiring like old cluster, stall for wiring but not for -messages. Update messages on a per-queue basis from back to front. +** TODO [#B] Network partitions and quorum. +Re-use existing implementation. -Updater: -- stall & push wiring: declare exchanges, queues, bindings. -- start update iterator thread on each queue. -- unstall and process normally while iterator threads run. +** TODO [#B] Review error handling, put in a consitent model. +- [ ] Review all asserts, for possible throw. +- [ ] Decide on fatal vs. non-fatal errors. -Update iterator thread: -- starts at back of updater queue, message m. -- send update_front(q,m) to updatee and advance towards front -- at front: send update_done(q) +** TODO [#B] Implement inconsistent error handling policy. +What to do if a message is enqueued sucessfully on the local broker, +but fails on one or more backups - e.g. due to store limits? +- we have more flexibility, we don't *have* to crash +- but we've loste some of our redundancy guarantee, how should we inform client? -Updatee: -- stall, receive wiring, lock all queues, mark queues "updating", unstall -- update_front(q,m): push m to *front* of q -- update_done(q): mark queue "ready" +** TODO [#C] Allow non-replicated exchanges, queues. -Updatee cannot take the queue consume lock for a queue that is updating. -Updatee *can* push messages onto a queue that is updating. +Set qpid.replicate=false in declare arguments, set flag on Exchange, Queue objects. +- save replicated status to store. +- support in management tools. +Replicated queue: replicate all messages. +Replicated exchange: replicate bindings to replicated queues only. -TODO: Is there any way to eliminate the stall for wiring? +Configurable default? Defaults to true. ** TODO [#C] Refactoring of common concerns. @@ -469,9 +231,46 @@ Look for ways to capitalize on the similarity & simplify the code. In particular QueuedEvents (async replication) strongly resembles cluster replication, but over TCP rather than multicast. -** TODO [#C] Concurrency for enqueue events. -All enqueue events are being processed in the CPG deliver thread context which -serializes all the work. We only need ordering on a per queue basis, can we -enqueue in parallel on different queues and will that improve performance? + ** TODO [#C] Handling immediate messages in a cluster Include remote consumers in descision to deliver an immediate message? +** TODO [#C] Remove old cluster hacks and workarounds +The old cluster has workarounds in the broker code that can be removed. +- [ ] drop code to replicate management model. +- [ ] drop timer workarounds for TTL, management, heartbeats. +- [ ] drop "cluster-safe assertions" in broker code. +- [ ] drop connections, sessions, management from cluster update. +- [ ] drop security workarounds: cluster code now operates after message decoding. +- [ ] drop connection tracking in cluster code. +- [ ] simpler inconsistent-error handling code, no need to stall. + +** TODO [#C] Support for live upgrades. + +Allow brokers in a running cluster to be replaced one-by-one with a new version. +(see new-cluster-design for design notes.) + +The old cluster protocol was unstable because any changes in broker +state caused changes to the cluster protocol.The new design should be +much more stable. + +Points to implement in anticipation of live upgrade: +- Prefix each CPG message with a version number and length. + Version number determines how to decode the message. +- Brokers ignore messages that have a higher version number than they understand. +- Protocol version XML element in cluster.xml, on each control. +- Initial status protocol to include protocol version number. + +New member udpates: use the store encode/decode for updates, use the +same backward compatibility strategy as the store. This allows for +adding new elements to the end of structures but not changing or +removing new elements. + +** TODO [#C] Support for AMQP 1.0. + +* Testing +** TODO [#A] Pass all existing cluster tests. +Requires [[Defer and async completion of wiring commands.]] +** TODO [#A] New cluster tests. +Stress tests & performance benchmarks focused on changes in new cluster: +- concurrency by queues rather than connections. +- different handling shared queues when consuemrs are on different brokers. diff --git a/cpp/docs/api/developer.doxygen.in b/cpp/docs/api/developer.doxygen.in index fd3a9ac621..1e1fddab80 100644 --- a/cpp/docs/api/developer.doxygen.in +++ b/cpp/docs/api/developer.doxygen.in @@ -1029,7 +1029,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN= QPID_MESSAGING_EXTERN= QMF_EXTERN= +PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN= QPID_MESSAGING_EXTERN= QMF_EXTERN= QMFE_EXTERN= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/cpp/docs/api/doxygen_mainpage.h b/cpp/docs/api/doxygen_mainpage.h index cb36d7edb0..9acae52da4 100644 --- a/cpp/docs/api/doxygen_mainpage.h +++ b/cpp/docs/api/doxygen_mainpage.h @@ -266,7 +266,46 @@ * else * session.rollback(); * - * + * + *

Exceptions

+ * + * All exceptions for the messaging API have MessagingException as + * their base class. + + * A common class of exception are those related to processing + * addresses used to create senders and/or receivers. These all have + * AddressError as their base class. + * + * Where there is a syntax error in the address itself, a + * MalformedAddress will be thrown. Where the address is valid, but + * there is an error in interpreting (i.e. resolving) it, a + * ResolutionError - or a sub-class of it - will be thrown. If the + * address has assertions enabled for a given context and the asserted + * node properties are not in fact correct then AssertionFailed will + * be thrown. If the node is not found, NotFound will be thrown. + * + * The loss of the underlying connection (e.g. the TCP connection) + * results in TransportFailure being thrown. If automatic reconnect is + * enabled, this will be caught be the library which will then try to + * reconnect. If reconnection - as configured by the connection + * options - fails, then TransportFailure will be thrown. This can + * occur on any call to the messaging API. + * + * Sending a message may also result in an exception + * (e.g. TargetCapacityExceeded if a queue to which the message is + * delivered cannot enqueue it due to lack of capacity). For + * asynchronous send the exception may not be thrown on the send + * invocation that actually triggers it, but on a subsequent method + * call on the API. + * + * Certain exceptions may render the session invalid; once these + * occur, subsequent calls on the session will throw the same class of + * exception. This is not an intrinsic property of the class of + * exception, but is a result of the current mapping of the API to the + * underlying AMQP 0-10 protocol. You can test whether the session is + * valid at any time using the hasError() and/or checkError() methods + * on Session. + * *

Logging

* * The Qpidd broker and C++ clients can both use environment variables to diff --git a/cpp/docs/api/footer.html b/cpp/docs/api/footer.html index 883410ce25..5a31e81821 100644 --- a/cpp/docs/api/footer.html +++ b/cpp/docs/api/footer.html @@ -25,7 +25,7 @@ Qpid C++ API Reference
-Generated on $datetime for $projectname by doxygen $doxygenversion +Generated on $date for $projectname by doxygen $doxygenversion
diff --git a/cpp/docs/api/user.doxygen.in b/cpp/docs/api/user.doxygen.in index 2728df47e4..ec0fd1361c 100644 --- a/cpp/docs/api/user.doxygen.in +++ b/cpp/docs/api/user.doxygen.in @@ -1021,7 +1021,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN= QPID_MESSAGING_EXTERN= QMF_EXTERN= +PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN= QPID_MESSAGING_EXTERN= QMF_EXTERN= QMFE_EXTERN= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/cpp/docs/man/Makefile.am b/cpp/docs/man/Makefile.am index 14295f73bf..b821568f81 100644 --- a/cpp/docs/man/Makefile.am +++ b/cpp/docs/man/Makefile.am @@ -16,10 +16,29 @@ # specific language governing permissions and limitations # under the License. # + +# Generate makefile from qpidd --help +# +# Note: qiddd.1 is normally a _checked in_ pre-generated file, so that +# make dist does not have to build the entire source just for the man page. +# +# To update the checked-in file (e.g. for a new release) do the following: +# +# - start with a completely clean checkout. +# - make sure there are no modules installed in your configured prefix, +# we don't want to pick up configuration from optional modules +# - do bootstrap; configure +# - in build-dir: cd src; make # build the broker +# - in source-dir: cd docs/man; rm qpidd.1 # remove checked-in man page. +# - in build-dir: cd docs/man; make # make new man page +# - edit qpidd.1 to remove all default values referring to file/directory locations. +# these values will differ between builds depending on configuration. +# - if source-dir != build-dir: copy qpidd.1 from build-dir/docs/man to source-dir/docs/man + dist_man_MANS = qpidd.1 -man_aux = $(dist_man_MANS:.1=.x) -EXTRA_DIST = $(man_aux) generate_manpage groffify_options.sed groffify_template.sed +man_aux = $(dist_man_MANS:.1=.x) +EXTRA_DIST = $(man_aux) generate_manpage groffify_options.sed groffify_template.sed DISTCLEANFILES = $(dist_man_MANS) CLEANFILES=qpidd.1 diff --git a/cpp/docs/man/qpidd.1 b/cpp/docs/man/qpidd.1 new file mode 100644 index 0000000000..d2cff454cf --- /dev/null +++ b/cpp/docs/man/qpidd.1 @@ -0,0 +1,247 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. +.TH QPIDD "1" "March 2011" "qpidd (qpidc) version 0.11" "User Commands" +.SH NAME + +qpidd \- the Qpid AMQP Message Broker Daemon +.SH SYNOPSIS + +qpidd [-p port] [--config config_file] [--data-dir directory] +.SH DESCRIPTION + +An AMQP message broker daemon that stores, routes and forwards +messages using the Advanced Message Queueing Protocol (AMQP). +.SH OPTIONS + +The options below are built-in to qpidd. Installing add-on modules provides additional options. To see the full set of options available type "qpidd --help" + +Options may be specified via command line, environment variable or configuration file. See FILES and ENVIRONMENT below for details. +.PP + +.TP +\fB\-h\fR [ \fB\-\-help\fR ] +Displays the help message +.TP +\fB\-v\fR [ \fB\-\-version\fR ] +Displays version information +.TP +\fB\-\-config\fR FILE +Reads configuration from FILE +.SS "Module options:" +.TP +\fB\-\-module\-dir\fR DIR +Load all shareable modules in this +directory +.TP +\fB\-\-load\-module\fR FILE +Specifies additional module(s) to be +loaded +.TP +\fB\-\-no\-module\-dir\fR +Don't load modules from module +directory +.SS "Broker Options:" +.TP +\fB\-\-data\-dir\fR DIR +Directory to contain persistent data +generated by the broker +.TP +\fB\-\-no\-data\-dir\fR +Don't use a data directory. No +persistent configuration will be loaded +or stored +.TP +\fB\-p\fR [ \fB\-\-port\fR ] PORT (5672) +Tells the broker to listen on PORT +.TP +\fB\-\-worker\-threads\fR N (3) +Sets the broker thread pool size +.TP +\fB\-\-max\-connections\fR N (500) +Sets the maximum allowed connections +.TP +\fB\-\-connection\-backlog\fR N (10) +Sets the connection backlog limit for +the server socket +.TP +\fB\-m\fR [ \fB\-\-mgmt\-enable\fR ] yes|no (1) +Enable Management +.TP +\fB\-\-mgmt\-qmf2\fR yes|no (1) +Enable broadcast of management +information over QMF v2 +.TP +\fB\-\-mgmt\-qmf1\fR yes|no (1) +Enable broadcast of management +information over QMF v1 +.TP +\fB\-\-mgmt\-pub\-interval\fR SECONDS (10) +Management Publish Interval +.TP +\fB\-\-queue\-purge\-interval\fR SECONDS (600) +Interval between attempts to purge any +expired messages from queues +.TP +\fB\-\-auth\fR yes|no (1) +Enable authentication, if disabled all +incoming connections will be trusted +.TP +\fB\-\-realm\fR REALM (QPID) +Use the given realm when performing +authentication +.TP +\fB\-\-default\-queue\-limit\fR BYTES (104857600) +Default maximum size for queues (in +bytes) +.TP +\fB\-\-tcp\-nodelay\fR +Set TCP_NODELAY on TCP connections +.TP +\fB\-\-require\-encryption\fR +Only accept connections that are +encrypted +.TP +\fB\-\-known\-hosts\-url\fR URL or 'none' +URL to send as 'known\-hosts' to clients +('none' implies empty list) +.TP +\fB\-\-sasl\-config\fR DIR +gets sasl config info from nonstandard +location +.TP +\fB\-\-max\-session\-rate\fR MESSAGES/S (0) +Sets the maximum message rate per +session (0=unlimited) +.TP +\fB\-\-async\-queue\-events\fR yes|no (0) +Set Queue Events async, used for +services like replication +.TP +\fB\-\-default\-flow\-stop\-threshold\fR PERCENT (80) +Percent of queue's maximum capacity at +which flow control is activated. +.TP +\fB\-\-default\-flow\-resume\-threshold\fR PERCENT (70) +Percent of queue's maximum capacity at +which flow control is de\-activated. +.TP +\fB\-\-default\-event\-threshold\-ratio\fR %age of limit (80) +The ratio of any specified queue limit +at which an event will be raised +.SS "Logging options:" +.TP +\fB\-t\fR [ \fB\-\-trace\fR ] +Enables all logging +.TP +\fB\-\-log\-enable\fR RULE (notice+) +Enables logging for selected levels and +components. RULE is in the form +\&'LEVEL[+][:PATTERN]' Levels are one of: +.IP +trace debug info notice warning error +.IP +critical +For example: +\&'\-\-log\-enable warning+' logs all +warning, error and critical messages. +\&'\-\-log\-enable debug:framing' logs debug +messages from the framing namespace. +This option can be used multiple times +.TP +\fB\-\-log\-time\fR yes|no (1) +Include time in log messages +.TP +\fB\-\-log\-level\fR yes|no (1) +Include severity level in log messages +.TP +\fB\-\-log\-source\fR yes|no (0) +Include source file:line in log +messages +.TP +\fB\-\-log\-thread\fR yes|no (0) +Include thread ID in log messages +.TP +\fB\-\-log\-function\fR yes|no (0) +Include function signature in log +messages +.TP +\fB\-\-log\-prefix\fR STRING +Prefix to append to all log messages +.SS "Logging sink options:" +.TP +\fB\-\-log\-to\-stderr\fR yes|no (1) +Send logging output to stderr +.TP +\fB\-\-log\-to\-stdout\fR yes|no (0) +Send logging output to stdout +.TP +\fB\-\-log\-to\-file\fR FILE +Send log output to FILE. +.TP +\fB\-\-log\-to\-syslog\fR yes|no (0) +Send logging output to syslog; +customize using \fB\-\-syslog\-name\fR and +\fB\-\-syslog\-facility\fR +.TP +\fB\-\-syslog\-name\fR NAME (lt\-qpidd) +Name to use in syslog messages +.TP +\fB\-\-syslog\-facility\fR LOG_XXX (LOG_DAEMON) +Facility to use in syslog messages +.SS "Daemon options:" +.TP +\fB\-d\fR [ \fB\-\-daemon\fR ] +Run as a daemon. Logs to syslog by +default in this mode. +.TP +\fB\-\-transport\fR TRANSPORT (tcp) +The transport for which to return the +port +.TP +\fB\-\-pid\-dir\fR DIR +Directory where port\-specific PID file +is stored +.TP +\fB\-w\fR [ \fB\-\-wait\fR ] SECONDS (600) +Sets the maximum wait time to +initialize the daemon. If the daemon +fails to initialize, prints an error +and returns 1 +.TP +\fB\-c\fR [ \fB\-\-check\fR ] +Prints the daemon's process ID to +stdout and returns 0 if the daemon is +running, otherwise returns 1 +.TP +\fB\-q\fR [ \fB\-\-quit\fR ] +Tells the daemon to shut down +.SH ENVIRONMENT +.I QPID_